diff --git a/bin/usb-client b/bin/usb-client index 9753511..eecd7d3 100755 Binary files a/bin/usb-client and b/bin/usb-client differ diff --git a/bin/usb-relay b/bin/usb-relay index a381a93..45c7722 100755 Binary files a/bin/usb-relay and b/bin/usb-relay differ diff --git a/internal/usbip/server.go b/internal/usbip/server.go index 3083f5a..489907c 100644 --- a/internal/usbip/server.go +++ b/internal/usbip/server.go @@ -105,14 +105,42 @@ func (s *Server) Detach() { return } - // Release all interfaces + // 1. Discard all pending URBs to clean up device state + s.mu.Lock() + for seqNum, pending := range s.pendingURBs { + if pending.urbPtr != nil { + unix.Syscall(unix.SYS_IOCTL, uintptr(s.handle.Fd()), + 0x8000550B, // USBDEVFS_DISCARDURB + uintptr(pending.urbPtr)) + } + delete(s.pendingURBs, seqNum) + } + s.mu.Unlock() + + // 2. Release all claimed interfaces for _, iface := range s.device.Interfaces { - s.handle.ReleaseInterface(uint32(iface.Number)) + if err := s.handle.ReleaseInterface(uint32(iface.Number)); err != nil { + log.Printf("[usbip-server] release interface %d: %v", iface.Number, err) + } } - // Reconnect kernel driver - s.handle.ConnectDriver() + // 3. Reset device to force driver re-probing (most reliable method) + // A USB reset forces the kernel to re-enumerate and rebind drivers. + // This is important for devices like webcams that may be left in a + // streaming state after URB transfers. + if err := s.handle.ResetDevice(); err != nil { + log.Printf("[usbip-server] device reset failed: %v, trying ConnectDriver", err) + // Fallback: try to reconnect kernel driver without reset + if err := s.handle.ConnectDriver(); err != nil { + log.Printf("[usbip-server] ConnectDriver also failed: %v", err) + } else { + log.Printf("[usbip-server] kernel driver reconnected via ConnectDriver") + } + } else { + log.Printf("[usbip-server] device reset OK, kernel drivers re-bound") + } + // 4. Close the device file descriptor s.handle.Close() s.handle = nil }