diff --git a/Cargo.lock b/Cargo.lock index 8da1af7f15..4b823ba54a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,14 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arg_parser" version = "0.1.0" @@ -34,6 +42,16 @@ dependencies = [ "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.7" @@ -114,6 +132,20 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -1054,6 +1086,11 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "1.0.14" @@ -1075,6 +1112,14 @@ dependencies = [ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thiserror" version = "1.0.10" @@ -1308,6 +1353,11 @@ dependencies = [ "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -1328,6 +1378,14 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "usbctl" +version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xhcid 0.1.0", +] + [[package]] name = "usbhidd" version = "0.1.0" @@ -1375,6 +1433,11 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.5" @@ -1472,8 +1535,10 @@ dependencies = [ ] [metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" @@ -1486,6 +1551,7 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" @@ -1585,8 +1651,10 @@ dependencies = [ "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad" "checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" @@ -1609,12 +1677,14 @@ dependencies = [ "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" diff --git a/Cargo.toml b/Cargo.toml index 0044204257..3c1f2a91d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "vboxd", "vesad", "xhcid", + "usbctl", "usbhidd", "usbscsid", ] diff --git a/usbctl/.gitignore b/usbctl/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/usbctl/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbctl/Cargo.toml b/usbctl/Cargo.toml new file mode 100644 index 0000000000..ee18af204b --- /dev/null +++ b/usbctl/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "usbctl" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = "2.33" +xhcid = { path = "../xhcid" } diff --git a/usbctl/src/main.rs b/usbctl/src/main.rs new file mode 100644 index 0000000000..0a48029c9d --- /dev/null +++ b/usbctl/src/main.rs @@ -0,0 +1,35 @@ +use clap::{Arg, App}; +use xhcid_interface::XhciClientHandle; + +fn main() { + let matches = App::new("usbctl") + .arg(Arg::with_name("SCHEME").takes_value(true).required(true).long("scheme").short("s")) + .subcommand(App::new("port") + .arg(Arg::with_name("PORT").takes_value(true).required(true)) + .subcommand(App::new("status") + ) + .subcommand(App::new("endpoint") + .arg(Arg::with_name("ENDPOINT_NUM").takes_value(true).required(true)) + .subcommand(App::new("status")) + ) + ) + .get_matches(); + + let scheme = matches.value_of("SCHEME").expect("no scheme"); + + if let Some(port_scmd_matches) = matches.subcommand_matches("port") { + let port = port_scmd_matches.value_of("PORT").expect("invalid utf-8 for PORT argument").parse::().expect("expected PORT to be an integer"); + + let handle = XhciClientHandle::new(scheme.to_owned(), port); + + if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") { + let state = handle.port_state().expect("Failed to get port state"); + println!("{}", state.as_str()); + } else if let Some(endp_scmd_matches) = port_scmd_matches.subcommand_matches("endpoint") { + let endp_num = endp_scmd_matches.value_of("ENDPOINT_NUM").expect("no valid ENDPOINT_NUM").parse::().expect("expected ENDPOINT_NUM to be an 8-bit integer"); + let mut endp_handle = handle.open_endpoint(endp_num).expect("Failed to open endpoint"); + let state = endp_handle.status().expect("Failed to get endpoint state"); + println!("{}", state.as_str()); + } + } +} diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 57394c9d1f..469a0006e1 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -95,8 +95,6 @@ impl<'a> BulkOnlyTransport<'a> { let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8; let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8; - bulk_only_mass_storage_reset(handle, if_desc.number.into())?; - let max_lun = get_max_lun(handle, 0)?; println!("BOT_MAX_LUN {}", max_lun); @@ -147,6 +145,8 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { dbg!(self.bulk_in.status()?, self.bulk_out.status()?); + bulk_only_mass_storage_reset(&self.handle, self.interface_num.into())?; + match self.bulk_out.transfer_write(&cbw_bytes)? { PortTransferStatus::ShortPacket(31) => (), PortTransferStatus::Stalled => { @@ -154,7 +154,7 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { self.clear_stall_out()?; dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - _ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"), + _ => (),//panic!("invalid number of CBW bytes written; expected a short packet of length 31 (0x1F)"), } match data { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 2d0fe8fde9..e49570a260 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -388,6 +388,9 @@ impl Xhci { } pub fn update_default_control_pipe(&mut self, input_context: &mut Dma, slot_id: u8, dev_desc: &DevDesc) -> Result<()> { + input_context.add_context.write(1 << 1); + input_context.drop_context.write(0); + let new_max_packet_size = if dev_desc.major_version() == 2 { u32::from(dev_desc.packet_size) } else { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 8d37f2c6b7..d12f21f318 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -217,7 +217,7 @@ impl Xhci { let (cmd, cycle) = ring.next(); cmd.status(false, cycle); } - self.dbs[ps.slot as usize].write(1); + self.dbs[ps.slot as usize].write(Self::def_control_endp_doorbell()); { let event = self.cmd.next_event(); @@ -259,33 +259,34 @@ impl Xhci { } fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); + let slot = self .port_states .get(&port_num) .ok_or(Error::new(EBADF))? .slot; - { - let (cmd, cycle, event) = self.cmd.next(); - cmd.reset_endpoint(slot, endp_num + 1, tsp, cycle); - self.dbs[0].write(0); + let (cmd, cycle, event) = self.cmd.next(); + cmd.reset_endpoint(slot, endp_num_xhc, tsp, cycle); - while event.data.read() == 0 { - println!(" - Waiting for event"); - } + self.dbs[0].write(0); - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } - - cmd.reserved(false); - event.reserved(false); - - self.run.ints[0].erdp.write(self.cmd.erdp()); + while event.data.read() == 0 { + println!(" - Waiting for event"); } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); + return Err(Error::new(EIO)); + } + + cmd.reserved(false); + event.reserved(false); + + self.run.ints[0].erdp.write(self.cmd.erdp()); Ok(()) } @@ -391,7 +392,10 @@ impl Xhci { return Err(Error::new(EIO)); } - let new_context_entries = 1 + endpoints.len() as u32; + let new_context_entries = match endpoints.last() { + Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), + None => 1, + } + 1; input_context.device.slot.a.write( (current_slot_a & !CONTEXT_ENTRIES_MASK) @@ -406,18 +410,19 @@ impl Xhci { let lec = self.cap.lec(); - for index in 0..endpoints.len() as u8 { - let endp_num = index + 1; - let xhc_endp_num = endp_num + 1; + for endp_idx in 0..endpoints.len() as u8 { + let endp_num = endp_idx + 1; - input_context.add_context.writef(1 << xhc_endp_num, true); + let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); + + input_context.add_context.writef(1 << endp_num_xhc, true); let endp_ctx = input_context .device .endpoints - .get_mut(endp_num as usize) + .get_mut(endp_num_xhc as usize - 1) .ok_or(Error::new(EIO))?; - let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?; let max_streams = endp_desc.max_streams(); let max_psa_size = self.cap.max_psa_size(); @@ -589,6 +594,30 @@ impl Xhci { }, ) } + const fn def_control_endp_doorbell() -> u32 { + 1 + } + // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of + // mixing the two up. + fn endp_num_to_dci(endp_num: u8, desc: &EndpDesc) -> u8 { + if endp_num == 0 { unreachable!("EndpDesc cannot be obtained from the default control endpoint") } + + if desc.is_control() || desc.direction() == EndpDirection::In { + endp_num * 2 + 1 + } else if desc.direction() == EndpDirection::Out { + endp_num * 2 + } else { unreachable!() } + } + fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> { + self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EIO)) + } + fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { + let db_target = Self::endp_num_to_dci(endp_num, desc); + let db_task_id: u16 = stream_id; + + (u32::from(db_task_id) << 16) + | u32::from(db_target) + } // TODO: Rename DeviceReqData to something more general. fn transfer( &mut self, @@ -598,7 +627,6 @@ impl Xhci { ) -> Result<(u8, u32)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - let xhc_endp_num = endp_num + 1; // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), // UB. let dma_buffer = match buf { @@ -629,12 +657,13 @@ impl Xhci { .get(endp_idx as usize) .ok_or(Error::new(EBADFD))?; + let direction = endp_desc.direction(); + if endp_desc.is_isoch() { return Err(Error::new(ENOSYS)); } if EndpDirection::from(buf.direction()) != endp_desc.direction() { - dbg!(buf.direction(), endp_desc.direction()); return Err(Error::new(EBADF)); } @@ -688,8 +717,7 @@ impl Xhci { } let stream_id = 1u16; - self.dbs[port_state.slot as usize] - .write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16)); + self.dbs[port_state.slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); let (completion_code, bytes_transferred) = { let event = self.cmd.next_event(); @@ -953,7 +981,7 @@ impl Xhci { let (cmd, cycle) = ring.next(); cmd.status(transfer_kind == TransferKind::In, cycle); } - self.dbs[port_state.slot as usize].write(1); + self.dbs[port_state.slot as usize].write(Self::def_control_endp_doorbell()); { let event = self.cmd.next_event(); @@ -1441,7 +1469,12 @@ impl SchemeMut for Xhci { impl Xhci { pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { let slot = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?.slot; - let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; + let endp_num_xhc = if endp_num != 0 { + Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?) + } else { + 1 + }; + let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num_xhc as usize - 1).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; Ok(match raw { 0 => EndpointStatus::Disabled, 1 => EndpointStatus::Enabled, @@ -1473,6 +1506,12 @@ impl Xhci { } pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let direction = if endp_num != 0 { + let endp_desc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EBADFD))?; + endp_desc.direction() + } else { + EndpDirection::Bidirectional + }; let endpoint_state: &mut EndpointState = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; let ring = match &mut endpoint_state.transfer { &mut super::RingOrStreams::Ring(ref mut ring) => ring, @@ -1483,17 +1522,21 @@ impl Xhci { let deque_ptr_and_cycle = ring.register(); let slot = port_state.slot; - self.set_tr_deque_ptr(slot, endp_num, deque_ptr_and_cycle)?; + self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle)?; - let endp_num_xhc = endp_num + 1; - self.dbs[slot as usize].write( - (1 << 16) // stream id - | u32::from(endp_num_xhc) - ); + let stream_id = 1u16; + self.dbs[slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); Ok(()) } - pub fn set_tr_deque_ptr(&mut self, slot: u8, endp_num: u8, deque_ptr_and_cycle: u64) -> Result<()> { - let endp_num_xhc = endp_num + 1; + pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { + Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize).ok_or(Error::new(EIO))?.direction()) + } + pub fn slot(&self, port_num: usize) -> Result { + Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) + } + pub fn set_tr_deque_ptr(&mut self, port_num: usize, endp_num: u8, deque_ptr_and_cycle: u64) -> Result<()> { + let slot = self.slot(port_num)?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); // TODO: Merge these command boilerplates into a single function. self.run.ints[0].erdp.write(self.cmd.erdp());