From d2962ce21b2bfc344d82296492dd39d2d4c1e170 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sat, 22 Mar 2025 23:00:31 +0800 Subject: [PATCH 1/2] freebsd: Use hidraw ioctls to get touchpad firmware version Signed-off-by: Daniel Schaefer --- README.md | 3 +- framework_lib/src/touchpad.rs | 106 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 01d2205e..a78c1b25 100644 --- a/README.md +++ b/README.md @@ -359,7 +359,8 @@ Keyboard backlight: 0% ## FreeBSD ``` -sudo pkg install hidapi +# Install pre-requisites +sudo pkg install rust hidapi # Build the library and tool cargo build --no-default-features --features freebsd diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs index fe4be04d..df692a24 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -1,8 +1,112 @@ use hidapi::{HidApi, HidDevice, HidError}; +#[cfg(target_os = "freebsd")] +use nix::{ioctl_read, ioctl_read_buf, ioctl_readwrite, ioctl_readwrite_buf, ioctl_write_buf}; +#[cfg(target_os = "freebsd")] +use std::fs::OpenOptions; +use std::io::{Read, Write}; +#[cfg(target_os = "freebsd")] +use std::os::fd::AsRawFd; +#[cfg(target_os = "freebsd")] +use std::os::unix::fs::OpenOptionsExt; + +#[cfg(target_os = "freebsd")] +#[repr(C)] +pub struct HidIocGrInfo { + bustype: u32, + vendor: u16, + product: u16, +} + +#[cfg(target_os = "freebsd")] +//ioctl_readwrite!(hidraw_get_report_desc, b'U', 21, HidrawGetReportDesc); +//ioctl_readwrite!(hidraw_get_report, b'U', 23, HidrawGetReport); +//ioctl_write!(hidraw_set_report, b'U', 24, HidrawSetReport); +ioctl_read!(hidiocgrawninfo, b'U', 32, HidIocGrInfo); +//ioctl_readwrite!(hidiocgrawnname, b'U', 33, HidIocGrName); +ioctl_read_buf!(hid_raw_name, b'U', 33, u8); +ioctl_write_buf!(hid_set_feature, b'U', 35, u8); +ioctl_readwrite_buf!(hid_get_feature, b'U', 36, u8); pub const PIX_VID: u16 = 0x093A; pub const PIX_REPORT_ID: u8 = 0x43; +#[cfg(target_os = "freebsd")] +pub fn print_touchpad_fw_ver() -> Option<()> { + println!("Touchpad"); + let path = "/dev/hidraw2"; + let mut file = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(libc::O_NONBLOCK) + .open(path) + .unwrap(); + + let mut desc = HidIocGrInfo { + bustype: 0, + vendor: 0, + product: 0, + }; + unsafe { + let fd = file.as_raw_fd(); + if let Err(err) = hidiocgrawninfo(fd, &mut desc) { + error!("Failed to access hidraw at {}: {:?}", path, err); + return None; + } + debug!( + "Found {:04X}:{:04X} Bustype: {:04X}", + desc.vendor, desc.product, desc.bustype + ); + // TODO: Iterate over all /dev/hidraw* devices and find the right one + // if vid != PIX_VID || (pid != 0x0274 && pid != 0x0239) { + println!(" IC Type: {:04X}", desc.product); + + let mut buf = [0u8; 255]; + if let Err(err) = hid_raw_name(fd, &mut buf) { + error!("Failed to access hidraw at {}: {:?}", path, err); + return None; + } + let name = std::str::from_utf8(&buf) + .unwrap() + .trim_end_matches(char::from(0)); + debug!(" Name: {}", name); + + println!(" Firmware Version: v{:04X}", read_ver(fd)?); + + read_byte(fd, 0x2b); + } + + Some(()) +} + +fn read_byte(fd: i32, addr: u8) -> Option { + unsafe { + let mut buf: [u8; 4] = [PIX_REPORT_ID, addr, 0x10, 0]; + if let Err(err) = hid_set_feature(fd, &mut buf) { + error!("Failed to hid_set_feature: {:?}", err); + return None; + } + //device.send_feature_report(&[PIX_REPORT_ID, addr, 0x10, 0])?; + + let mut buf = [0u8; 4]; + buf[0] = PIX_REPORT_ID; + + if let Err(err) = hid_get_feature(fd, &mut buf) { + error!("Failed to hid_get_feature: {:?}", err); + return None; + } + Some(buf[3]) + } +} + +#[cfg(target_os = "freebsd")] +fn read_ver(device: i32) -> Option { + Some(u16::from_le_bytes([ + read_byte(device, 0xb2)?, + read_byte(device, 0xb3)?, + ])) +} + +#[cfg(not(target_os = "freebsd"))] fn read_byte(device: &HidDevice, addr: u8) -> Result { device.send_feature_report(&[PIX_REPORT_ID, addr, 0x10, 0])?; @@ -13,6 +117,7 @@ fn read_byte(device: &HidDevice, addr: u8) -> Result { Ok(buf[3]) } +#[cfg(not(target_os = "freebsd"))] fn read_ver(device: &HidDevice) -> Result { Ok(u16::from_le_bytes([ read_byte(device, 0xb2)?, @@ -20,6 +125,7 @@ fn read_ver(device: &HidDevice) -> Result { ])) } +#[cfg(not(target_os = "freebsd"))] pub fn print_touchpad_fw_ver() -> Result<(), HidError> { debug!("Looking for touchpad HID device"); match HidApi::new() { From bcdf6083ba4d70c80248202b7af42c6f87a4c53c Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 23 Mar 2025 19:37:58 +0800 Subject: [PATCH 2/2] freebsd: Extract ioctl hidraw to separate module Signed-off-by: Daniel Schaefer --- framework_lib/src/freebsd_hid.rs | 61 ++++++++++++++++++++ framework_lib/src/lib.rs | 2 + framework_lib/src/touchpad.rs | 95 +++++++++++--------------------- 3 files changed, 95 insertions(+), 63 deletions(-) create mode 100644 framework_lib/src/freebsd_hid.rs diff --git a/framework_lib/src/freebsd_hid.rs b/framework_lib/src/freebsd_hid.rs new file mode 100644 index 00000000..efeb5003 --- /dev/null +++ b/framework_lib/src/freebsd_hid.rs @@ -0,0 +1,61 @@ +use nix::{ioctl_read, ioctl_read_buf, ioctl_readwrite, ioctl_readwrite_buf, ioctl_write_buf}; +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; +use std::os::unix::fs::OpenOptionsExt; + +#[repr(C)] +pub struct HidIocGrInfo { + pub bustype: u32, + pub vendor: u16, + pub product: u16, +} + +//ioctl_readwrite!(hidraw_get_report_desc, b'U', 21, HidrawGetReportDesc); +//ioctl_readwrite!(hidraw_get_report, b'U', 23, HidrawGetReport); +//ioctl_write!(hidraw_set_report, b'U', 24, HidrawSetReport); +ioctl_read!(hidiocgrawninfo, b'U', 32, HidIocGrInfo); +//ioctl_readwrite!(hidiocgrawnname, b'U', 33, HidIocGrName); +ioctl_read_buf!(hid_raw_name, b'U', 33, u8); +ioctl_write_buf!(hid_set_feature, b'U', 35, u8); +ioctl_readwrite_buf!(hid_get_feature, b'U', 36, u8); + +pub fn hidraw_open(vid: u16, pid: u16) -> Option { + // TODO: List files in the directory + for i in 0..32 { + let path = format!("/dev/hidraw{}", i); + let file = if let Ok(f) = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(libc::O_NONBLOCK) + .open(&path) + { + f + } else { + debug!("{} not found", path); + continue; + }; + + let mut desc = HidIocGrInfo { + bustype: 0, + vendor: 0, + product: 0, + }; + unsafe { + let fd = file.as_raw_fd(); + if let Err(err) = hidiocgrawninfo(fd, &mut desc) { + error!("Failed to access hidraw at {}: {:?}", path, err); + return None; + } + debug!( + "Found {:04X}:{:04X} Bustype: {:04X}", + desc.vendor, desc.product, desc.bustype + ); + if desc.vendor == vid && desc.product == pid { + return Some(file); + } + } + } + error!("No matching hidraw found. Is the hidraw kernel module loaded?"); + None +} diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index 50fa9b03..7d59031d 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -16,6 +16,8 @@ extern crate log; pub mod audio_card; #[cfg(feature = "rusb")] pub mod camera; +#[cfg(target_os = "freebsd")] +pub mod freebsd_hid; #[cfg(feature = "hidapi")] pub mod touchpad; diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs index df692a24..a5ef03dc 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -1,78 +1,47 @@ +#[cfg(not(target_os = "freebsd"))] use hidapi::{HidApi, HidDevice, HidError}; -#[cfg(target_os = "freebsd")] -use nix::{ioctl_read, ioctl_read_buf, ioctl_readwrite, ioctl_readwrite_buf, ioctl_write_buf}; -#[cfg(target_os = "freebsd")] -use std::fs::OpenOptions; -use std::io::{Read, Write}; -#[cfg(target_os = "freebsd")] -use std::os::fd::AsRawFd; -#[cfg(target_os = "freebsd")] -use std::os::unix::fs::OpenOptionsExt; #[cfg(target_os = "freebsd")] -#[repr(C)] -pub struct HidIocGrInfo { - bustype: u32, - vendor: u16, - product: u16, -} - +use crate::freebsd_hid::*; #[cfg(target_os = "freebsd")] -//ioctl_readwrite!(hidraw_get_report_desc, b'U', 21, HidrawGetReportDesc); -//ioctl_readwrite!(hidraw_get_report, b'U', 23, HidrawGetReport); -//ioctl_write!(hidraw_set_report, b'U', 24, HidrawSetReport); -ioctl_read!(hidiocgrawninfo, b'U', 32, HidIocGrInfo); -//ioctl_readwrite!(hidiocgrawnname, b'U', 33, HidIocGrName); -ioctl_read_buf!(hid_raw_name, b'U', 33, u8); -ioctl_write_buf!(hid_set_feature, b'U', 35, u8); -ioctl_readwrite_buf!(hid_get_feature, b'U', 36, u8); +use std::os::fd::AsRawFd; pub const PIX_VID: u16 = 0x093A; +pub const TP_PID: u16 = 0x0274; pub const PIX_REPORT_ID: u8 = 0x43; #[cfg(target_os = "freebsd")] pub fn print_touchpad_fw_ver() -> Option<()> { - println!("Touchpad"); - let path = "/dev/hidraw2"; - let mut file = OpenOptions::new() - .read(true) - .write(true) - .custom_flags(libc::O_NONBLOCK) - .open(path) - .unwrap(); - - let mut desc = HidIocGrInfo { - bustype: 0, - vendor: 0, - product: 0, - }; - unsafe { - let fd = file.as_raw_fd(); - if let Err(err) = hidiocgrawninfo(fd, &mut desc) { - error!("Failed to access hidraw at {}: {:?}", path, err); - return None; - } - debug!( - "Found {:04X}:{:04X} Bustype: {:04X}", - desc.vendor, desc.product, desc.bustype - ); - // TODO: Iterate over all /dev/hidraw* devices and find the right one - // if vid != PIX_VID || (pid != 0x0274 && pid != 0x0239) { - println!(" IC Type: {:04X}", desc.product); - - let mut buf = [0u8; 255]; - if let Err(err) = hid_raw_name(fd, &mut buf) { - error!("Failed to access hidraw at {}: {:?}", path, err); - return None; - } - let name = std::str::from_utf8(&buf) - .unwrap() - .trim_end_matches(char::from(0)); - debug!(" Name: {}", name); + if let Some(file) = hidraw_open(PIX_VID, TP_PID) { + println!("Touchpad"); + unsafe { + let fd = file.as_raw_fd(); + + let mut desc = HidIocGrInfo { + bustype: 0, + vendor: 0, + product: 0, + }; + if let Err(err) = hidiocgrawninfo(fd, &mut desc) { + error!("Failed to call hidiocgrawninfo: {}", err); + return None; + } + println!(" IC Type: {:04X}", desc.product); + + let mut buf = [0u8; 255]; + if let Err(err) = hid_raw_name(fd, &mut buf) { + error!("Failed to call hid_raw_name: {}", err); + return None; + } + let name = std::str::from_utf8(&buf) + .unwrap() + .trim_end_matches(char::from(0)); + debug!(" Name: {}", name); - println!(" Firmware Version: v{:04X}", read_ver(fd)?); + println!(" Firmware Version: v{:04X}", read_ver(fd)?); - read_byte(fd, 0x2b); + read_byte(fd, 0x2b); + } } Some(())