fix keyboard and mass storgae stream

This commit is contained in:
duffyduck 2026-02-19 12:41:30 +01:00
parent 67ab5418ee
commit 3a94bf35a7
5 changed files with 51 additions and 9 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -37,6 +37,7 @@ var (
usbdevfsSetInterface = ior('U', 4, unsafe.Sizeof(usbdevfsSetIntf{}))
usbdevfsSetConfig = ior('U', 5, 4)
usbdevfsSubmitURB = ior('U', 10, unsafe.Sizeof(usbdevfsURB{}))
usbdevfsResetEP = ior('U', 3, 4)
usbdevfsDiscardURB = io_('U', 11)
usbdevfsReapURB = iow('U', 12, unsafe.Sizeof(uintptr(0)))
usbdevfsReapURBNDelay = iow('U', 13, unsafe.Sizeof(uintptr(0)))
@ -348,6 +349,27 @@ func (h *DeviceHandle) DiscardURB(urb *usbdevfsURB) error {
return nil
}
// DiscardURBByPtr cancels a submitted URB given its raw pointer.
// Use this when the URB type is not accessible (e.g. from another package).
func (h *DeviceHandle) DiscardURBByPtr(ptr unsafe.Pointer) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(h.fd), usbdevfsDiscardURB, uintptr(ptr))
if errno != 0 {
return fmt.Errorf("USBDEVFS_DISCARDURB: %w", errno)
}
return nil
}
// ResetEndpoint resets the host-side data toggle for an endpoint without
// sending any USB traffic to the device. Use after SET_CONFIGURATION to
// sync host controller toggle state with the device.
func (h *DeviceHandle) ResetEndpoint(endpoint uint32) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(h.fd), usbdevfsResetEP, uintptr(unsafe.Pointer(&endpoint)))
if errno != 0 {
return fmt.Errorf("USBDEVFS_RESETEP(%d): %w", endpoint, errno)
}
return nil
}
// SubmitISOURBParams holds parameters for async ISO URB submission
type SubmitISOURBParams struct {
Endpoint uint8

View File

@ -15,7 +15,6 @@ import (
"unsafe"
"github.com/duffy/usb-server/internal/usb"
"golang.org/x/sys/unix"
)
// Server handles USB/IP protocol on the share side.
@ -112,9 +111,7 @@ func (s *Server) Detach() {
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))
s.handle.DiscardURBByPtr(pending.urbPtr)
}
delete(s.pendingURBs, seqNum)
}
@ -410,6 +407,33 @@ func (s *Server) handleCmdSubmit(r io.Reader, hdr *URBHeader, retChan chan<- []b
status = -32
}
case bmRequestType == 0x00 && bRequest == 0x09:
// SET_CONFIGURATION — the device resets all endpoint data toggles
// to DATA0 on SET_CONFIGURATION, but USBDEVFS_CONTROL doesn't update
// the host controller's toggle state. We must manually reset host-side
// toggles via USBDEVFS_RESETEP, otherwise data toggle mismatch causes
// all non-control transfers (bulk, interrupt) to fail silently.
buf := transferBuf
if buf == nil {
buf = make([]byte, 0)
}
_, err := s.handle.ControlTransfer(bmRequestType, bRequest, wValue, wIndex, 0, 5000, buf)
if err != nil {
log.Printf("[usbip-server] SET_CONFIGURATION(%d) failed: %v", wValue, err)
status = -32
} else {
log.Printf("[usbip-server] SET_CONFIGURATION(%d) OK, resetting endpoint toggles", wValue)
for epNum := range s.epTypes {
if epNum == 0 {
continue
}
// Reset both OUT and IN directions; ignore errors for
// non-existent directions (e.g. endpoint only has IN)
s.handle.ResetEndpoint(uint32(epNum))
s.handle.ResetEndpoint(uint32(epNum) | 0x80)
}
}
default:
// Generic OUT control transfer
buf := transferBuf
@ -577,11 +601,7 @@ func (s *Server) handleCmdUnlink(r io.Reader, hdr *URBHeader, retChan chan<- []b
var status int32
if exists && pending.urbPtr != nil {
// Try to discard the URB via proper ioctl
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(s.handle.Fd()),
uintptr(0x8000550B), // USBDEVFS_DISCARDURB
uintptr(pending.urbPtr))
if errno == 0 {
if err := s.handle.DiscardURBByPtr(pending.urbPtr); err == nil {
status = -104 // -ECONNRESET
}
}