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