You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在rusb(Rust libusb绑定库)中调用claim_interface失败?

问题:调用libusb的claim_interface时触发NotFound错误

我尝试用Rust通过libusb向Pixel6设备写入Bulk数据以学习其用法,代码省略了大部分错误处理,但调用claim_interface时出现NotFound错误,根据rusb文档,该错误表示指定接口编号不存在。请问错误原因是什么?

错误日志

[timestamp] [threadID] facility level [function call] <message>
--------------------------------------------------------------------------------
[ 0.005973] [000015a8] libusb: debug [libusb_get_device_list]  
[ 0.005981] [000015a8] libusb: debug [libusb_get_device_descriptor]  
[ 0.005983] [000015a8] libusb: debug [libusb_open] open 7.8
[ 0.006006] [000015a8] libusb: debug [usbi_add_event_source] add fd 7 events 4
[ 0.006009] [000015a8] libusb: debug [libusb_get_device_descriptor]  
[ 0.006011] [000015a8] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.006015] [000015a8] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.006016] [000015a8] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.006021] [000015a8] libusb: debug [libusb_kernel_driver_active] interface 0
[ 0.006023] [000015a8] libusb: debug [libusb_set_configuration] configuration 0
[ 0.007677] [000015a8] libusb: debug [libusb_claim_interface] interface 0
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NotFound', src/bulk.rs:37:68
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
[ 0.007738] [000015a8] libusb: debug [libusb_close]  
[ 0.007743] [000015a8] libusb: debug [usbi_remove_event_source] remove fd 7

问题代码

use rusb::devices;
use rusb::Direction::{In, Out};
use rusb::TransferType::{Bulk, Control};
use rusb::{open_device_with_vid_pid, TransferType};
use std::time::Duration;
pub fn pixel6_bulk() {
    write_to_device(6353, 20199, Bulk);
}

fn write_to_device(vendor_id: u16, product_id: u16, ttype: TransferType) {
    let mut has_kernel_driver: bool = false;
    if let Some(mut device_handle) = open_device_with_vid_pid(vendor_id, product_id) {
        let dev = device_handle.device();
        let dd = dev.device_descriptor().unwrap();
        let num_config = dd.num_configurations();
        for p in 0..num_config {
            let cd = dev.config_descriptor(p).unwrap();
            let ifaces = cd.interfaces();
            for iface in ifaces {
                let inumber = iface.number();
                let ifds = iface.descriptors();
                for ifd in ifds {
                    let setting_number = ifd.setting_number();
                    for efd in ifd.endpoint_descriptors() {
                        if efd.direction() == Out && efd.transfer_type() == ttype {
                            let buf: &[u8] = "Hello".as_bytes();
                            let endpoint_address = efd.address();
                            if device_handle.kernel_driver_active(inumber).unwrap() {
                                has_kernel_driver =
                                    match device_handle.detach_kernel_driver(inumber) {
                                        Ok(_) => true,
                                        _ => false,
                                    };
                            }
                            //let endpoint_number = efd.number();
                            device_handle.set_active_configuration(p).unwrap();
                            device_handle.claim_interface(inumber).unwrap();
                            device_handle
                                .set_alternate_setting(inumber, setting_number)
                                .unwrap();
                            match device_handle.write_bulk(
                                endpoint_address,
                                buf,
                                Duration::new(2, 0),
                            ) {
                                Ok(n) => println!("{} bytes was written with bulk", n),
                                Err(_) => println!("Write_bulk was failed"),
                            }
                            if has_kernel_driver {
                                match device_handle.attach_kernel_driver(inumber) {
                                    Ok(_) => (),
                                    Err(_) => println!("Kernel driver attach failed"),
                                }
                            }
                            device_handle.release_interface(inumber).unwrap();
                        }
                    }
                }
            }
        }
    } else {
        panic!("There is no device");
    }
}

错误原因分析

1. 配置与接口操作顺序颠倒

