xhcid: use lang id when reading string descriptors

This commit is contained in:
Jeremy Soller
2025-03-21 15:41:53 -06:00
parent 5afc5c9de4
commit 7c9801379d
4 changed files with 69 additions and 17 deletions
+7 -4
View File
@@ -56,7 +56,10 @@ fn main() {
Some((conf_desc.clone(), if_desc))
})
.expect("Failed to find suitable configuration");
//TODO: is it required to configure before reading hub descriptor?
// Read hub descriptor
let mut hub_desc = usb::HubDescriptor::default();
handle
.device_request(
@@ -64,12 +67,12 @@ fn main() {
PortReqRecipient::Device,
usb::SetupReq::GetDescriptor as u8,
0,
//TODO: should this be an index into interface_descs?
interface_num as u16,
0,
DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }),
)
.expect("Failed to retrieve hub descriptor");
.expect("Failed to read hub descriptor");
// Configure as hub device
handle
.configure_endpoints(&ConfigureEndpointsReq {
config_desc: conf_desc.configuration_value,
@@ -77,7 +80,7 @@ fn main() {
alternate_setting: Some(if_desc.alternate_setting),
hub_ports: Some(hub_desc.ports),
})
.expect("Failed to configure endpoints");
.expect("Failed to configure endpoints after reading hub descriptor");
/*TODO: only set hub depth on USB 3+ hubs
handle
+5
View File
@@ -2,14 +2,17 @@
#[derive(Clone, Copy, Debug)]
pub struct HubDescriptor {
pub length: u8,
// 0x29 for USB 2, 0x2A for USB 3
pub kind: u8,
pub ports: u8,
pub characteristics: u16,
pub power_on_good: u8,
pub current: u8,
/*TODO: USB 2 and 3 disagree on the descriptor, so some fields are disabled
// device_removable: bitmap of ports, maximum of 256 bits (32 bytes)
// power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes)
bitmaps: [u8; 64],
*/
}
unsafe impl plain::Plain for HubDescriptor {}
@@ -23,7 +26,9 @@ impl Default for HubDescriptor {
characteristics: 0,
power_on_good: 0,
current: 0,
/*
bitmaps: [0; 64],
*/
}
}
}
+37 -7
View File
@@ -99,7 +99,8 @@ impl Xhci {
port: PortId,
slot: u8,
kind: usb::DescriptorKind,
index: u8,
value: u8,
index: u16,
desc: &mut Dma<T>,
) -> Result<()> {
if self.interrupt_is_pending(0) {
@@ -108,10 +109,11 @@ impl Xhci {
}
let len = mem::size_of::<T>();
log::debug!(
"get_desc_raw port {} slot {} kind {:?} index {} len {}",
"get_desc_raw port {} slot {} kind {:?} value {} index {} len {}",
port,
slot,
kind,
value,
index,
len
);
@@ -128,7 +130,7 @@ impl Xhci {
let first_index = ring.next_index();
let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle);
cmd.setup(
usb::Setup::get_descriptor(kind, index, 0, len as u16),
usb::Setup::get_descriptor(kind, value, index, len as u16),
TransferKind::In,
cycle,
);
@@ -173,14 +175,14 @@ impl Xhci {
slot: u8,
) -> Result<usb::DeviceDescriptor8Byte> {
let mut desc = unsafe { self.alloc_dma_zeroed::<usb::DeviceDescriptor8Byte>()? };
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc)
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, 0, &mut desc)
.await?;
Ok(*desc)
}
async fn fetch_dev_desc(&self, port: PortId, slot: u8) -> Result<usb::DeviceDescriptor> {
let mut desc = unsafe { self.alloc_dma_zeroed::<usb::DeviceDescriptor>()? };
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc)
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, 0, &mut desc)
.await?;
Ok(*desc)
}
@@ -197,6 +199,7 @@ impl Xhci {
slot,
usb::DescriptorKind::Configuration,
config,
0,
&mut desc,
)
.await?;
@@ -214,17 +217,44 @@ impl Xhci {
slot,
usb::DescriptorKind::BinaryObjectStorage,
0,
0,
&mut desc,
)
.await?;
Ok(*desc)
}
async fn fetch_string_desc(&self, port: PortId, slot: u8, index: u8) -> Result<String> {
async fn fetch_lang_ids_desc(&self, port: PortId, slot: u8) -> Result<Vec<u16>> {
let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? };
self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc)
self.get_desc_raw(port, slot, usb::DescriptorKind::String, 0, 0, &mut sdesc)
.await?;
let len = sdesc.0 as usize;
if len > 2 {
Ok(sdesc.2[..(len - 2) / 2].to_vec())
} else {
Ok(Vec::new())
}
}
async fn fetch_string_desc(
&self,
port: PortId,
slot: u8,
value: u8,
lang_id: u16,
) -> Result<String> {
let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? };
self.get_desc_raw(
port,
slot,
usb::DescriptorKind::String,
value,
lang_id,
&mut sdesc,
)
.await?;
let len = sdesc.0 as usize;
if len > 2 {
Ok(String::from_utf16(&sdesc.2[..(len - 2) / 2]).unwrap_or(String::new()))
+20 -6
View File
@@ -550,13 +550,14 @@ impl Xhci {
desc: usb::InterfaceDescriptor,
endps: impl IntoIterator<Item = EndpDesc>,
hid_descs: impl IntoIterator<Item = HidDesc>,
lang_id: u16,
) -> Result<IfDesc> {
Ok(IfDesc {
alternate_setting: desc.alternate_setting,
class: desc.class,
interface_str: if desc.interface_str > 0 {
Some(
self.fetch_string_desc(port_id, slot, desc.interface_str)
self.fetch_string_desc(port_id, slot, desc.interface_str, lang_id)
.await?,
)
} else {
@@ -1443,10 +1444,23 @@ impl Xhci {
let raw_dd = self.fetch_dev_desc(port_id, slot).await?;
log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd);
let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?;
// Prefer US English, but fall back to first language ID, or zero
let en_us_id = 0x409;
let lang_id = if lang_ids.contains(&en_us_id) {
en_us_id
} else {
match lang_ids.first() {
Some(some) => *some,
None => 0,
}
};
log::debug!("port {} using language ID 0x{:04x}", port_id, lang_id);
let (manufacturer_str, product_str, serial_str) = (
if raw_dd.manufacturer_str > 0 {
Some(
self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str)
self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str, lang_id)
.await?,
)
} else {
@@ -1454,7 +1468,7 @@ impl Xhci {
},
if raw_dd.product_str > 0 {
Some(
self.fetch_string_desc(port_id, slot, raw_dd.product_str)
self.fetch_string_desc(port_id, slot, raw_dd.product_str, lang_id)
.await?,
)
} else {
@@ -1462,7 +1476,7 @@ impl Xhci {
},
if raw_dd.serial_str > 0 {
Some(
self.fetch_string_desc(port_id, slot, raw_dd.serial_str)
self.fetch_string_desc(port_id, slot, raw_dd.serial_str, lang_id)
.await?,
)
} else {
@@ -1548,7 +1562,7 @@ impl Xhci {
}
interface_descs.push(
self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs)
self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs, lang_id)
.await?,
);
} else {
@@ -1562,7 +1576,7 @@ impl Xhci {
kind: desc.kind,
configuration: if desc.configuration_str > 0 {
Some(
self.fetch_string_desc(port_id, slot, desc.configuration_str)
self.fetch_string_desc(port_id, slot, desc.configuration_str, lang_id)
.await?,
)
} else {