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/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 fe4be04d..a5ef03dc 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -1,8 +1,81 @@ +#[cfg(not(target_os = "freebsd"))] use hidapi::{HidApi, HidDevice, HidError}; +#[cfg(target_os = "freebsd")] +use crate::freebsd_hid::*; +#[cfg(target_os = "freebsd")] +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<()> { + 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)?); + + 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 +86,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 +94,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() {