1 use core::{ 2 fmt::Debug, 3 sync::atomic::{AtomicBool, AtomicUsize, Ordering}, 4 }; 5 6 use alloc::{ 7 collections::LinkedList, 8 string::String, 9 sync::{Arc, Weak}, 10 vec::Vec, 11 }; 12 use system_error::SystemError; 13 14 use crate::{ 15 driver::{serial::serial8250::send_to_default_serial8250_port, tty::pty::ptm_driver}, 16 libs::{ 17 rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard}, 18 spinlock::{SpinLock, SpinLockGuard}, 19 wait_queue::EventWaitQueue, 20 }, 21 mm::VirtAddr, 22 net::event_poll::{EPollEventType, EPollItem}, 23 process::Pid, 24 syscall::user_access::{UserBufferReader, UserBufferWriter}, 25 }; 26 27 use super::{ 28 termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize}, 29 tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation}, 30 tty_ldisc::{ 31 ntty::{NTtyData, NTtyLinediscipline}, 32 TtyLineDiscipline, 33 }, 34 tty_port::TtyPort, 35 virtual_terminal::{virtual_console::VirtualConsoleData, VIRT_CONSOLES}, 36 }; 37 38 #[derive(Debug)] 39 pub struct TtyCore { 40 core: TtyCoreData, 41 /// 线路规程函数集 42 line_discipline: Arc<dyn TtyLineDiscipline>, 43 } 44 45 impl Drop for TtyCore { 46 fn drop(&mut self) { 47 if self.core.driver().tty_driver_sub_type() == TtyDriverSubType::PtySlave { 48 ptm_driver().ttys().remove(&self.core().index); 49 } 50 } 51 } 52 53 impl TtyCore { 54 pub fn new(driver: Arc<TtyDriver>, index: usize) -> Arc<Self> { 55 let name = driver.tty_line_name(index); 56 let termios = driver.init_termios(); 57 let core = TtyCoreData { 58 tty_driver: driver, 59 termios: RwLock::new(termios), 60 name, 61 flags: RwLock::new(TtyFlag::empty()), 62 count: AtomicUsize::new(0), 63 window_size: RwLock::new(WindowSize::default()), 64 read_wq: EventWaitQueue::new(), 65 write_wq: EventWaitQueue::new(), 66 port: RwLock::new(None), 67 index, 68 ctrl: SpinLock::new(TtyContorlInfo::default()), 69 closing: AtomicBool::new(false), 70 flow: SpinLock::new(TtyFlowState::default()), 71 link: RwLock::default(), 72 epitems: SpinLock::new(LinkedList::new()), 73 }; 74 75 return Arc::new(Self { 76 core, 77 line_discipline: Arc::new(NTtyLinediscipline { 78 data: SpinLock::new(NTtyData::new()), 79 }), 80 }); 81 } 82 83 #[inline] 84 pub fn core(&self) -> &TtyCoreData { 85 return &self.core; 86 } 87 88 #[inline] 89 pub fn ldisc(&self) -> Arc<dyn TtyLineDiscipline> { 90 self.line_discipline.clone() 91 } 92 93 pub fn write_without_serial(&self, buf: &[u8], nr: usize) -> Result<usize, SystemError> { 94 self.core 95 .driver() 96 .driver_funcs() 97 .write(self.core(), buf, nr) 98 } 99 100 pub fn reopen(&self) -> Result<(), SystemError> { 101 let tty_core = self.core(); 102 let driver = tty_core.driver(); 103 104 if driver.tty_driver_type() == TtyDriverType::Pty 105 && driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster 106 { 107 return Err(SystemError::EIO); 108 } 109 110 // if *tty_core.count.read() == 0 { 111 // return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); 112 // } 113 114 // TODO 判断flags 115 116 tty_core.add_count(); 117 118 Ok(()) 119 } 120 121 #[inline] 122 pub fn set_port(&self, port: Arc<dyn TtyPort>) { 123 *self.core.port.write() = Some(port); 124 } 125 126 pub fn tty_start(&self) { 127 let mut flow = self.core.flow.lock_irqsave(); 128 if !flow.stopped || flow.tco_stopped { 129 return; 130 } 131 132 flow.stopped = false; 133 let _ = self.start(self.core()); 134 self.tty_wakeup(); 135 } 136 137 pub fn tty_stop(&self) { 138 let mut flow = self.core.flow.lock_irqsave(); 139 if flow.stopped { 140 return; 141 } 142 flow.stopped = true; 143 144 let _ = self.stop(self.core()); 145 } 146 147 pub fn tty_wakeup(&self) { 148 if self.core.flags().contains(TtyFlag::DO_WRITE_WAKEUP) { 149 let _ = self.ldisc().write_wakeup(self.core()); 150 } 151 152 self.core() 153 .write_wq 154 .wakeup_any(EPollEventType::EPOLLOUT.bits() as u64); 155 } 156 157 pub fn tty_mode_ioctl(tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<usize, SystemError> { 158 let core = tty.core(); 159 let real_tty = if core.driver().tty_driver_type() == TtyDriverType::Pty 160 && core.driver().tty_driver_sub_type() == TtyDriverSubType::PtyMaster 161 { 162 core.link().unwrap() 163 } else { 164 tty 165 }; 166 match cmd { 167 TtyIoctlCmd::TCGETS => { 168 let termios = PosixTermios::from_kernel_termios(*real_tty.core.termios()); 169 let mut user_writer = UserBufferWriter::new( 170 VirtAddr::new(arg).as_ptr::<PosixTermios>(), 171 core::mem::size_of::<PosixTermios>(), 172 true, 173 )?; 174 175 user_writer.copy_one_to_user(&termios, 0)?; 176 return Ok(0); 177 } 178 TtyIoctlCmd::TCSETS => { 179 return TtyCore::core_set_termios( 180 real_tty, 181 VirtAddr::new(arg), 182 TtySetTermiosOpt::TERMIOS_OLD, 183 ); 184 } 185 TtyIoctlCmd::TCSETSW => { 186 return TtyCore::core_set_termios( 187 real_tty, 188 VirtAddr::new(arg), 189 TtySetTermiosOpt::TERMIOS_WAIT | TtySetTermiosOpt::TERMIOS_OLD, 190 ); 191 } 192 _ => { 193 return Err(SystemError::ENOIOCTLCMD); 194 } 195 } 196 } 197 198 pub fn core_set_termios( 199 tty: Arc<TtyCore>, 200 arg: VirtAddr, 201 opt: TtySetTermiosOpt, 202 ) -> Result<usize, SystemError> { 203 #[allow(unused_assignments)] 204 // TERMIOS_TERMIO下会用到 205 let mut tmp_termios = *tty.core().termios(); 206 207 if opt.contains(TtySetTermiosOpt::TERMIOS_TERMIO) { 208 todo!() 209 } else { 210 let user_reader = UserBufferReader::new( 211 arg.as_ptr::<PosixTermios>(), 212 core::mem::size_of::<PosixTermios>(), 213 true, 214 )?; 215 216 let mut term = PosixTermios::default(); 217 user_reader.copy_one_from_user(&mut term, 0)?; 218 219 tmp_termios = term.to_kernel_termios(); 220 } 221 222 if opt.contains(TtySetTermiosOpt::TERMIOS_FLUSH) { 223 let ld = tty.ldisc(); 224 let _ = ld.flush_buffer(tty.clone()); 225 } 226 227 if opt.contains(TtySetTermiosOpt::TERMIOS_WAIT) { 228 // TODO 229 } 230 231 TtyCore::set_termios_next(tty, tmp_termios)?; 232 Ok(0) 233 } 234 235 pub fn set_termios_next(tty: Arc<TtyCore>, new_termios: Termios) -> Result<(), SystemError> { 236 let mut termios = tty.core().termios_write(); 237 238 let old_termios = *termios; 239 *termios = new_termios; 240 let tmp = termios.control_mode; 241 termios.control_mode ^= (tmp ^ old_termios.control_mode) & ControlMode::ADDRB; 242 243 drop(termios); 244 let ret = tty.set_termios(tty.clone(), old_termios); 245 let mut termios = tty.core().termios_write(); 246 if ret.is_err() { 247 termios.control_mode &= ControlMode::HUPCL | ControlMode::CREAD | ControlMode::CLOCAL; 248 termios.control_mode |= old_termios.control_mode 249 & !(ControlMode::HUPCL | ControlMode::CREAD | ControlMode::CLOCAL); 250 termios.input_speed = old_termios.input_speed; 251 termios.output_speed = old_termios.output_speed; 252 } 253 254 drop(termios); 255 let ld = tty.ldisc(); 256 ld.set_termios(tty, Some(old_termios))?; 257 258 Ok(()) 259 } 260 261 pub fn tty_do_resize(&self, windowsize: WindowSize) -> Result<(), SystemError> { 262 // TODO: 向前台进程发送信号 263 *self.core.window_size_write() = windowsize; 264 Ok(()) 265 } 266 } 267 268 #[derive(Debug, Default)] 269 pub struct TtyContorlInfo { 270 /// 前台进程pid 271 pub session: Option<Pid>, 272 /// 前台进程组id 273 pub pgid: Option<Pid>, 274 275 /// packet模式下使用,目前未用到 276 pub pktstatus: TtyPacketStatus, 277 pub packet: bool, 278 } 279 280 #[derive(Debug, Default)] 281 pub struct TtyCoreWriteData { 282 /// 写缓冲区 283 pub write_buf: Vec<u8>, 284 /// 写入数量 285 pub write_cnt: usize, 286 } 287 288 #[derive(Debug, Default)] 289 pub struct TtyFlowState { 290 /// 表示流控是否被停止 291 pub stopped: bool, 292 /// 表示 TCO(Transmit Continuous Operation)流控是否被停止 293 pub tco_stopped: bool, 294 } 295 296 #[derive(Debug)] 297 pub struct TtyCoreData { 298 tty_driver: Arc<TtyDriver>, 299 termios: RwLock<Termios>, 300 name: String, 301 flags: RwLock<TtyFlag>, 302 /// 在初始化时即确定不会更改,所以这里不用加锁 303 index: usize, 304 count: AtomicUsize, 305 /// 窗口大小 306 window_size: RwLock<WindowSize>, 307 /// 读等待队列 308 read_wq: EventWaitQueue, 309 /// 写等待队列 310 write_wq: EventWaitQueue, 311 /// 端口 312 port: RwLock<Option<Arc<dyn TtyPort>>>, 313 /// 前台进程 314 ctrl: SpinLock<TtyContorlInfo>, 315 /// 是否正在关闭 316 closing: AtomicBool, 317 /// 流控状态 318 flow: SpinLock<TtyFlowState>, 319 /// 链接tty 320 link: RwLock<Weak<TtyCore>>, 321 /// epitems 322 epitems: SpinLock<LinkedList<Arc<EPollItem>>>, 323 } 324 325 impl TtyCoreData { 326 #[inline] 327 pub fn driver(&self) -> Arc<TtyDriver> { 328 self.tty_driver.clone() 329 } 330 331 #[inline] 332 pub fn flow_irqsave(&self) -> SpinLockGuard<TtyFlowState> { 333 self.flow.lock_irqsave() 334 } 335 336 #[inline] 337 pub fn port(&self) -> Option<Arc<dyn TtyPort>> { 338 self.port.read().clone() 339 } 340 341 #[inline] 342 pub fn index(&self) -> usize { 343 self.index 344 } 345 346 #[inline] 347 pub fn name(&self) -> String { 348 self.name.clone() 349 } 350 351 #[inline] 352 pub fn flags(&self) -> TtyFlag { 353 *self.flags.read_irqsave() 354 } 355 356 #[inline] 357 pub fn flags_write(&self) -> RwLockWriteGuard<'_, TtyFlag> { 358 self.flags.write_irqsave() 359 } 360 361 #[inline] 362 pub fn termios(&self) -> RwLockReadGuard<'_, Termios> { 363 self.termios.read_irqsave() 364 } 365 366 #[inline] 367 pub fn termios_write(&self) -> RwLockWriteGuard<Termios> { 368 self.termios.write_irqsave() 369 } 370 371 #[inline] 372 pub fn set_termios(&self, termios: Termios) { 373 let mut termios_guard = self.termios_write(); 374 *termios_guard = termios; 375 } 376 377 #[inline] 378 pub fn count(&self) -> usize { 379 self.count.load(Ordering::SeqCst) 380 } 381 382 #[inline] 383 pub fn add_count(&self) { 384 self.count 385 .fetch_add(1, core::sync::atomic::Ordering::SeqCst); 386 } 387 388 #[inline] 389 pub fn read_wq(&self) -> &EventWaitQueue { 390 &self.read_wq 391 } 392 393 #[inline] 394 pub fn write_wq(&self) -> &EventWaitQueue { 395 &self.write_wq 396 } 397 398 #[inline] 399 pub fn contorl_info_irqsave(&self) -> SpinLockGuard<TtyContorlInfo> { 400 self.ctrl.lock_irqsave() 401 } 402 403 #[inline] 404 pub fn window_size_upgradeable(&self) -> RwLockUpgradableGuard<WindowSize> { 405 self.window_size.upgradeable_read() 406 } 407 408 #[inline] 409 pub fn window_size(&self) -> RwLockReadGuard<WindowSize> { 410 self.window_size.read() 411 } 412 413 #[inline] 414 pub fn window_size_write(&self) -> RwLockWriteGuard<WindowSize> { 415 self.window_size.write() 416 } 417 418 #[inline] 419 pub fn is_closing(&self) -> bool { 420 self.closing.load(core::sync::atomic::Ordering::SeqCst) 421 } 422 423 #[inline] 424 pub fn vc_data_irqsave(&self) -> SpinLockGuard<VirtualConsoleData> { 425 VIRT_CONSOLES[self.index].lock_irqsave() 426 } 427 428 #[inline] 429 pub fn link(&self) -> Option<Arc<TtyCore>> { 430 self.link.read().upgrade() 431 } 432 433 pub fn checked_link(&self) -> Result<Arc<TtyCore>, SystemError> { 434 if let Some(link) = self.link() { 435 return Ok(link); 436 } 437 return Err(SystemError::ENODEV); 438 } 439 440 pub fn set_link(&self, link: Weak<TtyCore>) { 441 *self.link.write() = link; 442 } 443 444 pub fn init_termios(&self) { 445 let tty_index = self.index(); 446 let driver = self.driver(); 447 // 初始化termios 448 if !driver 449 .flags() 450 .contains(super::tty_driver::TtyDriverFlag::TTY_DRIVER_RESET_TERMIOS) 451 { 452 // 先查看是否有已经保存的termios 453 if let Some(t) = driver.saved_termios().get(tty_index) { 454 let mut termios = *t; 455 termios.line = driver.init_termios().line; 456 self.set_termios(termios); 457 } 458 } 459 // TODO:设置termios波特率? 460 } 461 462 #[inline] 463 pub fn add_epitem(&self, epitem: Arc<EPollItem>) { 464 self.epitems.lock().push_back(epitem) 465 } 466 } 467 468 /// TTY 核心接口,不同的tty需要各自实现这个trait 469 pub trait TtyCoreFuncs: Debug + Send + Sync {} 470 471 impl TtyOperation for TtyCore { 472 #[inline] 473 fn open(&self, tty: &TtyCoreData) -> Result<(), SystemError> { 474 return self.core().tty_driver.driver_funcs().open(tty); 475 } 476 477 #[inline] 478 fn write_room(&self, tty: &TtyCoreData) -> usize { 479 return self.core().tty_driver.driver_funcs().write_room(tty); 480 } 481 482 #[inline] 483 fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> { 484 send_to_default_serial8250_port(buf); 485 return self.core().tty_driver.driver_funcs().write(tty, buf, nr); 486 } 487 488 #[inline] 489 fn flush_chars(&self, tty: &TtyCoreData) { 490 self.core().tty_driver.driver_funcs().flush_chars(tty); 491 } 492 493 #[inline] 494 fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { 495 return self.core().tty_driver.driver_funcs().put_char(tty, ch); 496 } 497 498 #[inline] 499 fn install(&self, driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> { 500 return self.core().tty_driver.driver_funcs().install(driver, tty); 501 } 502 503 #[inline] 504 fn start(&self, tty: &TtyCoreData) -> Result<(), SystemError> { 505 return self.core().tty_driver.driver_funcs().start(tty); 506 } 507 508 #[inline] 509 fn stop(&self, tty: &TtyCoreData) -> Result<(), SystemError> { 510 return self.core().tty_driver.driver_funcs().stop(tty); 511 } 512 513 #[inline] 514 fn ioctl(&self, tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<(), SystemError> { 515 return self.core().tty_driver.driver_funcs().ioctl(tty, cmd, arg); 516 } 517 518 #[inline] 519 fn chars_in_buffer(&self) -> usize { 520 return self.core().tty_driver.driver_funcs().chars_in_buffer(); 521 } 522 523 #[inline] 524 fn set_termios(&self, tty: Arc<TtyCore>, old_termios: Termios) -> Result<(), SystemError> { 525 return self 526 .core() 527 .tty_driver 528 .driver_funcs() 529 .set_termios(tty, old_termios); 530 } 531 532 fn close(&self, tty: Arc<TtyCore>) -> Result<(), SystemError> { 533 self.core().tty_driver.driver_funcs().close(tty) 534 } 535 536 fn resize(&self, tty: Arc<TtyCore>, winsize: WindowSize) -> Result<(), SystemError> { 537 self.core.tty_driver.driver_funcs().resize(tty, winsize) 538 } 539 } 540 541 bitflags! { 542 pub struct TtyFlag: u32 { 543 /// 终端被节流 544 const THROTTLED = 1 << 0; 545 /// 终端输入输出错误状态 546 const IO_ERROR = 1 << 1; 547 /// 终端的其他一方已关闭 548 const OTHER_CLOSED = 1 << 2; 549 /// 终端处于独占状态 550 const EXCLUSIVE = 1 << 3; 551 /// 终端执行写唤醒操作 552 const DO_WRITE_WAKEUP = 1 << 5; 553 /// 终端线路驱动程序已打开 554 const LDISC_OPEN = 1 << 11; 555 /// 终端伪终端设备已锁定 556 const PTY_LOCK = 1 << 16; 557 /// 终端禁用写分裂操作 558 const NO_WRITE_SPLIT = 1 << 17; 559 /// 终端挂断(挂起)状态 560 const HUPPED = 1 << 18; 561 /// 终端正在挂断(挂起) 562 const HUPPING = 1 << 19; 563 /// 终端线路驱动程序正在更改 564 const LDISC_CHANGING = 1 << 20; 565 /// 终端线路驱动程序已停止 566 const LDISC_HALTED = 1 << 22; 567 } 568 569 #[derive(Default)] 570 pub struct TtyPacketStatus: u8 { 571 /* Used for packet mode */ 572 const TIOCPKT_DATA = 0; 573 const TIOCPKT_FLUSHREAD = 1; 574 const TIOCPKT_FLUSHWRITE = 2; 575 const TIOCPKT_STOP = 4; 576 const TIOCPKT_START = 8; 577 const TIOCPKT_NOSTOP = 16; 578 const TIOCPKT_DOSTOP = 32; 579 const TIOCPKT_IOCTL = 64; 580 } 581 } 582 583 #[derive(Debug, PartialEq)] 584 pub enum EchoOperation { 585 /// 开始特殊操作。 586 Start, 587 /// 向后移动光标列。 588 MoveBackCol, 589 /// 设置规范模式下的列位置。 590 SetCanonCol, 591 /// 擦除制表符。 592 EraseTab, 593 594 Undefined(u8), 595 } 596 597 impl EchoOperation { 598 pub fn from_u8(num: u8) -> EchoOperation { 599 match num { 600 0xff => Self::Start, 601 0x80 => Self::MoveBackCol, 602 0x81 => Self::SetCanonCol, 603 0x82 => Self::EraseTab, 604 _ => Self::Undefined(num), 605 } 606 } 607 608 pub fn to_u8(&self) -> u8 { 609 match *self { 610 EchoOperation::Start => 0xff, 611 EchoOperation::MoveBackCol => 0x80, 612 EchoOperation::SetCanonCol => 0x81, 613 EchoOperation::EraseTab => 0x82, 614 EchoOperation::Undefined(num) => num, 615 } 616 } 617 } 618 619 pub struct TtyIoctlCmd; 620 621 #[allow(dead_code)] 622 impl TtyIoctlCmd { 623 /// 获取终端参数 624 pub const TCGETS: u32 = 0x5401; 625 /// 设置终端参数 626 pub const TCSETS: u32 = 0x5402; 627 /// 设置终端参数并等待所有输出完成 628 pub const TCSETSW: u32 = 0x5403; 629 /// 设置终端参数并且等待所有输出完成,但在这之前将终端清空 630 pub const TCSETSF: u32 = 0x5404; 631 /// 获取终端参数 632 pub const TCGETA: u32 = 0x5405; 633 /// 设置终端参数 634 pub const TCSETA: u32 = 0x5406; 635 /// 设置终端参数并等待所有输出完成 636 pub const TCSETAW: u32 = 0x5407; 637 /// 设置终端参数并且等待所有输出完成,但在这之前将终端清空 638 pub const TCSETAF: u32 = 0x5408; 639 /// 发送零字节,等待所有输出完成 640 pub const TCSBRK: u32 = 0x5409; 641 /// 控制终端的流控 642 pub const TCXONC: u32 = 0x540A; 643 /// 刷新输入/输出缓冲区或者丢弃输入缓冲区 644 pub const TCFLSH: u32 = 0x540B; 645 /// 设置设备为独占模式 646 pub const TIOCEXCL: u32 = 0x540C; 647 /// 设置设备为非独占模式 648 pub const TIOCNXCL: u32 = 0x540D; 649 /// 设置当前进程的控制终端 650 pub const TIOCSCTTY: u32 = 0x540E; 651 /// 获取前台进程组 652 pub const TIOCGPGRP: u32 = 0x540F; 653 ///设置前台进程组 654 pub const TIOCSPGRP: u32 = 0x5410; 655 /// 获取输出队列的字节数 656 pub const TIOCOUTQ: u32 = 0x5411; 657 /// 模拟从终端输入字符 658 pub const TIOCSTI: u32 = 0x5412; 659 /// 获取窗口大小 660 pub const TIOCGWINSZ: u32 = 0x5413; 661 /// 设置窗口大小 662 pub const TIOCSWINSZ: u32 = 0x5414; 663 /// 获取终端控制信号的状态 664 pub const TIOCMGET: u32 = 0x5415; 665 /// 设置终端控制信号的位 666 pub const TIOCMBIS: u32 = 0x5416; 667 /// 清除终端控制信号的位 668 pub const TIOCMBIC: u32 = 0x5417; 669 /// 设置终端控制信号的状态 670 pub const TIOCMSET: u32 = 0x5418; 671 /// 获取软件载波状态 672 pub const TIOCGSOFTCAR: u32 = 0x5419; 673 /// 设置软件载波状态 674 pub const TIOCSSOFTCAR: u32 = 0x541A; 675 /// 获取输入队列的字节数 676 pub const FIONREAD: u32 = 0x541B; 677 /// Linux 特有命令 678 pub const TIOCLINUX: u32 = 0x541C; 679 /// 获取控制台设备 680 pub const TIOCCONS: u32 = 0x541D; 681 /// 获取串行设备参数 682 pub const TIOCGSERIAL: u32 = 0x541E; 683 /// 设置串行设备参数 684 pub const TIOCSSERIAL: u32 = 0x541F; 685 /// 设置套接字的报文模式 686 pub const TIOCPKT: u32 = 0x5420; 687 /// 设置非阻塞 I/O 688 pub const FIONBIO: u32 = 0x5421; 689 /// 清除控制终端 690 pub const TIOCNOTTY: u32 = 0x5422; 691 /// 设置终端线路驱动器 692 pub const TIOCSETD: u32 = 0x5423; 693 /// 获取终端线路驱动器 694 pub const TIOCGETD: u32 = 0x5424; 695 /// 发送终止条件 696 pub const TCSBRKP: u32 = 0x5425; 697 /// 开始发送零比特 698 pub const TIOCSBRK: u32 = 0x5427; 699 /// 停止发送零比特 700 pub const TIOCCBRK: u32 = 0x5428; 701 /// Return the session ID of FD 702 pub const TIOCGSID: u32 = 0x5429; 703 /// 设置ptl锁标记 704 pub const TIOCSPTLCK: u32 = 0x40045431; 705 /// 获取ptl锁标记 706 pub const TIOCGPTLCK: u32 = 0x80045439; 707 /// 获取packet标记 708 pub const TIOCGPKT: u32 = 0x80045438; 709 /// 获取pts index 710 pub const TIOCGPTN: u32 = 0x80045430; 711 } 712