Skip to content

Commit 9972142

Browse files
committed
Implement latch control
1 parent 3870ee0 commit 9972142

File tree

4 files changed

+181
-0
lines changed

4 files changed

+181
-0
lines changed

Cargo.lock

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ edition = "2018"
1313
[dependencies]
1414
clap = "2.33.0"
1515
indoc = "0.3.1"
16+
nix = "0.13.0"

src/latch.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::fs::File;
2+
use std::path::Path;
3+
use std::io::Result;
4+
use std::os::unix::io::AsRawFd;
5+
6+
7+
use nix::ioctl_none;
8+
use nix::ioctl_read;
9+
use nix::request_code_read;
10+
use nix::request_code_none;
11+
use nix::convert_ioctl_res;
12+
use nix::ioc;
13+
14+
15+
#[derive(Debug)]
16+
pub enum OpMode {
17+
Tablet,
18+
Laptop,
19+
Studio,
20+
}
21+
22+
impl OpMode {
23+
pub fn as_str(&self) -> &'static str {
24+
match self {
25+
OpMode::Tablet => "tablet",
26+
OpMode::Laptop => "laptop",
27+
OpMode::Studio => "studio",
28+
}
29+
}
30+
}
31+
32+
impl std::fmt::Display for OpMode {
33+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
34+
write!(f, "{}", self.as_str())
35+
}
36+
}
37+
38+
39+
#[derive(Debug)]
40+
pub struct Device {
41+
file: File,
42+
}
43+
44+
impl Device {
45+
pub fn open() -> Result<Self> {
46+
Device::open_path("/dev/surface_dtx")
47+
}
48+
49+
pub fn open_path<P: AsRef<Path>>(path: P) -> Result<Self> {
50+
let file = File::open(path)?;
51+
Ok(Device { file })
52+
}
53+
54+
pub fn latch_lock(&self) -> Result<()> {
55+
unsafe {
56+
dtx_latch_lock(self.file.as_raw_fd())
57+
.map_err(|_| std::io::Error::last_os_error())?;
58+
}
59+
Ok(())
60+
}
61+
62+
pub fn latch_unlock(&self) -> Result<()> {
63+
unsafe {
64+
dtx_latch_unlock(self.file.as_raw_fd())
65+
.map_err(|_| std::io::Error::last_os_error())?;
66+
}
67+
Ok(())
68+
}
69+
70+
pub fn latch_request(&self) -> Result<()> {
71+
unsafe {
72+
dtx_latch_request(self.file.as_raw_fd())
73+
.map_err(|_| std::io::Error::last_os_error())?;
74+
}
75+
Ok(())
76+
}
77+
78+
pub fn get_opmode(&self) -> Result<OpMode> {
79+
use std::io;
80+
81+
let mut opmode: u32 = 0;
82+
unsafe {
83+
dtx_get_opmode(self.file.as_raw_fd(), &mut opmode as *mut u32)
84+
.map_err(|_| std::io::Error::last_os_error())?;
85+
}
86+
87+
match opmode {
88+
0 => Ok(OpMode::Tablet),
89+
1 => Ok(OpMode::Laptop),
90+
2 => Ok(OpMode::Studio),
91+
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "invalid opmode").into()),
92+
}
93+
}
94+
}
95+
96+
97+
ioctl_none!(dtx_latch_lock, 0x11, 0x01);
98+
ioctl_none!(dtx_latch_unlock, 0x11, 0x02);
99+
ioctl_none!(dtx_latch_request, 0x11, 0x03);
100+
ioctl_none!(dtx_latch_open, 0x11, 0x04);
101+
ioctl_read!(dtx_get_opmode, 0x11, 0x05, u32);

src/main.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use indoc::indoc;
44

55
mod dgpu;
66
mod perf;
7+
mod latch;
78

89

910
fn app() -> clap::App<'static, 'static> {
@@ -59,6 +60,22 @@ fn app() -> clap::App<'static, 'static> {
5960
.subcommand(SubCommand::with_name("get")
6061
.about("Get the current dGPU power state"));
6162

63+
let latch = SubCommand::with_name("latch")
64+
.about("Control the latch/dtx-system on the Surface Book 2")
65+
.setting(AppSettings::SubcommandRequiredElseHelp)
66+
.subcommand(SubCommand::with_name("lock")
67+
.about("Lock the latch")
68+
.display_order(1))
69+
.subcommand(SubCommand::with_name("unlock")
70+
.about("Unlock the latch")
71+
.display_order(2))
72+
.subcommand(SubCommand::with_name("request")
73+
.about("Request latch-open or abort if already in progress")
74+
.display_order(3))
75+
.subcommand(SubCommand::with_name("get-opmode")
76+
.about("Query the current device operation mode")
77+
.display_order(4));
78+
6279
App::new(clap::crate_name!())
6380
.version(clap::crate_version!())
6481
.author(clap::crate_authors!("\n"))
@@ -68,6 +85,7 @@ fn app() -> clap::App<'static, 'static> {
6885
.subcommand(status)
6986
.subcommand(perf)
7087
.subcommand(dgpu)
88+
.subcommand(latch)
7189
}
7290

7391
fn main() {
@@ -77,6 +95,7 @@ fn main() {
7795
("status", Some(m)) => cmd_status(m),
7896
("dgpu", Some(m)) => cmd_dgpu(m),
7997
("performance", Some(m)) => cmd_perf(m),
98+
("latch", Some(m)) => cmd_latch(m),
8099
_ => unreachable!(),
81100
};
82101

@@ -138,3 +157,31 @@ fn cmd_perf_get(_: &clap::ArgMatches) -> Result<()> {
138157
println!("{}", perf::Device::open()?.get_mode()?);
139158
Ok(())
140159
}
160+
161+
162+
fn cmd_latch(m: &clap::ArgMatches) -> Result<()> {
163+
match m.subcommand() {
164+
("lock", Some(m)) => cmd_latch_lock(m),
165+
("unlock", Some(m)) => cmd_latch_unlock(m),
166+
("request", Some(m)) => cmd_latch_request(m),
167+
("get-opmode", Some(m)) => cmd_latch_get_opmode(m),
168+
_ => unreachable!(),
169+
}
170+
}
171+
172+
fn cmd_latch_lock(_: &clap::ArgMatches) -> Result<()> {
173+
latch::Device::open()?.latch_lock()
174+
}
175+
176+
fn cmd_latch_unlock(_: &clap::ArgMatches) -> Result<()> {
177+
latch::Device::open()?.latch_unlock()
178+
}
179+
180+
fn cmd_latch_request(_: &clap::ArgMatches) -> Result<()> {
181+
latch::Device::open()?.latch_request()
182+
}
183+
184+
fn cmd_latch_get_opmode(_: &clap::ArgMatches) -> Result<()> {
185+
println!("{}", latch::Device::open()?.get_opmode()?);
186+
Ok(())
187+
}

0 commit comments

Comments
 (0)