server: read UVC interface numbers
This commit is contained in:
parent
d9d2bd6c73
commit
7ea2f83002
@ -101,9 +101,20 @@ struct PendingRequest {
|
||||
selector: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct UvcInterfaces {
|
||||
control: u8,
|
||||
streaming: u8,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let (dev, cfg) = parse_args()?;
|
||||
let interfaces = load_interfaces();
|
||||
eprintln!("[lesavka-uvc] starting (dev={dev})");
|
||||
eprintln!(
|
||||
"[lesavka-uvc] interfaces control={} streaming={}",
|
||||
interfaces.control, interfaces.streaming
|
||||
);
|
||||
|
||||
let debug = env::var("LESAVKA_UVC_DEBUG").is_ok();
|
||||
let mut setup_seen: u64 = 0;
|
||||
@ -184,6 +195,7 @@ fn main() -> Result<()> {
|
||||
uvc_send_response,
|
||||
&mut state,
|
||||
&mut pending,
|
||||
interfaces,
|
||||
req,
|
||||
debug,
|
||||
);
|
||||
@ -197,7 +209,7 @@ fn main() -> Result<()> {
|
||||
data.length
|
||||
);
|
||||
}
|
||||
handle_data(&mut state, &mut pending, data, debug);
|
||||
handle_data(&mut state, &mut pending, interfaces, data, debug);
|
||||
}
|
||||
_ => {
|
||||
if debug {
|
||||
@ -268,6 +280,22 @@ impl UvcState {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_interfaces() -> UvcInterfaces {
|
||||
let control = env_u8("LESAVKA_UVC_CTRL_INTF")
|
||||
.or_else(|| read_interface("/sys/kernel/config/usb_gadget/lesavka/functions/uvc.usb0/control/bInterfaceNumber"))
|
||||
.unwrap_or(UVC_STRING_CONTROL_IDX);
|
||||
let streaming = env_u8("LESAVKA_UVC_STREAM_INTF")
|
||||
.or_else(|| read_interface("/sys/kernel/config/usb_gadget/lesavka/functions/uvc.usb0/streaming/bInterfaceNumber"))
|
||||
.unwrap_or(UVC_STRING_STREAMING_IDX);
|
||||
UvcInterfaces { control, streaming }
|
||||
}
|
||||
|
||||
fn read_interface(path: &str) -> Option<u8> {
|
||||
std::fs::read_to_string(path)
|
||||
.ok()
|
||||
.and_then(|v| v.trim().parse::<u8>().ok())
|
||||
}
|
||||
|
||||
fn open_with_retry(path: &str) -> Result<std::fs::File> {
|
||||
for attempt in 1..=200 {
|
||||
let mut opts = OpenOptions::new();
|
||||
@ -310,6 +338,7 @@ fn handle_setup(
|
||||
uvc_send_response: libc::c_ulong,
|
||||
state: &mut UvcState,
|
||||
pending: &mut Option<PendingRequest>,
|
||||
interfaces: UvcInterfaces,
|
||||
req: UsbCtrlRequest,
|
||||
debug: bool,
|
||||
) {
|
||||
@ -318,6 +347,10 @@ fn handle_setup(
|
||||
let is_in = (req.b_request_type & USB_DIR_IN) != 0;
|
||||
|
||||
if !is_in && req.b_request == UVC_SET_CUR {
|
||||
if interface != interfaces.streaming {
|
||||
let _ = send_stall(fd, uvc_send_response);
|
||||
return;
|
||||
}
|
||||
*pending = Some(PendingRequest { interface, selector });
|
||||
let len = req.w_length as usize;
|
||||
let payload = vec![0u8; len.min(UVC_DATA_SIZE)];
|
||||
@ -336,7 +369,7 @@ fn handle_setup(
|
||||
return;
|
||||
}
|
||||
|
||||
let payload = build_in_response(state, interface, selector, req.b_request);
|
||||
let payload = build_in_response(state, interfaces, interface, selector, req.b_request);
|
||||
match payload {
|
||||
Some(bytes) => {
|
||||
let _ = send_response(fd, uvc_send_response, &bytes);
|
||||
@ -350,6 +383,7 @@ fn handle_setup(
|
||||
fn handle_data(
|
||||
state: &mut UvcState,
|
||||
pending: &mut Option<PendingRequest>,
|
||||
interfaces: UvcInterfaces,
|
||||
data: UvcRequestData,
|
||||
debug: bool,
|
||||
) {
|
||||
@ -375,7 +409,7 @@ fn handle_data(
|
||||
);
|
||||
}
|
||||
|
||||
if p.interface == UVC_STRING_STREAMING_IDX
|
||||
if p.interface == interfaces.streaming
|
||||
&& matches!(p.selector, UVC_VS_PROBE_CONTROL | UVC_VS_COMMIT_CONTROL)
|
||||
{
|
||||
let sanitized = sanitize_streaming_control(slice, state);
|
||||
@ -407,13 +441,16 @@ fn handle_data(
|
||||
|
||||
fn build_in_response(
|
||||
state: &UvcState,
|
||||
interfaces: UvcInterfaces,
|
||||
interface: u8,
|
||||
selector: u8,
|
||||
request: u8,
|
||||
) -> Option<Vec<u8>> {
|
||||
match interface {
|
||||
UVC_STRING_STREAMING_IDX => build_streaming_response(state, selector, request),
|
||||
UVC_STRING_CONTROL_IDX => build_control_response(selector, request),
|
||||
_ if interface == interfaces.streaming => {
|
||||
build_streaming_response(state, selector, request)
|
||||
}
|
||||
_ if interface == interfaces.control => build_control_response(selector, request),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -561,6 +598,10 @@ fn env_u32(name: &str, default: u32) -> u32 {
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn env_u8(name: &str) -> Option<u8> {
|
||||
env::var(name).ok().and_then(|v| v.parse::<u8>().ok())
|
||||
}
|
||||
|
||||
fn write_le16(dst: &mut [u8], val: u16) {
|
||||
let bytes = val.to_le_bytes();
|
||||
dst[0] = bytes[0];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user