mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat(tty): 将tty设备适配epoll,修改串口部分问题 (#968)
- tty文件适配epoll,使epoll能够监听tty - 修改串口handle_irq,原有每次只读取一个字节会导致:输入left(esc+[+A)被错误解析为(esc)+([)+(A)三个字符 - 为串口加上vcdata用于控制输入输出的格式问题(未解决,这个pr捎带)
This commit is contained in:
parent
40db1e61da
commit
c709f79fda
@ -19,12 +19,14 @@ use crate::{
|
||||
},
|
||||
serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort},
|
||||
tty::{
|
||||
console::ConsoleSwitch,
|
||||
kthread::send_to_tty_refresh_thread,
|
||||
termios::WindowSize,
|
||||
tty_core::{TtyCore, TtyCoreData},
|
||||
tty_driver::{TtyDriver, TtyDriverManager, TtyOperation},
|
||||
virtual_terminal::{vc_manager, VirtConsole},
|
||||
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, VirtConsole},
|
||||
},
|
||||
video::console::dummycon::dummy_console,
|
||||
},
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
@ -32,7 +34,7 @@ use crate::{
|
||||
manage::irq_manager,
|
||||
IrqNumber,
|
||||
},
|
||||
libs::rwlock::RwLock,
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
@ -265,9 +267,20 @@ impl UartPort for Serial8250PIOPort {
|
||||
}
|
||||
|
||||
fn handle_irq(&self) -> Result<(), SystemError> {
|
||||
let mut buf = [0; 8];
|
||||
let mut index = 0;
|
||||
|
||||
// Read up to the size of the buffer
|
||||
while index < buf.len() {
|
||||
if let Some(c) = self.read_one_byte() {
|
||||
send_to_tty_refresh_thread(&[c]);
|
||||
buf[index] = c;
|
||||
index += 1;
|
||||
} else {
|
||||
break; // No more bytes to read
|
||||
}
|
||||
}
|
||||
|
||||
send_to_tty_refresh_thread(&buf[0..index]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -385,7 +398,18 @@ impl TtyOperation for Serial8250PIOTtyDriverInner {
|
||||
if tty.core().index() >= unsafe { PIO_PORTS.len() } {
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
let vc = VirtConsole::new(None);
|
||||
|
||||
*tty.core().window_size_write() = WindowSize::DEFAULT;
|
||||
let vc_data = Arc::new(SpinLock::new(VirtualConsoleData::new(usize::MAX)));
|
||||
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||
vc_data_guard.set_driver_funcs(Arc::downgrade(&dummy_console()) as Weak<dyn ConsoleSwitch>);
|
||||
vc_data_guard.init(
|
||||
Some(tty.core().window_size().row.into()),
|
||||
Some(tty.core().window_size().col.into()),
|
||||
true,
|
||||
);
|
||||
drop(vc_data_guard);
|
||||
let vc = VirtConsole::new(Some(vc_data));
|
||||
let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
|
||||
self.do_install(driver, tty, vc.clone()).inspect_err(|_| {
|
||||
vc_manager().free(vc_index);
|
||||
|
@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType;
|
||||
|
||||
/// ## 窗口大小
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
pub struct WindowSize {
|
||||
/// 行
|
||||
pub row: u16,
|
||||
@ -26,12 +26,6 @@ impl WindowSize {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WindowSize {
|
||||
fn default() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Termios {
|
||||
pub input_mode: InputMode,
|
||||
|
@ -31,7 +31,7 @@ use super::{
|
||||
TtyLineDiscipline,
|
||||
},
|
||||
tty_port::TtyPort,
|
||||
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData},
|
||||
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, DrawRegion},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -489,6 +489,61 @@ impl TtyCoreData {
|
||||
pub fn add_epitem(&self, epitem: Arc<EPollItem>) {
|
||||
self.epitems.lock().push_back(epitem)
|
||||
}
|
||||
|
||||
pub fn eptiems(&self) -> &SpinLock<LinkedList<Arc<EPollItem>>> {
|
||||
&self.epitems
|
||||
}
|
||||
|
||||
pub fn do_write(&self, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
|
||||
// 关闭中断
|
||||
if let Some(vc_data) = self.vc_data() {
|
||||
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||
let mut offset = 0;
|
||||
|
||||
// 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
|
||||
let mut rescan = false;
|
||||
let mut ch: u32 = 0;
|
||||
|
||||
let mut draw = DrawRegion::default();
|
||||
|
||||
// 首先隐藏光标再写
|
||||
vc_data_guard.hide_cursor();
|
||||
|
||||
while nr != 0 {
|
||||
if !rescan {
|
||||
ch = buf[offset] as u32;
|
||||
offset += 1;
|
||||
nr -= 1;
|
||||
}
|
||||
|
||||
let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
|
||||
if tc.is_none() {
|
||||
// 表示未转换完成
|
||||
continue;
|
||||
}
|
||||
|
||||
let tc = tc.unwrap();
|
||||
rescan = rescan_last;
|
||||
|
||||
if vc_data_guard.is_control(tc, ch) {
|
||||
vc_data_guard.flush(&mut draw);
|
||||
vc_data_guard.do_control(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
vc_data_guard.flush(&mut draw);
|
||||
|
||||
// TODO: notify update
|
||||
return Ok(offset);
|
||||
} else {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TtyOperation for TtyCore {
|
||||
|
@ -4,7 +4,10 @@ use alloc::sync::{Arc, Weak};
|
||||
use kdepends::thingbuf::mpsc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||
use crate::{
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
net::event_poll::EventPoll,
|
||||
};
|
||||
|
||||
use super::tty_core::TtyCore;
|
||||
|
||||
@ -85,6 +88,8 @@ pub trait TtyPort: Sync + Send + Debug {
|
||||
return ld.receive_buf(tty, buf, None, count);
|
||||
}
|
||||
|
||||
EventPoll::wakeup_epoll(tty.core().eptiems(), None)?;
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -300,55 +300,6 @@ impl TtyConsoleDriverInner {
|
||||
Ok(Self { console })
|
||||
}
|
||||
|
||||
fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
|
||||
// 关闭中断
|
||||
let vc_data = tty.vc_data().unwrap();
|
||||
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||
|
||||
let mut offset = 0;
|
||||
|
||||
// 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
|
||||
let mut rescan = false;
|
||||
let mut ch: u32 = 0;
|
||||
|
||||
let mut draw = DrawRegion::default();
|
||||
|
||||
// 首先隐藏光标再写
|
||||
vc_data_guard.hide_cursor();
|
||||
|
||||
while nr != 0 {
|
||||
if !rescan {
|
||||
ch = buf[offset] as u32;
|
||||
offset += 1;
|
||||
nr -= 1;
|
||||
}
|
||||
|
||||
let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
|
||||
if tc.is_none() {
|
||||
// 表示未转换完成
|
||||
continue;
|
||||
}
|
||||
|
||||
let tc = tc.unwrap();
|
||||
rescan = rescan_last;
|
||||
|
||||
if vc_data_guard.is_control(tc, ch) {
|
||||
vc_data_guard.flush(&mut draw);
|
||||
vc_data_guard.do_control(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
vc_data_guard.flush(&mut draw);
|
||||
|
||||
// TODO: notify update
|
||||
return Ok(offset);
|
||||
}
|
||||
|
||||
fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
|
||||
let tty_core = tty.core();
|
||||
|
||||
@ -426,7 +377,7 @@ impl TtyOperation for TtyConsoleDriverInner {
|
||||
// loop {}
|
||||
// }
|
||||
send_to_default_serial8250_port(buf);
|
||||
let ret = self.do_write(tty, buf, nr);
|
||||
let ret = tty.do_write(buf, nr);
|
||||
self.flush_chars(tty);
|
||||
ret
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ impl VirtualConsoleData {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
|
||||
pub fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
|
||||
if let Some(rows) = rows {
|
||||
self.rows = rows;
|
||||
}
|
||||
@ -242,7 +242,7 @@ impl VirtualConsoleData {
|
||||
self.driver_funcs.as_ref().unwrap().upgrade().unwrap()
|
||||
}
|
||||
|
||||
pub(super) fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) {
|
||||
pub fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) {
|
||||
self.driver_funcs = Some(func);
|
||||
}
|
||||
|
||||
@ -312,7 +312,7 @@ impl VirtualConsoleData {
|
||||
///
|
||||
/// ### 返回值
|
||||
/// ### (转换后的字符:i32,是否需要更多的数据才能进行转换:bool)
|
||||
pub(super) fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) {
|
||||
pub fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) {
|
||||
if self.vc_state != VirtualConsoleState::ESnormal {
|
||||
// 在控制字符状态下不需要翻译
|
||||
return (Some(*c), false);
|
||||
@ -440,7 +440,7 @@ impl VirtualConsoleData {
|
||||
const CTRL_ALWAYS: u32 = 0x0800f501;
|
||||
|
||||
/// ## 用于判断tc(终端字符)在当前VC下是不是需要显示的控制字符
|
||||
pub(super) fn is_control(&self, tc: u32, c: u32) -> bool {
|
||||
pub fn is_control(&self, tc: u32, c: u32) -> bool {
|
||||
// 当前vc状态机不在正常状态,即在接收特殊字符的状态,则是控制字符
|
||||
if self.vc_state != VirtualConsoleState::ESnormal {
|
||||
return true;
|
||||
@ -1257,7 +1257,7 @@ impl VirtualConsoleData {
|
||||
|
||||
/// ## 处理终端控制字符
|
||||
#[inline(never)]
|
||||
pub(super) fn do_control(&mut self, ch: u32) {
|
||||
pub fn do_control(&mut self, ch: u32) {
|
||||
// 首先检查是否处于 ANSI 控制字符串状态
|
||||
if self.vc_state.is_ansi_control_string() && (8..=13).contains(&ch) {
|
||||
return;
|
||||
@ -1534,12 +1534,7 @@ impl VirtualConsoleData {
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub(super) fn console_write_normal(
|
||||
&mut self,
|
||||
mut tc: u32,
|
||||
c: u32,
|
||||
draw: &mut DrawRegion,
|
||||
) -> bool {
|
||||
pub fn console_write_normal(&mut self, mut tc: u32, c: u32, draw: &mut DrawRegion) -> bool {
|
||||
let mut attr = self.attr;
|
||||
let himask = self.hi_font_mask;
|
||||
let charmask = if himask == 0 { 0xff } else { 0x1ff };
|
||||
@ -1753,7 +1748,7 @@ impl VirtualConsoleData {
|
||||
return (self.attr & 0x88) | ((self.attr & 0x70) >> 4) | ((self.attr & 0x07) << 4);
|
||||
}
|
||||
|
||||
pub(super) fn flush(&self, draw: &mut DrawRegion) {
|
||||
pub fn flush(&self, draw: &mut DrawRegion) {
|
||||
if draw.x.is_none() {
|
||||
return;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ impl IndexNode for EventFdInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
|
||||
|
||||
return Ok(8);
|
||||
}
|
||||
@ -184,7 +184,7 @@ impl IndexNode for EventFdInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
|
||||
return Ok(8);
|
||||
}
|
||||
|
||||
|
@ -399,6 +399,15 @@ impl IndexNode for MountFSInode {
|
||||
return self.inner_inode.ioctl(cmd, data, private_data);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn kernel_ioctl(
|
||||
&self,
|
||||
arg: Arc<dyn crate::net::event_poll::KernelIoctlData>,
|
||||
data: &FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
return self.inner_inode.kernel_ioctl(arg, data);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
|
||||
return self.inner_inode.list();
|
||||
|
@ -267,7 +267,7 @@ impl IndexNode for LockedPipeInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&inode.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
|
||||
|
||||
//返回读取的字节数
|
||||
return Ok(num);
|
||||
@ -413,7 +413,7 @@ impl IndexNode for LockedPipeInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&inode.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
|
||||
|
||||
// 返回写入的字节数
|
||||
return Ok(len);
|
||||
|
@ -716,12 +716,20 @@ impl EventPoll {
|
||||
/// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可
|
||||
pub fn wakeup_epoll(
|
||||
epitems: &SpinLock<LinkedList<Arc<EPollItem>>>,
|
||||
pollflags: EPollEventType,
|
||||
pollflags: Option<EPollEventType>,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut epitems_guard = epitems.try_lock_irqsave()?;
|
||||
// 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓
|
||||
if let Some(epitem) = epitems_guard.pop_front() {
|
||||
let epoll = epitem.epoll().upgrade().unwrap();
|
||||
let pollflags = pollflags.unwrap_or({
|
||||
if let Some(file) = epitem.file.upgrade() {
|
||||
EPollEventType::from_bits_truncate(file.poll()? as u32)
|
||||
} else {
|
||||
EPollEventType::empty()
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(epoll) = epitem.epoll().upgrade() {
|
||||
let mut epoll_guard = epoll.try_lock()?;
|
||||
let binding = epitem.clone();
|
||||
let event_guard = binding.event().read();
|
||||
@ -752,6 +760,7 @@ impl EventPoll {
|
||||
|
||||
epitems_guard.push_back(epitem);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ fn send_event(sockets: &smoltcp::iface::SocketSet) -> Result<(), SystemError> {
|
||||
}
|
||||
EventPoll::wakeup_epoll(
|
||||
&posix_item.epitems,
|
||||
EPollEventType::from_bits_truncate(events as u32),
|
||||
Some(EPollEventType::from_bits_truncate(events as u32)),
|
||||
)?;
|
||||
drop(handle_guard);
|
||||
// crate::debug!(
|
||||
|
Loading…
x
Reference in New Issue
Block a user