⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty_io.c

📁 linux0.11内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
// 如果该字符是停止字符(^Q),则复位tty 停止标志,继续处理其它字符。	  if (c == START_CHAR (tty))	    {	      tty->stopped = 0;	      continue;	    }	}// 若输入模式标志集中ISIG 标志置位,则在收到INTR、QUIT、SUSP 或DSUSP 字符时,需要为进程// 产生相应的信号。      if (L_ISIG (tty))	{// 如果该字符是键盘中断符(^C),则向当前进程发送键盘中断信号,并继续处理下一字符。	  if (c == INTR_CHAR (tty))	    {	      tty_intr (tty, INTMASK);	      continue;	    }// 如果该字符是键盘中断符(^\),则向当前进程发送键盘退出信号,并继续处理下一字符。	  if (c == QUIT_CHAR (tty))	    {	      tty_intr (tty, QUITMASK);	      continue;	    }	}// 如果该字符是换行符NL(10),或者是文件结束符EOF(^D),辅助缓冲队列字符数加1。[??]      if (c == 10 || c == EOF_CHAR (tty))	tty->secondary.data++;// 如果本地模式标志集中回显标志ECHO 置位,那么,如果字符是换行符NL(10),则将换行符NL(10)// 和回车符CR(13)放入tty 写队列缓冲区中;如果字符是控制字符(字符值<32)并且回显控制字符标志// ECHOCTL 置位,则将字符'^'和字符c+64 放入tty 写队列中(也即会显示^C、^H 等);否则将该字符// 直接放入tty 写缓冲队列中。最后调用该tty 的写操作函数。      if (L_ECHO (tty))	{	  if (c == 10)	    {	      PUTCH (10, tty->write_q);	      PUTCH (13, tty->write_q);	    }	  else if (c < 32)	    {	      if (L_ECHOCTL (tty))		{		  PUTCH ('^', tty->write_q);		  PUTCH (c + 64, tty->write_q);		}	    }	  else	    PUTCH (c, tty->write_q);	  tty->write (tty);	}// 将该字符放入辅助队列中。      PUTCH (c, tty->secondary);    }// 唤醒等待该辅助缓冲队列的进程(如果有的话)。  wake_up (&tty->secondary.proc_list);}//// tty 读函数。// 参数:channel - 子设备号;buf - 缓冲区指针;nr - 欲读字节数。// 返回已读字节数。inttty_read (unsigned channel, char *buf, int nr){  struct tty_struct *tty;  char c, *b = buf;  int minimum, time, flag = 0;  long oldalarm;// 本版本linux 内核的终端只有3 个子设备,分别是控制台(0)、串口终端1(1)和串口终端2(2)。// 所以任何大于2 的子设备号都是非法的。写的字节数当然也不能小于0 的。  if (channel > 2 || nr < 0)    return -1;// tty 指针指向子设备号对应ttb_table 表中的tty 结构。  tty = &tty_table[channel];// 下面首先保存进程原定时值,然后根据控制字符VTIME 和VMIN 设置读字符操作的超时定时值。// 在非规范模式下,这两个值是超时定时值。MIN 表示为了满足读操作,需要读取的最少字符数。// TIME 是一个十分之一秒计数的计时值。// 首先取进程中的(报警)定时值(滴答数)。  oldalarm = current->alarm;// 并设置读操作超时定时值time 和需要最少读取的字符个数minimum。  time = 10L * tty->termios.c_cc[VTIME];  minimum = tty->termios.c_cc[VMIN];// 如果设置了读超时定时值time 但没有设置最少读取个数minimum,那么在读到至少一个字符或者// 定时超时后读操作将立刻返回。所以这里置minimum=1。  if (time && !minimum)    {      minimum = 1;// 如果进程原定时值是0 或者time+当前系统时间值小于进程原定时值的话,则置重新设置进程定时// 值为time+当前系统时间,并置flag 标志。      if (flag = (!oldalarm || time + jiffies < oldalarm))	current->alarm = time + jiffies;    }// 如果设置的最少读取字符数>欲读的字符数,则令其等于此次欲读取的字符数。  if (minimum > nr)    minimum = nr;// 当欲读的字节数>0,则循环执行以下操作。  while (nr > 0)    {// 如果flag 不为0(即进程原定时值是0 或者time+当前系统时间值小于进程原定时值)并且进程有定// 时信号SIGALRM,则复位进程的定时信号并中断循环。      if (flag && (current->signal & ALRMMASK))	{	  current->signal &= ~ALRMMASK;	  break;	}// 如果当前进程有信号要处理,则退出,返回0。      if (current->signal)	break;// 如果辅助缓冲队列(规范模式队列)为空,或者设置了规范模式标志并且辅助队列中字符数为0 以及// 辅助模式缓冲队列空闲空间>20,则进入可中断睡眠状态,返回后继续处理。      if (EMPTY (tty->secondary) || (L_CANON (tty) &&				     !tty->secondary.data				     && LEFT (tty->secondary) > 20))	{	  sleep_if_empty (&tty->secondary);	  continue;	}// 执行以下操作,直到nr=0 或者辅助缓冲队列为空。      do	{// 取辅助缓冲队列字符c。	  GETCH (tty->secondary, c);// 如果该字符是文件结束符(^D)或者是换行符NL(10),则辅助缓冲队列字符数减1。	  if (c == EOF_CHAR (tty) || c == 10)	    tty->secondary.data--;// 如果该字符是文件结束符(^D)并且规范模式标志置位,则返回已读字符数,并退出。	  if (c == EOF_CHAR (tty) && L_CANON (tty))	    return (b - buf);// 否则将该字符放入用户数据段缓冲区buf 中,欲读字符数减1,如果欲读字符数已为0,则中断循环。	  else	    {	      put_fs_byte (c, b++);	      if (!--nr)		break;	    }	}      while (nr > 0 && !EMPTY (tty->secondary));// 如果超时定时值time 不为0 并且规范模式标志没有置位(非规范模式),那么:      if (time && !L_CANON (tty))// 如果进程原定时值是0 或者time+当前系统时间值小于进程原定时值的话,则置重新设置进程定时值// 为time+当前系统时间,并置flag 标志。否则让进程的定时值等于进程原定时值。	if (flag = (!oldalarm || time + jiffies < oldalarm))	  current->alarm = time + jiffies;	else	  current->alarm = oldalarm;// 如果规范模式标志置位,那么若没有读到1 个字符则中断循环。否则若已读取数大于或等于最少要// 求读取的字符数,则也中断循环。      if (L_CANON (tty))	{	  if (b - buf)	    break;	}      else if (b - buf >= minimum)	break;    }// 让进程的定时值等于进程原定时值。  current->alarm = oldalarm;// 如果进程有信号并且没有读取任何字符,则返回出错号(超时)。  if (current->signal && !(b - buf))    return -EINTR;  return (b - buf);		// 返回已读取的字符数。}//// tty 写函数。// 参数:channel - 子设备号;buf - 缓冲区指针;nr - 写字节数。// 返回已写字节数。inttty_write (unsigned channel, char *buf, int nr){  static cr_flag = 0;  struct tty_struct *tty;  char c, *b = buf;// 本版本linux 内核的终端只有3 个子设备,分别是控制台(0)、串口终端1(1)和串口终端2(2)。// 所以任何大于2 的子设备号都是非法的。写的字节数当然也不能小于0 的。  if (channel > 2 || nr < 0)    return -1;// tty 指针指向子设备号对应ttb_table 表中的tty 结构。  tty = channel + tty_table;// 字符设备是一个一个字符进行处理的,所以这里对于nr 大于0 时对每个字符进行循环处理。  while (nr > 0)    {// 如果此时tty 的写队列已满,则当前进程进入可中断的睡眠状态。      sleep_if_full (&tty->write_q);// 如果当前进程有信号要处理,则退出,返回0。      if (current->signal)	break;// 当要写的字节数>0 并且tty 的写队列不满时,循环执行以下操作。      while (nr > 0 && !FULL (tty->write_q))	{// 从用户数据段内存中取一字节c。	  c = get_fs_byte (b);// 如果终端输出模式标志集中的执行输出处理标志OPOST 置位,则执行下列输出时处理过程。	  if (O_POST (tty))	    {// 如果该字符是回车符'\r'(CR,13)并且回车符转换行符标志OCRNL 置位,则将该字符换成换行符// '\n'(NL,10);否则如果该字符是换行符'\n'(NL,10)并且换行转回车功能标志ONLRET 置位的话,// 则将该字符换成回车符'\r'(CR,13)。	      if (c == '\r' && O_CRNL (tty))		c = '\n';	      else if (c == '\n' && O_NLRET (tty))		c = '\r';// 如果该字符是换行符'\n'并且回车标志cr_flag 没有置位,换行转回车-换行标志ONLCR 置位的话,// 则将cr_flag 置位,并将一回车符放入写队列中。然后继续处理下一个字符。	      if (c == '\n' && !cr_flag && O_NLCR (tty))		{		  cr_flag = 1;		  PUTCH (13, tty->write_q);		  continue;		}// 如果小写转大写标志OLCUC 置位的话,就将该字符转成大写字符。	      if (O_LCUC (tty))		c = toupper (c);	    }// 用户数据缓冲指针b 前进1 字节;欲写字节数减1 字节;复位cr_flag 标志,并将该字节放入tty// 写队列中。	  b++;	  nr--;	  cr_flag = 0;	  PUTCH (c, tty->write_q);	}// 若字节全部写完,或者写队列已满,则程序执行到这里。调用对应tty 的写函数,若还有字节要写,// 则等待写队列不满,所以调用调度程序,先去执行其它任务。      tty->write (tty);      if (nr > 0)	schedule ();    }  return (b - buf);		// 返回写入的字节数。}/** Jeh, sometimes I really like the 386.* This routine is called from an interrupt,* and there should be absolutely no problem* with sleeping even in an interrupt (I hope).* Of course, if somebody proves me wrong, I'll* hate intel for all time :-). We'll have to* be careful and see to reinstating the interrupt* chips before calling this, though.** I don't think we sleep here under normal circumstances* anyway, which is good, as the task sleeping might be* totally innocent.*//** 呵,有时我是真得很喜欢386。该子程序是从一个中断处理程序中调用的,即使在* 中断处理程序中睡眠也应该绝对没有问题(我希望如此)。当然,如果有人证明我是* 错的,那么我将憎恨intel 一辈子?。但是我们必须小心,在调用该子程序之前需* 要恢复中断。** 我不认为在通常环境下会处在这里睡眠,这样很好,因为任务睡眠是完全任意的。*///// tty 中断处理调用函数 - 执行tty 中断处理。// 参数:tty - 指定的tty 终端号(0,1 或2)。// 将指定tty 终端队列缓冲区中的字符复制成规范(熟)模式字符并存放在辅助队列(规范模式队列)中。// 在串口读字符中断(rs_io.s, 109)和键盘中断(kerboard.S, 69)中调用。voiddo_tty_interrupt (int tty){  copy_to_cooked (tty_table + tty);}//// 字符设备初始化函数。空,为以后扩展做准备。voidchr_dev_init (void){}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -