Skip to content

freebsd: Use hidraw instead of hidapi for non-USB devices #95

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 61 additions & 0 deletions framework_lib/src/freebsd_hid.rs
Original file line number Diff line number Diff line change
@@ -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<std::fs::File> {
// 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
}
2 changes: 2 additions & 0 deletions framework_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
75 changes: 75 additions & 0 deletions framework_lib/src/touchpad.rs
Original file line number Diff line number Diff line change
@@ -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<u8> {
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<u16> {
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<u8, HidError> {
device.send_feature_report(&[PIX_REPORT_ID, addr, 0x10, 0])?;

Expand All @@ -13,13 +86,15 @@ fn read_byte(device: &HidDevice, addr: u8) -> Result<u8, HidError> {
Ok(buf[3])
}

#[cfg(not(target_os = "freebsd"))]
fn read_ver(device: &HidDevice) -> Result<u16, HidError> {
Ok(u16::from_le_bytes([
read_byte(device, 0xb2)?,
read_byte(device, 0xb3)?,
]))
}

#[cfg(not(target_os = "freebsd"))]
pub fn print_touchpad_fw_ver() -> Result<(), HidError> {
debug!("Looking for touchpad HID device");
match HidApi::new() {
Expand Down
Loading