Skip to content

Commit 7510a72

Browse files
committed
Unload and restore kernel driver on Linux
1 parent 8502a30 commit 7510a72

File tree

9 files changed

+355
-13
lines changed

9 files changed

+355
-13
lines changed

java-does-usb/jextract/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
6262
with:
6363

6464
```
65-
SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit());
65+
SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", MemorySession.openImplicit());
6666
```
6767

6868

java-does-usb/jextract/linux/gen_linux.sh

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@
22

33
JEXTRACT=../../../../jextract/build/jextract/bin/jextract
44

5-
# sd-device.h (install libsystemd-dev if file is missing)
6-
# Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t'
7-
#$JEXTRACT --source --output ../src/main/java \
8-
#$JEXTRACT --source --output ../src/main/java \
9-
# --header-class-name sd_device \
10-
# --target-package net.codecrete.usb.linux.gen.sd-device
11-
# /usr/include/systemd/sd-device.h
12-
135
# errno.h
146
$JEXTRACT --source --output ../../src/main/java \
157
--header-class-name errno \
@@ -51,6 +43,8 @@ $JEXTRACT --source --output ../../src/main/java \
5143
--include-struct usbdevfs_ctrltransfer \
5244
--include-struct usbdevfs_setinterface \
5345
--include-struct usbdevfs_urb \
46+
--include-struct usbdevfs_disconnect_claim \
47+
--include-struct usbdevfs_ioctl \
5448
--include-constant USBDEVFS_CONTROL \
5549
--include-constant USBDEVFS_BULK \
5650
--include-constant USBDEVFS_CLAIMINTERFACE \
@@ -60,10 +54,12 @@ $JEXTRACT --source --output ../../src/main/java \
6054
--include-constant USBDEVFS_SUBMITURB \
6155
--include-constant USBDEVFS_DISCARDURB \
6256
--include-constant USBDEVFS_REAPURB \
57+
--include-constant USBDEVFS_DISCONNECT_CLAIM \
6358
--include-constant USBDEVFS_URB_TYPE_INTERRUPT \
6459
--include-constant USBDEVFS_URB_TYPE_CONTROL \
6560
--include-constant USBDEVFS_URB_TYPE_BULK \
6661
--include-constant USBDEVFS_URB_TYPE_ISO \
62+
--include-constant USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER \
6763
/usr/include/linux/usbdevice_fs.h
6864

6965
# libudev.h

java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
import net.codecrete.usb.common.USBInterfaceImpl;
1717
import net.codecrete.usb.linux.gen.fcntl.fcntl;
1818
import net.codecrete.usb.linux.gen.unistd.unistd;
19+
import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_disconnect_claim;
20+
import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ioctl;
1921
import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface;
22+
import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs;
2023
import net.codecrete.usb.usbstandard.DeviceDescriptor;
2124
import net.codecrete.usb.usbstandard.SetupPacket;
2225

@@ -110,9 +113,18 @@ public synchronized void claimInterface(int interfaceNumber) {
110113
try (var arena = Arena.openConfined()) {
111114
var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber);
112115
var errnoState = arena.allocate(Linux.ERRNO_STATE.layout());
113-
int ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errnoState);
116+
117+
// claim interface (possibly disconnecting kernel driver)
118+
var disconnectClaim = usbdevfs_disconnect_claim.allocate(arena);
119+
usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber);
120+
usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER());
121+
byte[] driverName = { 'u', 's', 'b', 'f', 's', 0 };
122+
usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(MemorySegment.ofArray(driverName));
123+
int ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errnoState);
124+
114125
if (ret != 0)
115126
throwLastError(errnoState, "Cannot claim USB interface");
127+
116128
setClaimed(interfaceNumber, true);
117129
}
118130
}
@@ -161,7 +173,15 @@ public synchronized void releaseInterface(int interfaceNumber) {
161173
int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState);
162174
if (ret != 0)
163175
throwLastError(errnoState, "Cannot release USB interface");
176+
164177
setClaimed(interfaceNumber, false);
178+
179+
// reattach kernel driver
180+
var request = usbdevfs_ioctl.allocate(arena);
181+
usbdevfs_ioctl.ifno$set(request, interfaceNumber);
182+
usbdevfs_ioctl.ioctl_code$set(request, USBDevFS.CONNECT);
183+
usbdevfs_ioctl.data$set(request, MemorySegment.NULL);
184+
IO.ioctl(fd, USBDevFS.IOCTL, request, errnoState);
165185
}
166186
}
167187

