|
| 1 | +package usbgadget |
| 2 | + |
| 3 | +// USB endpoint budget for the JetKVM RV1106 dwc3 controller. |
| 4 | +// |
| 5 | +// dwc3 exposes IN (device->host) and OUT (host->device) endpoints as separate |
| 6 | +// hardware resources, so they are budgeted independently — allocating a |
| 7 | +// bulk-OUT never steals from the IN pool. |
| 8 | +// |
| 9 | +// The IN budget of 7 is empirically confirmed: the full default function set |
| 10 | +// plus CDC-NCM needs 8 IN endpoints and NCM's bulk-IN silently fails to |
| 11 | +// allocate (the link enumerates and usb0 comes up RX-only, TX is a black |
| 12 | +// hole); dropping any single IN-using function (-> 7) makes it work. The OUT |
| 13 | +// pool on this part is symmetric with IN and OUT demand stays far below it in |
| 14 | +// practice, so the same ceiling is used for both. |
| 15 | +// |
| 16 | +// Note: the true low-level limiter for IN endpoints may be dwc3's TX-FIFO |
| 17 | +// SRAM (each IN endpoint reserves FIFO space sized to its max packet) rather |
| 18 | +// than a raw endpoint count, but the effective ceiling we observed is 7, so a |
| 19 | +// simple count captures it. FIFO RAM is not modeled separately. |
| 20 | +const ( |
| 21 | + usbInEndpointBudget uint = 7 |
| 22 | + usbOutEndpointBudget uint = 7 |
| 23 | +) |
| 24 | + |
| 25 | +// endpointCost is the number of USB IN and OUT endpoints a gadget function |
| 26 | +// consumes. |
| 27 | +type endpointCost struct { |
| 28 | + in uint |
| 29 | + out uint |
| 30 | +} |
| 31 | + |
| 32 | +// endpointCosts maps a gadget config item key to its endpoint cost. Keys match |
| 33 | +// entries in defaultGadgetConfig; items absent here cost nothing (base, |
| 34 | +// base_info, mass_storage_lun0, ...). HID OUT cost follows the function's |
| 35 | +// no_out_endpoint attribute (keyboard has an interrupt-OUT for LED reports; |
| 36 | +// the mice and wake HID do not). |
| 37 | +var endpointCosts = map[string]endpointCost{ |
| 38 | + "keyboard": {in: 1, out: 1}, // interrupt IN + interrupt OUT (LED reports) |
| 39 | + "wake_hid": {in: 1, out: 0}, // interrupt IN only |
| 40 | + "absolute_mouse": {in: 1, out: 0}, // interrupt IN only |
| 41 | + "relative_mouse": {in: 1, out: 0}, // interrupt IN only |
| 42 | + "audio": {in: 1, out: 0}, // UAC1 capture: isochronous IN |
| 43 | + "mass_storage_base": {in: 1, out: 1}, // bulk IN + bulk OUT |
| 44 | + "serial_console": {in: 2, out: 1}, // CDC-ACM: bulk IN + notify IN + bulk OUT |
| 45 | + "ncm": {in: 2, out: 1}, // CDC-NCM: bulk IN + notify IN + bulk OUT |
| 46 | +} |
| 47 | + |
| 48 | +// endpointUsage returns the IN and OUT endpoint demand of a device selection, |
| 49 | +// including always-on functions (wake_hid, audio). |
| 50 | +func endpointUsage(devices *Devices) (in, out uint) { |
| 51 | + for key, cost := range endpointCosts { |
| 52 | + if isGadgetConfigItemEnabledForDevices(key, devices) { |
| 53 | + in += cost.in |
| 54 | + out += cost.out |
| 55 | + } |
| 56 | + } |
| 57 | + return in, out |
| 58 | +} |
| 59 | + |
| 60 | +// ExceedsEndpointBudget reports whether the given device selection would exceed |
| 61 | +// the controller's IN or OUT endpoint budget. An over-budget gadget still |
| 62 | +// enumerates but leaves some function's endpoint(s) silently unallocated (e.g. |
| 63 | +// CDC-NCM comes up RX-only with a dead TX path), so the UI uses this to warn |
| 64 | +// before the user commits to the combination. |
| 65 | +func ExceedsEndpointBudget(devices *Devices) bool { |
| 66 | + in, out := endpointUsage(devices) |
| 67 | + return in > usbInEndpointBudget || out > usbOutEndpointBudget |
| 68 | +} |
0 commit comments