use std::os::unix::io::RawFd; use bitflags::bitflags; use nix::libc; use crate::Result; // These are wrapped in a module because they're `pub` by default mod raw { use nix::libc; use nix::{ioctl_none_bad, ioctl_read, ioctl_read_bad, ioctl_write_ptr, ioctl_write_ptr_bad}; ioctl_none_bad!(tiocexcl, libc::TIOCEXCL); ioctl_none_bad!(tiocnxcl, libc::TIOCNXCL); ioctl_read_bad!(tiocmget, libc::TIOCMGET, libc::c_int); ioctl_none_bad!(tiocsbrk, libc::TIOCSBRK); ioctl_none_bad!(tioccbrk, libc::TIOCCBRK); #[cfg(any(target_os = "android", target_os = "linux"))] ioctl_read_bad!(fionread, libc::FIONREAD, libc::c_int); // See: /usr/include/sys/filio.h #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd" ))] ioctl_read!(fionread, b'f', 127, libc::c_int); #[cfg(any(target_os = "android", target_os = "linux"))] ioctl_read_bad!(tiocoutq, libc::TIOCOUTQ, libc::c_int); // See: /usr/include/sys/ttycom.h #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd" ))] ioctl_read!(tiocoutq, b't', 115, libc::c_int); ioctl_write_ptr_bad!(tiocmbic, libc::TIOCMBIC, libc::c_int); ioctl_write_ptr_bad!(tiocmbis, libc::TIOCMBIS, libc::c_int); ioctl_read!( #[cfg(any( target_os = "android", all( target_os = "linux", not(any( target_env = "musl", target_arch = "powerpc", target_arch = "powerpc64" )) ) ))] tcgets2, b'T', 0x2A, libc::termios2 ); ioctl_write_ptr!( #[cfg(any( target_os = "android", all( target_os = "linux", not(any( target_env = "musl", target_arch = "powerpc", target_arch = "powerpc64" )) ) ))] tcsets2, b'T', 0x2B, libc::termios2 ); #[cfg(any(target_os = "ios", target_os = "macos"))] const IOSSIOSPEED: libc::c_ulong = 0x80045402; ioctl_write_ptr_bad!( #[cfg(any(target_os = "ios", target_os = "macos"))] iossiospeed, IOSSIOSPEED, libc::speed_t ); } bitflags! { /// Flags to indicate which wires in a serial connection to use pub struct SerialLines: libc::c_int { const DATA_SET_READY = libc::TIOCM_DSR; const DATA_TERMINAL_READY = libc::TIOCM_DTR; const REQUEST_TO_SEND = libc::TIOCM_RTS; const SECONDARY_TRANSMIT = libc::TIOCM_ST; const SECONDARY_RECEIVE = libc::TIOCM_SR; const CLEAR_TO_SEND = libc::TIOCM_CTS; const DATA_CARRIER_DETECT = libc::TIOCM_CAR; const RING = libc::TIOCM_RNG; } } pub fn tiocexcl(fd: RawFd) -> Result<()> { unsafe { raw::tiocexcl(fd) } .map(|_| ()) .map_err(|e| e.into()) } pub fn tiocnxcl(fd: RawFd) -> Result<()> { unsafe { raw::tiocnxcl(fd) } .map(|_| ()) .map_err(|e| e.into()) } pub fn tiocmget(fd: RawFd) -> Result { let mut status: libc::c_int = 0; unsafe { raw::tiocmget(fd, &mut status) } .map(|_| SerialLines::from_bits_truncate(status)) .map_err(|e| e.into()) } pub fn tiocsbrk(fd: RawFd) -> Result<()> { unsafe { raw::tiocsbrk(fd) } .map(|_| ()) .map_err(|e| e.into()) } pub fn tioccbrk(fd: RawFd) -> Result<()> { unsafe { raw::tioccbrk(fd) } .map(|_| ()) .map_err(|e| e.into()) } pub fn fionread(fd: RawFd) -> Result { let mut retval: libc::c_int = 0; unsafe { raw::fionread(fd, &mut retval) } .map(|_| retval as u32) .map_err(|e| e.into()) } pub fn tiocoutq(fd: RawFd) -> Result { let mut retval: libc::c_int = 0; unsafe { raw::tiocoutq(fd, &mut retval) } .map(|_| retval as u32) .map_err(|e| e.into()) } pub fn tiocmbic(fd: RawFd, status: SerialLines) -> Result<()> { let bits = status.bits() as libc::c_int; unsafe { raw::tiocmbic(fd, &bits) } .map(|_| ()) .map_err(|e| e.into()) } pub fn tiocmbis(fd: RawFd, status: SerialLines) -> Result<()> { let bits = status.bits() as libc::c_int; unsafe { raw::tiocmbis(fd, &bits) } .map(|_| ()) .map_err(|e| e.into()) } #[cfg(any( target_os = "android", all( target_os = "linux", not(any( target_env = "musl", target_arch = "powerpc", target_arch = "powerpc64" )) ) ))] pub fn tcgets2(fd: RawFd) -> Result { let mut options = std::mem::MaybeUninit::uninit(); match unsafe { raw::tcgets2(fd, options.as_mut_ptr()) } { Ok(_) => unsafe { Ok(options.assume_init()) }, Err(e) => Err(e.into()), } } #[cfg(any( target_os = "android", all( target_os = "linux", not(any( target_env = "musl", target_arch = "powerpc", target_arch = "powerpc64" )) ) ))] pub fn tcsets2(fd: RawFd, options: &libc::termios2) -> Result<()> { unsafe { raw::tcsets2(fd, options) } .map(|_| ()) .map_err(|e| e.into()) } #[cfg(any(target_os = "ios", target_os = "macos"))] pub fn iossiospeed(fd: RawFd, baud_rate: &libc::speed_t) -> Result<()> { unsafe { raw::iossiospeed(fd, baud_rate) } .map(|_| ()) .map_err(|e| e.into()) }