java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
*/
1313
public class USBDevFS {
1414

15-
public static final long CLAIMINTERFACE = 0x8004550FL;
1615
public static final long RELEASEINTERFACE = 0x80045510L;
1716
public static final long SETINTERFACE = 0x80085504L;
1817
public static final long CLEAR_HALT = 0x80045515L;
1918
public static final long SUBMITURB = 0x8038550AL;
2019
public static final long DISCARDURB = 0x550BL;
2120
public static final long REAPURBNDELAY = 0x4008550DL;
22-
21+
public static final long DISCONNECT_CLAIM = 0x8108551BL;
22+
public static final int CONNECT = 0x5517;
23+
public static final long IOCTL = 0xC0105512L;
2324
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Generated by jextract
2+
3+
package net.codecrete.usb.linux.gen.usbdevice_fs;
4+
5+
import java.lang.foreign.*;
6+
import java.lang.invoke.VarHandle;
7+
/**
8+
* {@snippet :
9+
* struct usbdevfs_disconnect_claim {
10+
* unsigned int interface;
11+
* unsigned int flags;
12+
* char driver[256];
13+
* };
14+
* }
15+
*/
16+
public class usbdevfs_disconnect_claim {
17+
18+
static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout(
19+
Constants$root.C_INT$LAYOUT.withName("interface"),
20+
Constants$root.C_INT$LAYOUT.withName("flags"),
21+
MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver")
22+
).withName("usbdevfs_disconnect_claim");
23+
public static MemoryLayout $LAYOUT() {
24+
return usbdevfs_disconnect_claim.$struct$LAYOUT;
25+
}
26+
static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface"));
27+
public static VarHandle interface_$VH() {
28+
return usbdevfs_disconnect_claim.interface_$VH;
29+
}
30+
/**
31+
* Getter for field:
32+
* {@snippet :
33+
* unsigned int interface;
34+
* }
35+
*/
36+
public static int interface_$get(MemorySegment seg) {
37+
return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg);
38+
}
39+
/**
40+
* Setter for field:
41+
* {@snippet :
42+
* unsigned int interface;
43+
* }
44+
*/
45+
public static void interface_$set(MemorySegment seg, int x) {
46+
usbdevfs_disconnect_claim.interface_$VH.set(seg, x);
47+
}
48+
public static int interface_$get(MemorySegment seg, long index) {
49+
return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg.asSlice(index*sizeof()));
50+
}
51+
public static void interface_$set(MemorySegment seg, long index, int x) {
52+
usbdevfs_disconnect_claim.interface_$VH.set(seg.asSlice(index*sizeof()), x);
53+
}
54+
static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags"));
55+
public static VarHandle flags$VH() {
56+
return usbdevfs_disconnect_claim.flags$VH;
57+
}
58+
/**
59+
* Getter for field:
60+
* {@snippet :
61+
* unsigned int flags;
62+
* }
63+
*/
64+
public static int flags$get(MemorySegment seg) {
65+
return (int)usbdevfs_disconnect_claim.flags$VH.get(seg);
66+
}
67+
/**
68+
* Setter for field:
69+
* {@snippet :
70+
* unsigned int flags;
71+
* }
72+
*/
73+
public static void flags$set(MemorySegment seg, int x) {
74+
usbdevfs_disconnect_claim.flags$VH.set(seg, x);
75+
}
76+
public static int flags$get(MemorySegment seg, long index) {
77+
return (int)usbdevfs_disconnect_claim.flags$VH.get(seg.asSlice(index*sizeof()));
78+
}
79+
public static void flags$set(MemorySegment seg, long index, int x) {
80+
usbdevfs_disconnect_claim.flags$VH.set(seg.asSlice(index*sizeof()), x);
81+
}
82+
public static MemorySegment driver$slice(MemorySegment seg) {
83+
return seg.asSlice(8, 256);
84+
}
85+
public static long sizeof() { return $LAYOUT().byteSize(); }
86+
public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); }
87+
public static MemorySegment allocateArray(long len, SegmentAllocator allocator) {
88+
return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT()));
89+
}
90+
public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); }
91+
}
92+
93+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Generated by jextract
2+
3+
package net.codecrete.usb.linux.gen.usbdevice_fs;
4+
5+
import java.lang.foreign.*;
6+
import java.lang.invoke.VarHandle;
7+
/**
8+
* {@snippet :
9+
* struct usbdevfs_ioctl {
10+
* int ifno;
11+
* int ioctl_code;
12+
* void* data;
13+
* };
14+
* }
15+
*/
16+
public class usbdevfs_ioctl {
17+
18+
static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout(
19+
Constants$root.C_INT$LAYOUT.withName("ifno"),
20+
Constants$root.C_INT$LAYOUT.withName("ioctl_code"),
21+
Constants$root.C_POINTER$LAYOUT.withName("data")
22+
).withName("usbdevfs_ioctl");
23+
public static MemoryLayout $LAYOUT() {
24+
return usbdevfs_ioctl.$struct$LAYOUT;
25+
}
26+
static final VarHandle ifno$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ifno"));
27+
public static VarHandle ifno$VH() {
28+
return usbdevfs_ioctl.ifno$VH;
29+
}
30+
/**
31+
* Getter for field:
32+
* {@snippet :
33+
* int ifno;
34+
* }
35+
*/
36+
public static int ifno$get(MemorySegment seg) {
37+
return (int)usbdevfs_ioctl.ifno$VH.get(seg);
38+
}
39+
/**
40+
* Setter for field:
41+
* {@snippet :
42+
* int ifno;
43+
* }
44+
*/
45+
public static void ifno$set(MemorySegment seg, int x) {
46+
usbdevfs_ioctl.ifno$VH.set(seg, x);
47+
}
48+
public static int ifno$get(MemorySegment seg, long index) {
49+
return (int)usbdevfs_ioctl.ifno$VH.get(seg.asSlice(index*sizeof()));
50+
}
51+
public static void ifno$set(MemorySegment seg, long index, int x) {
52+
usbdevfs_ioctl.ifno$VH.set(seg.asSlice(index*sizeof()), x);
53+
}
54+
static final VarHandle ioctl_code$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code"));
55+
public static VarHandle ioctl_code$VH() {
56+
return usbdevfs_ioctl.ioctl_code$VH;
57+
}
58+
/**
59+
* Getter for field:
60+
* {@snippet :
61+
* int ioctl_code;
62+
* }
63+
*/
64+
public static int ioctl_code$get(MemorySegment seg) {
65+
return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg);
66+
}
67+
/**
68+
* Setter for field:
69+
* {@snippet :
70+
* int ioctl_code;
71+
* }
72+
*/
73+
public static void ioctl_code$set(MemorySegment seg, int x) {
74+
usbdevfs_ioctl.ioctl_code$VH.set(seg, x);
75+
}
76+
public static int ioctl_code$get(MemorySegment seg, long index) {
77+
return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg.asSlice(index*sizeof()));
78+
}
79+
public static void ioctl_code$set(MemorySegment seg, long index, int x) {
80+
usbdevfs_ioctl.ioctl_code$VH.set(seg.asSlice(index*sizeof()), x);
81+
}
82+
static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data"));
83+
public static VarHandle data$VH() {
84+
return usbdevfs_ioctl.data$VH;
85+
}
86+
/**
87+
* Getter for field:
88+
* {@snippet :
89+
* void* data;
90+
* }
91+
*/
92+
public static MemorySegment data$get(MemorySegment seg) {
93+
return (java.lang.foreign.MemorySegment)usbdevfs_ioctl.data$VH.get(seg);
94+
}
95+
/**
96+
* Setter for field:
97+
* {@snippet :
98+
* void* data;
99+
* }
100+
*/
101+
public static void data$set(MemorySegment seg, MemorySegment x) {
102+
usbdevfs_ioctl.data$VH.set(seg, x);
103+
}
104+
public static MemorySegment data$get(MemorySegment seg, long index) {
105+
return (java.lang.foreign.MemorySegment)usbdevfs_ioctl.data$VH.get(seg.asSlice(index*sizeof()));
106+
}
107+
public static void data$set(MemorySegment seg, long index, MemorySegment x) {
108+
usbdevfs_ioctl.data$VH.set(seg.asSlice(index*sizeof()), x);
109+
}
110+
public static long sizeof() { return $LAYOUT().byteSize(); }
111+
public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); }
112+
public static MemorySegment allocateArray(long len, SegmentAllocator allocator) {
113+
return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT()));
114+
}
115+
public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); }
116+
}
117+
118+

java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ public static int USBDEVFS_URB_TYPE_CONTROL() {
4545
public static int USBDEVFS_URB_TYPE_BULK() {
4646
return (int)3L;
4747
}
48+
/**
49+
* {@snippet :
50+
* #define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 2
51+
* }
52+
*/
53+
public static int USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER() {
54+
return (int)2L;
55+
}
4856
}
4957

5058

0 commit comments

Comments
 (0)