Add HID protocol and idle configuration to USB stack
This commit is contained in:
@@ -77,6 +77,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u
|
||||
config_desc: configuration_value,
|
||||
interface_desc: Some(interface_num),
|
||||
alternate_setting: Some(alternate_setting),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("Failed to configure endpoints");
|
||||
|
||||
|
||||
+129
-118
@@ -10,7 +10,7 @@ use rehid::{
|
||||
report_handler::ReportHandler,
|
||||
usage_tables::{GenericDesktopUsage, UsagePage},
|
||||
};
|
||||
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, PortReqRecipient, XhciClientHandle};
|
||||
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle, PROTOCOL_REPORT};
|
||||
|
||||
mod keymap;
|
||||
mod reqs;
|
||||
@@ -243,24 +243,24 @@ fn main() {
|
||||
|
||||
// TODO: Perhaps the drivers should just be given the config, interface, and alternate setting
|
||||
// from xhcid.
|
||||
let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, endpoint_num, hid_desc)) = desc
|
||||
let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, endpoint_num_opt, hid_desc)) = desc
|
||||
.config_descs
|
||||
.iter()
|
||||
.find_map(|conf_desc| {
|
||||
let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| {
|
||||
if if_desc.class == 3 {
|
||||
let endpoint_num = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| {
|
||||
if endpoint.direction() == EndpDirection::In {
|
||||
let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| {
|
||||
if endpoint.ty() == EndpointTy::Interrupt && endpoint.direction() == EndpDirection::In {
|
||||
Some(endpoint_i + 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
});
|
||||
let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| {
|
||||
//TODO: should we do any filtering?
|
||||
Some(hid_desc)
|
||||
})?;
|
||||
Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, endpoint_num, hid_desc))
|
||||
Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, endpoint_num_opt, hid_desc))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -280,6 +280,10 @@ fn main() {
|
||||
config_desc: configuration_value,
|
||||
interface_desc: Some(interface_num),
|
||||
alternate_setting: Some(alternate_setting),
|
||||
protocol: Some(PROTOCOL_REPORT),
|
||||
//TODO: dynamically create good values, fix xhcid so it does not block on each request
|
||||
// This sets all reports to a duration of 4ms
|
||||
report_idles: vec![(0, 1)]
|
||||
})
|
||||
.expect("Failed to configure endpoints");
|
||||
|
||||
@@ -301,27 +305,34 @@ fn main() {
|
||||
let mut handler =
|
||||
ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor");
|
||||
|
||||
// Get all main items, and their global item options.
|
||||
{
|
||||
let mut report_buffer = vec![0u8; handler.total_byte_length];
|
||||
let report_ty = ReportTy::Input;
|
||||
let report_id = 0;
|
||||
let mut report_buffer = vec![0u8; handler.total_byte_length];
|
||||
let report_ty = ReportTy::Input;
|
||||
let report_id = 0;
|
||||
|
||||
let mut display =
|
||||
File::open("input:producer").expect("Failed to open orbital input socket");
|
||||
//TODO: let mut endpoint = handle.open_endpoint(endpoint_num as u8).expect("failed to open interrupt endpoint");
|
||||
let mut left_shift = false;
|
||||
let mut right_shift = false;
|
||||
let mut last_mouse_pos = (0, 0);
|
||||
let mut last_buttons = [false, false, false];
|
||||
loop {
|
||||
//TODO: get frequency from device
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
let mut display =
|
||||
File::open("input:producer").expect("Failed to open orbital input socket");
|
||||
let mut endpoint_opt = match endpoint_num_opt {
|
||||
Some(endpoint_num) => match handle.open_endpoint(endpoint_num as u8) {
|
||||
Ok(ok) => Some(ok),
|
||||
Err(err) => {
|
||||
log::warn!("failed to open endpoint {endpoint_num}: {err}");
|
||||
None
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
let mut left_shift = false;
|
||||
let mut right_shift = false;
|
||||
let mut last_mouse_pos = (0, 0);
|
||||
let mut last_buttons = [false, false, false];
|
||||
loop {
|
||||
//TODO: get frequency from device
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
|
||||
/*TODO: interrupt transfer
|
||||
if let Some(endpoint) = &mut endpoint_opt {
|
||||
// interrupt transfer
|
||||
endpoint.transfer_read(&mut report_buffer).expect("failed to get report");
|
||||
*/
|
||||
|
||||
} else {
|
||||
// control transfer
|
||||
reqs::get_report(
|
||||
&handle,
|
||||
@@ -332,123 +343,123 @@ fn main() {
|
||||
&mut report_buffer,
|
||||
)
|
||||
.expect("failed to get report");
|
||||
}
|
||||
|
||||
let mut mouse_pos = last_mouse_pos;
|
||||
let mut mouse_dx = 0i32;
|
||||
let mut mouse_dy = 0i32;
|
||||
let mut buttons = last_buttons;
|
||||
for event in handler
|
||||
.handle(&report_buffer)
|
||||
.expect("failed to parse report")
|
||||
{
|
||||
log::debug!("{:X?}", event);
|
||||
if event.usage_page == UsagePage::GenericDesktop as u32 {
|
||||
if event.usage == GenericDesktopUsage::X as u32 {
|
||||
if event.relative {
|
||||
mouse_dx += event.value;
|
||||
} else {
|
||||
mouse_pos.0 = event.value;
|
||||
}
|
||||
} else if event.usage == GenericDesktopUsage::Y as u32 {
|
||||
if event.relative {
|
||||
mouse_dy += event.value;
|
||||
} else {
|
||||
mouse_pos.1 = event.value;
|
||||
}
|
||||
let mut mouse_pos = last_mouse_pos;
|
||||
let mut mouse_dx = 0i32;
|
||||
let mut mouse_dy = 0i32;
|
||||
let mut buttons = last_buttons;
|
||||
for event in handler
|
||||
.handle(&report_buffer)
|
||||
.expect("failed to parse report")
|
||||
{
|
||||
log::debug!("{:X?}", event);
|
||||
if event.usage_page == UsagePage::GenericDesktop as u32 {
|
||||
if event.usage == GenericDesktopUsage::X as u32 {
|
||||
if event.relative {
|
||||
mouse_dx += event.value;
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported generic desktop usage 0x{:X}:0x{:X} value {}",
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
event.value
|
||||
);
|
||||
mouse_pos.0 = event.value;
|
||||
}
|
||||
} else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 {
|
||||
let (pressed, shift_opt) = if event.value != 0 {
|
||||
(true, Some(left_shift | right_shift))
|
||||
} else if event.usage == GenericDesktopUsage::Y as u32 {
|
||||
if event.relative {
|
||||
mouse_dy += event.value;
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
if event.usage == 0xE1 {
|
||||
left_shift = pressed;
|
||||
} else if event.usage == 0xE5 {
|
||||
right_shift = pressed;
|
||||
}
|
||||
send_key_event(
|
||||
&mut display,
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
pressed,
|
||||
shift_opt,
|
||||
);
|
||||
} else if event.usage_page == UsagePage::Button as u32 {
|
||||
if event.usage > 0 && event.usage as usize <= buttons.len() {
|
||||
buttons[event.usage as usize - 1] = event.value != 0;
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported buttons usage 0x{:X}:0x{:X} value {}",
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
event.value
|
||||
);
|
||||
mouse_pos.1 = event.value;
|
||||
}
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported usage 0x{:X}:0x{:X} value {}",
|
||||
"unsupported generic desktop usage 0x{:X}:0x{:X} value {}",
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
event.value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if mouse_pos != last_mouse_pos {
|
||||
last_mouse_pos = mouse_pos;
|
||||
|
||||
// ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital
|
||||
// expects the former range, so multiply by two here to translate
|
||||
// the usb coordinates to what orbital expects.
|
||||
let mouse_event = orbclient::event::MouseEvent {
|
||||
x: mouse_pos.0 * 2,
|
||||
y: mouse_pos.1 * 2,
|
||||
} else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 {
|
||||
let (pressed, shift_opt) = if event.value != 0 {
|
||||
(true, Some(left_shift | right_shift))
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
if event.usage == 0xE1 {
|
||||
left_shift = pressed;
|
||||
} else if event.usage == 0xE5 {
|
||||
right_shift = pressed;
|
||||
}
|
||||
send_key_event(
|
||||
&mut display,
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
pressed,
|
||||
shift_opt,
|
||||
);
|
||||
} else if event.usage_page == UsagePage::Button as u32 {
|
||||
if event.usage > 0 && event.usage as usize <= buttons.len() {
|
||||
buttons[event.usage as usize - 1] = event.value != 0;
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported buttons usage 0x{:X}:0x{:X} value {}",
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
event.value
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::info!(
|
||||
"unsupported usage 0x{:X}:0x{:X} value {}",
|
||||
event.usage_page,
|
||||
event.usage,
|
||||
event.value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match display.write(&mouse_event.to_event()) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
log::warn!("failed to send mouse event to orbital: {}", err);
|
||||
}
|
||||
if mouse_pos != last_mouse_pos {
|
||||
last_mouse_pos = mouse_pos;
|
||||
|
||||
// ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital
|
||||
// expects the former range, so multiply by two here to translate
|
||||
// the usb coordinates to what orbital expects.
|
||||
let mouse_event = orbclient::event::MouseEvent {
|
||||
x: mouse_pos.0 * 2,
|
||||
y: mouse_pos.1 * 2,
|
||||
};
|
||||
|
||||
match display.write(&mouse_event.to_event()) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
log::warn!("failed to send mouse event to orbital: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if mouse_dx != 0 || mouse_dy != 0 {
|
||||
let mouse_event = orbclient::event::MouseRelativeEvent {
|
||||
dx: mouse_dx,
|
||||
dy: mouse_dy,
|
||||
};
|
||||
if mouse_dx != 0 || mouse_dy != 0 {
|
||||
let mouse_event = orbclient::event::MouseRelativeEvent {
|
||||
dx: mouse_dx,
|
||||
dy: mouse_dy,
|
||||
};
|
||||
|
||||
match display.write(&mouse_event.to_event()) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
log::warn!("failed to send mouse event to orbital: {}", err);
|
||||
}
|
||||
match display.write(&mouse_event.to_event()) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
log::warn!("failed to send mouse event to orbital: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if buttons != last_buttons {
|
||||
last_buttons = buttons;
|
||||
if buttons != last_buttons {
|
||||
last_buttons = buttons;
|
||||
|
||||
let button_event = orbclient::event::ButtonEvent {
|
||||
left: buttons[0],
|
||||
right: buttons[1],
|
||||
middle: buttons[2],
|
||||
};
|
||||
let button_event = orbclient::event::ButtonEvent {
|
||||
left: buttons[0],
|
||||
right: buttons[1],
|
||||
middle: buttons[2],
|
||||
};
|
||||
|
||||
match display.write(&button_event.to_event()) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
log::warn!("failed to send button event to orbital: {}", err);
|
||||
}
|
||||
match display.write(&button_event.to_event()) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
log::warn!("failed to send button event to orbital: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,17 @@ use thiserror::Error;
|
||||
|
||||
pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub const PROTOCOL_BOOT: u8 = 0;
|
||||
pub const PROTOCOL_REPORT: u8 = 1;
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct ConfigureEndpointsReq {
|
||||
/// Index into the configuration descriptors of the device descriptor.
|
||||
pub config_desc: u8,
|
||||
pub interface_desc: Option<u8>,
|
||||
pub alternate_setting: Option<u8>,
|
||||
pub protocol: Option<u8>,
|
||||
pub report_idles: Vec<(u8, u8)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
||||
@@ -181,6 +181,7 @@ impl Setup {
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn set_interface(interface: u8, alternate_setting: u8) -> Self {
|
||||
Self {
|
||||
kind: 0b0000_0001,
|
||||
@@ -190,4 +191,24 @@ impl Setup {
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn set_protocol(interface: u8, protocol: u8) -> Self {
|
||||
Self {
|
||||
kind: 0b0010_0001,
|
||||
request: 0x0B,
|
||||
value: protocol as u16,
|
||||
index: interface as u16,
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn set_idle(interface: u8, report_id: u8, duration: u8) -> Self {
|
||||
Self {
|
||||
kind: 0b0010_0001,
|
||||
request: 0x0A,
|
||||
value: (report_id as u16) | ((duration as u16) << 8),
|
||||
index: interface as u16,
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,10 +481,12 @@ impl Xhci {
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_configuration(&self, port: usize, config: u8) -> Result<()> {
|
||||
debug!("Setting configuration value {} to port {}", config, port);
|
||||
self.device_req_no_data(port, usb::Setup::set_configuration(config)).await
|
||||
}
|
||||
|
||||
async fn set_interface(
|
||||
&self,
|
||||
port: usize,
|
||||
@@ -498,6 +500,33 @@ impl Xhci {
|
||||
).await
|
||||
}
|
||||
|
||||
async fn set_protocol(
|
||||
&self,
|
||||
port: usize,
|
||||
interface_num: u8,
|
||||
protocol: u8,
|
||||
) -> Result<()> {
|
||||
debug!("Setting idle value {} (protocol {}) to port {}", interface_num, protocol, port);
|
||||
self.device_req_no_data(
|
||||
port,
|
||||
usb::Setup::set_protocol(interface_num, protocol),
|
||||
).await
|
||||
}
|
||||
|
||||
async fn set_idle(
|
||||
&self,
|
||||
port: usize,
|
||||
interface_num: u8,
|
||||
report_id: u8,
|
||||
duration: u8,
|
||||
) -> Result<()> {
|
||||
debug!("Setting idle value {} (report_id {}, duration {}) to port {}", interface_num, report_id, duration, port);
|
||||
self.device_req_no_data(
|
||||
port,
|
||||
usb::Setup::set_idle(interface_num, report_id, duration),
|
||||
).await
|
||||
}
|
||||
|
||||
async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> {
|
||||
let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
@@ -838,10 +867,18 @@ impl Xhci {
|
||||
// Tell the device about this configuration.
|
||||
self.set_configuration(port, configuration_value).await?;
|
||||
|
||||
if let (Some(interface_num), Some(alternate_setting)) =
|
||||
(req.interface_desc, req.alternate_setting)
|
||||
{
|
||||
self.set_interface(port, interface_num, alternate_setting).await?;
|
||||
if let Some(interface_num) = req.interface_desc {
|
||||
if let Some(alternate_setting) = req.alternate_setting {
|
||||
self.set_interface(port, interface_num, alternate_setting).await?;
|
||||
}
|
||||
|
||||
if let Some(protocol) = req.protocol {
|
||||
self.set_protocol(port, interface_num, protocol).await?;
|
||||
}
|
||||
|
||||
for (report_id, duration) in req.report_idles {
|
||||
self.set_idle(port, interface_num, report_id, duration).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user