mod apdu;
mod asn1;
mod capmt;
mod controller;
mod resource;
mod session;
mod spdu;
pub mod sys;
mod tpdu;
mod transport;
use std::{
fs::{
File,
OpenOptions,
},
io::{
ErrorKind,
Read,
Write,
},
os::{
fd::{
AsFd,
BorrowedFd,
},
unix::{
fs::OpenOptionsExt,
io::{
AsRawFd,
RawFd,
},
},
},
};
use self::sys::*;
pub use self::{
apdu::ApduTag,
controller::{
CaSlotFailure,
CaSlotStatus,
CamStatus,
CiController,
CiControllerConfig,
},
resource::{
ApplicationInfo,
MmiMenu,
ResourceId,
},
session::{
CaEvent,
CiSession,
},
tpdu::TpduTag,
transport::{
CiTransport,
TransportRecv,
},
};
use crate::{
error::{
Error,
Result,
},
sysfs,
};
#[derive(Debug)]
pub struct CaDevice {
adapter: u32,
device: u32,
file: File,
vendor_id: Option<u32>,
device_id: Option<u32>,
}
impl AsRawFd for CaDevice {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl AsFd for CaDevice {
fn as_fd(&self) -> BorrowedFd<'_> {
self.file.as_fd()
}
}
impl CaDevice {
pub fn open(adapter: u32, device: u32) -> Result<CaDevice> {
let path = format!("/dev/dvb/adapter{}/ca{}", adapter, device);
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(::nix::libc::O_NONBLOCK)
.open(&path)?;
let vendor_id = sysfs::read_hex_attr(&file, "vendor");
let device_id = sysfs::read_hex_attr(&file, "device");
Ok(CaDevice {
adapter,
device,
file,
vendor_id,
device_id,
})
}
pub fn adapter(&self) -> u32 {
self.adapter
}
pub fn device(&self) -> u32 {
self.device
}
pub fn vendor_id(&self) -> Option<u32> {
self.vendor_id
}
pub fn device_id(&self) -> Option<u32> {
self.device_id
}
pub fn caps(&self) -> Result<CaCaps> {
let mut caps = CaCaps::default();
unsafe { ca_get_cap(self.as_raw_fd(), &mut caps as *mut _) }?;
Ok(caps)
}
pub fn slot_info(&self, slot_id: u8) -> Result<CaSlotInfo> {
let mut slot_info = CaSlotInfo {
slot_num: u32::from(slot_id),
..CaSlotInfo::default()
};
unsafe { ca_get_slot_info(self.as_raw_fd(), &mut slot_info as *mut _) }?;
Ok(slot_info)
}
pub fn reset(&self) -> Result<()> {
unsafe { ca_reset(self.as_raw_fd()) }?;
Ok(())
}
pub fn send_msg(&self, msg: &[u8]) -> Result<()> {
let written = (&self.file).write(msg)?;
if written != msg.len() {
return Err(Error::InvalidData("ca link frame short write".to_owned()));
}
Ok(())
}
#[cfg(test)]
pub(crate) fn from_file(file: File) -> CaDevice {
CaDevice {
adapter: 0,
device: 0,
file,
vendor_id: None,
device_id: None,
}
}
pub fn recv_msg(&self, buf: &mut [u8]) -> Result<Option<usize>> {
match (&self.file).read(buf) {
Ok(0) => Err(Error::Io(std::io::Error::new(
ErrorKind::UnexpectedEof,
"ca device closed (zero-length read)",
))),
Ok(len) => Ok(Some(len)),
Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(None),
Err(e) => Err(Error::Io(e)),
}
}
}