你当前的逻辑是先枚举所有配置下的接口和端点,找到符合条件的端点后才调用set_active_configuration(p)切换配置。但USB设备切换配置后,之前枚举的接口信息会失效,此时尝试申请的接口属于未激活的配置,自然会返回NotFound错误。

2. 接口有效性依赖当前激活配置

USB设备的接口属于特定配置,只有当前激活的配置下的接口才能被申请。你在未激活目标配置的情况下就获取了接口编号,后续切换配置后该接口编号可能在新配置中不存在,或者无法被访问。

修正方案

调整操作顺序,先激活目标配置,再枚举该配置下的接口和端点,最后执行接口申请和数据传输:

use rusb::Direction::{In, Out};
use rusb::TransferType::{Bulk, Control};
use rusb::{open_device_with_vid_pid, TransferType};
use std::time::Duration;

pub fn pixel6_bulk() {
    write_to_device(6353, 20199, Bulk);
}

fn write_to_device(vendor_id: u16, product_id: u16, ttype: TransferType) {
    let mut has_kernel_driver: bool = false;
    if let Some(mut device_handle) = open_device_with_vid_pid(vendor_id, product_id) {
        let dev = device_handle.device();
        let dd = dev.device_descriptor().unwrap();
        
        // 遍历所有配置,先激活再处理接口
        for config_idx in 0..dd.num_configurations() {
            let cd = dev.config_descriptor(config_idx).unwrap();
            
            // 先激活当前配置
            if let Err(e) = device_handle.set_active_configuration(config_idx) {
                eprintln!("激活配置{}失败: {}", config_idx, e);
                continue;
            }
            
            let ifaces = cd.interfaces();
            for iface in ifaces {
                let inumber = iface.number();
                let ifds = iface.descriptors();
                
                for ifd in ifds {
                    let setting_number = ifd.setting_number();
                    
                    for efd in ifd.endpoint_descriptors() {
                        if efd.direction() == Out && efd.transfer_type() == ttype {
                            let buf: &[u8] = "Hello".as_bytes();
                            let endpoint_address = efd.address();
                            
                            // 检查并分离内核驱动
                            if device_handle.kernel_driver_active(inumber).unwrap_or(false) {
                                has_kernel_driver = match device_handle.detach_kernel_driver(inumber) {
                                    Ok(_) => true,
                                    Err(e) => {
                                        eprintln!("分离接口{}的内核驱动失败: {}", inumber, e);
                                        false
                                    }
                                };
                            }
                            
                            // 申请接口
                            if let Err(e) = device_handle.claim_interface(inumber) {
                                eprintln!("申请接口{}失败: {}", inumber, e);
                                if has_kernel_driver {
                                    let _ = device_handle.attach_kernel_driver(inumber);
                                }
                                continue;
                            }
                            
                            // 设置替代设置
                            if let Err(e) = device_handle.set_alternate_setting(inumber, setting_number) {
                                eprintln!("为接口{}设置替代设置{}失败: {}", inumber, setting_number, e);
                                let _ = device_handle.release_interface(inumber);
                                if has_kernel_driver {
                                    let _ = device_handle.attach_kernel_driver(inumber);
                                }
                                continue;
                            }
                            
                            // 执行Bulk写入
                            match device_handle.write_bulk(endpoint_address, buf, Duration::new(2, 0)) {
                                Ok(n) => println!("通过Bulk写入{}字节", n),
                                Err(e) => println!("Bulk写入失败: {}", e),
                            }
                            
                            // 释放资源
                            let _ = device_handle.release_interface(inumber);
                            if has_kernel_driver {
                                match device_handle.attach_kernel_driver(inumber) {
                                    Ok(_) => (),
                                    Err(e) => println!("重新挂载内核驱动失败: {}", e),
                                }
                            }
                        }
                    }
                }
            }
        }
    } else {
        panic!("未找到匹配设备");
    }
}

内容的提问来源于stack exchange,提问作者KiYugadgeter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 00:30:57