use std::{
fs::{
File,
OpenOptions,
},
io,
os::{
fd::{
AsFd,
BorrowedFd,
},
unix::{
fs::OpenOptionsExt,
io::{
AsRawFd,
IntoRawFd,
RawFd,
},
},
},
};
use crate::{
error::Result,
fe::sys::DtvPropertyRaw,
};
const VENDOR_TBS: u32 = 0x544d;
const MODULATOR_INPUT_BITRATE: u32 = 33;
#[derive(Debug)]
pub struct SecDevice {
fd_in: File,
fd_out: File,
vendor_id: Option<u32>,
device_id: Option<u32>,
}
impl AsRawFd for SecDevice {
fn as_raw_fd(&self) -> RawFd {
self.fd_out.as_raw_fd()
}
}
impl AsFd for SecDevice {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd_out.as_fd()
}
}
impl SecDevice {
pub fn open(adapter: u32, device: u32) -> Result<SecDevice> {
let ci_path = format!("/dev/dvb/adapter{}/ci{}", adapter, device);
let sec_path = format!("/dev/dvb/adapter{}/sec{}", adapter, device);
let try_open = |path: &str| -> io::Result<(File, File)> {
let fd_in = OpenOptions::new()
.write(true)
.custom_flags(::nix::libc::O_NONBLOCK)
.open(path)?;
let fd_out = OpenOptions::new()
.read(true)
.custom_flags(::nix::libc::O_NONBLOCK)
.open(path)?;
Ok((fd_in, fd_out))
};
let (fd_in, fd_out) = match try_open(&ci_path) {
Err(ref e) if e.kind() == io::ErrorKind::NotFound => try_open(&sec_path)?,
result => result?,
};
let vendor_id = crate::sysfs::read_hex_attr(&fd_out, "vendor");
let device_id = crate::sysfs::read_hex_attr(&fd_out, "device");
Ok(SecDevice {
fd_in,
fd_out,
vendor_id,
device_id,
})
}
pub fn vendor_id(&self) -> Option<u32> {
self.vendor_id
}
pub fn device_id(&self) -> Option<u32> {
self.device_id
}
pub fn fd_in(&self) -> RawFd {
self.fd_in.as_raw_fd()
}
pub fn fd_out(&self) -> RawFd {
self.fd_out.as_raw_fd()
}
pub fn into_raw_fd_pair(self) -> (RawFd, RawFd) {
(self.fd_in.into_raw_fd(), self.fd_out.into_raw_fd())
}
pub fn set_ci_bitrate(&self, bitrate: u32) -> Result<()> {
if !matches!(self.vendor_id, Some(VENDOR_TBS)) {
return Ok(());
}
#[repr(C)]
struct DtvProperties {
num: u32,
props: *mut DtvPropertyRaw,
}
let mut props = [DtvPropertyRaw::new(MODULATOR_INPUT_BITRATE, bitrate)];
let cmd = DtvProperties {
num: props.len() as u32,
props: props.as_mut_ptr(),
};
nix::ioctl_write_ptr!(
#[inline]
ioctl_call,
b'o',
82,
DtvProperties
);
unsafe { ioctl_call(self.fd_in.as_raw_fd(), &cmd as *const _) }?;
Ok(())
}
}