BOOK.T
上传用户:datang2001
上传日期:2007-02-01
资源大小:53269k
文件大小:987k
源码类别:

操作系统开发

开发平台:

C/C++

  1. 10970 }
  2. 10973 /*==========================================================================*
  3. 10974  *                              w_handler                                   *
  4. 10975  *==========================================================================*/
  5. 10976 PRIVATE int w_handler(irq)
  6. 10977 int irq;
  7. 10978 {
  8. 10979 /* Disk interrupt, send message to winchester task and reenable interrupts. */
  9. 10980
  10. 10981   w_status = in_byte(w_wn->base + REG_STATUS);  /* acknowledge interrupt */
  11. 10982   interrupt(WINCHESTER);
  12. 10983   return 1;
  13. 10984 }
  14. 10987 /*============================================================================*
  15. 10988  *                              w_geometry                                    *
  16. 10989  *============================================================================*/
  17. .Ep 144 src/kernel/at_wini.c
  18. 10990 PRIVATE void w_geometry(entry)
  19. 10991 struct partition *entry;
  20. 10992 {
  21. 10993   entry->cylinders = w_wn->lcylinders;
  22. 10994   entry->heads = w_wn->lheads;
  23. 10995   entry->sectors = w_wn->lsectors;
  24. 10996 }
  25. 10997 #endif /* ENABLE_AT_WINI */
  26. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  27. src/kernel/clock.c    
  28. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  29. 11000 /* This file contains the code and data for the clock task.  The clock task
  30. 11001  * accepts six message types:
  31. 11002  *
  32. 11003  *   HARD_INT:    a clock interrupt has occurred
  33. 11004  *   GET_UPTIME:  get the time since boot in ticks
  34. 11005  *   GET_TIME:    a process wants the real time in seconds
  35. 11006  *   SET_TIME:    a process wants to set the real time in seconds
  36. 11007  *   SET_ALARM:   a process wants to be alerted after a specified interval
  37. 11008  *   SET_SYN_AL:  set the sync alarm
  38. 11009  *
  39. 11010  *
  40. 11011  * The input message is format m6.  The parameters are as follows:
  41. 11012  *
  42. 11013  *     m_type    CLOCK_PROC   FUNC    NEW_TIME
  43. 11014  * ---------------------------------------------
  44. 11015  * | HARD_INT   |          |         |         |
  45. 11016  * |------------+----------+---------+---------|
  46. 11017  * | GET_UPTIME |          |         |         |
  47. 11018  * |------------+----------+---------+---------|
  48. 11019  * | GET_TIME   |          |         |         |
  49. 11020  * |------------+----------+---------+---------|
  50. 11021  * | SET_TIME   |          |         | newtime |
  51. 11022  * |------------+----------+---------+---------|
  52. 11023  * | SET_ALARM  | proc_nr  |f to call|  delta  |
  53. 11024  * |------------+----------+---------+---------|
  54. 11025  * | SET_SYN_AL | proc_nr  |         |  delta  |
  55. 11026  * ---------------------------------------------
  56. 11027  * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
  57. 11028  * the message, depending upon the message type.
  58. 11029  *
  59. 11030  * Reply messages are of type OK, except in the case of a HARD_INT, to
  60. 11031  * which no reply is generated. For the GET_* messages the time is returned
  61. 11032  * in the NEW_TIME field, and for the SET_ALARM and SET_SYN_AL the time
  62. 11033  * in seconds remaining until the alarm is returned is returned in the same
  63. 11034  * field.
  64. 11035  *
  65. 11036  * When an alarm goes off, if the caller is a user process, a SIGALRM signal
  66. 11037  * is sent to it.  If it is a task, a function specified by the caller will
  67. 11038  * be invoked.  This function may, for example, send a message, but only if
  68. 11039  * it is certain that the task will be blocked when the timer goes off. A
  69. 11040  * synchronous alarm sends a message to the synchronous alarm task, which
  70. 11041  * in turn can dispatch a message to another server. This is the only way
  71. 11042  * to send an alarm to a server, since servers cannot use the function-call
  72. 11043  * mechanism available to tasks and servers cannot receive signals.
  73. 11044  */
  74. .Op 145 src/kernel/clock.c
  75. 11045
  76. 11046 #include "kernel.h"
  77. 11047 #include <signal.h>
  78. 11048 #include <minix/callnr.h>
  79. 11049 #include <minix/com.h>
  80. 11050 #include "proc.h"
  81. 11051
  82. 11052 /* Constant definitions. */
  83. 11053 #define MILLISEC         100    /* how often to call the scheduler (msec) */
  84. 11054 #define SCHED_RATE (MILLISEC*HZ/1000)   /* number of ticks per schedule */
  85. 11055
  86. 11056 /* Clock parameters. */
  87. 11057 #define COUNTER_FREQ (2*TIMER_FREQ)     /* counter frequency using sqare wave*/
  88. 11058 #define LATCH_COUNT     0x00    /* cc00xxxx, c = channel, x = any */
  89. 11059 #define SQUARE_WAVE     0x36    /* ccaammmb, a = access, m = mode, b = BCD */
  90. 11060                                 /*   11x11, 11 = LSB then MSB, x11 = sq wave */
  91. 11061 #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
  92. 11062 #define TIMER_FREQ  1193182L    /* clock frequency for timer in PC and AT */
  93. 11063
  94. 11064 #define CLOCK_ACK_BIT   0x80    /* PS/2 clock interrupt acknowledge bit */
  95. 11065
  96. 11066 /* Clock task variables. */
  97. 11067 PRIVATE clock_t realtime;       /* real time clock */
  98. 11068 PRIVATE time_t boot_time;       /* time in seconds of system boot */
  99. 11069 PRIVATE clock_t next_alarm;     /* probable time of next alarm */
  100. 11070 PRIVATE message mc;             /* message buffer for both input and output */
  101. 11071 PRIVATE int watchdog_proc;      /* contains proc_nr at call of *watch_dog[]*/
  102. 11072 PRIVATE watchdog_t watch_dog[NR_TASKS+NR_PROCS];
  103. 11073
  104. 11074 /* Variables used by both clock task and synchronous alarm task */
  105. 11075 PRIVATE int syn_al_alive= TRUE; /* don't wake syn_alrm_task before inited*/
  106. 11076 PRIVATE int syn_table[NR_TASKS+NR_PROCS]; /* which tasks get CLOCK_INT*/
  107. 11077
  108. 11078 /* Variables changed by interrupt handler */
  109. 11079 PRIVATE clock_t pending_ticks;  /* ticks seen by low level only */
  110. 11080 PRIVATE int sched_ticks = SCHED_RATE;   /* counter: when 0, call scheduler */
  111. 11081 PRIVATE struct proc *prev_ptr;  /* last user process run by clock task */
  112. 11082
  113. 11083 FORWARD _PROTOTYPE( void common_setalarm, (int proc_nr,
  114. 11084                 long delta_ticks, watchdog_t fuction) );
  115. 11085 FORWARD _PROTOTYPE( void do_clocktick, (void) );
  116. 11086 FORWARD _PROTOTYPE( void do_get_time, (void) );
  117. 11087 FORWARD _PROTOTYPE( void do_getuptime, (void) );
  118. 11088 FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
  119. 11089 FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr) );
  120. 11090 FORWARD _PROTOTYPE( void init_clock, (void) );
  121. 11091 FORWARD _PROTOTYPE( void cause_alarm, (void) );
  122. 11092 FORWARD _PROTOTYPE( void do_setsyn_alrm, (message *m_ptr) );
  123. 11093 FORWARD _PROTOTYPE( int clock_handler, (int irq) );
  124. 11094
  125. 11095 /*===========================================================================*
  126. 11096  *                              clock_task                                   *
  127. 11097  *===========================================================================*/
  128. 11098 PUBLIC void clock_task()
  129. 11099 {
  130. 11100 /* Main program of clock task.  It corrects realtime by adding pending
  131. 11101  * ticks seen only by the interrupt service, then it determines which
  132. 11102  * of the 6 possible calls this is by looking at 'mc.m_type'.  Then
  133. 11103  * it dispatches.
  134. 11104  */
  135. .Ep 146 src/kernel/clock.c
  136. 11105
  137. 11106   int opcode;
  138. 11107
  139. 11108   init_clock();                 /* initialize clock task */
  140. 11109
  141. 11110   /* Main loop of the clock task.  Get work, process it, sometimes reply. */
  142. 11111   while (TRUE) {
  143. 11112      receive(ANY, &mc);         /* go get a message */
  144. 11113      opcode = mc.m_type;        /* extract the function code */
  145. 11114
  146. 11115      lock();
  147. 11116      realtime += pending_ticks; /* transfer ticks from low level handler */
  148. 11117      pending_ticks = 0;         /* so we don't have to worry about them */
  149. 11118      unlock();
  150. 11119
  151. 11120      switch (opcode) {
  152. 11121         case HARD_INT:   do_clocktick();        break;
  153. 11122         case GET_UPTIME: do_getuptime();        break;
  154. 11123         case GET_TIME:   do_get_time();         break;
  155. 11124         case SET_TIME:   do_set_time(&mc);      break;
  156. 11125         case SET_ALARM:  do_setalarm(&mc);      break;
  157. 11126         case SET_SYNC_AL:do_setsyn_alrm(&mc);   break;
  158. 11127         default: panic("clock task got bad message", mc.m_type);
  159. 11128      }
  160. 11129
  161. 11130     /* Send reply, except for clock tick. */
  162. 11131     mc.m_type = OK;
  163. 11132     if (opcode != HARD_INT) send(mc.m_source, &mc);
  164. 11133   }
  165. 11134 }
  166. 11137 /*===========================================================================*
  167. 11138  *                              do_clocktick                                 *
  168. 11139  *===========================================================================*/
  169. 11140 PRIVATE void do_clocktick()
  170. 11141 {
  171. 11142 /* Despite its name, this routine is not called on every clock tick. It
  172. 11143  * is called on those clock ticks when a lot of work needs to be done.
  173. 11144  */
  174. 11145
  175. 11146   register struct proc *rp;
  176. 11147   register int proc_nr;
  177. 11148
  178. 11149   if (next_alarm <= realtime) {
  179. 11150         /* An alarm may have gone off, but proc may have exited, so check. */
  180. 11151         next_alarm = LONG_MAX;  /* start computing next alarm */
  181. 11152         for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
  182. 11153                 if (rp->p_alarm != 0) {
  183. 11154                         /* See if this alarm time has been reached. */
  184. 11155                         if (rp->p_alarm <= realtime) {
  185. 11156                                 /* A timer has gone off.  If it is a user proc,
  186. 11157                                  * send it a signal.  If it is a task, call the
  187. 11158                                  * function previously specified by the task.
  188. 11159                                  */
  189. 11160                                 proc_nr = proc_number(rp);
  190. 11161                                 if (watch_dog[proc_nr+NR_TASKS]) {
  191. 11162                                         watchdog_proc= proc_nr;
  192. 11163                                         (*watch_dog[proc_nr+NR_TASKS])();
  193. 11164                                 }
  194. .Op 147 src/kernel/clock.c
  195. 11165                                 else
  196. 11166                                         cause_sig(proc_nr, SIGALRM);
  197. 11167                                 rp->p_alarm = 0;
  198. 11168                         }
  199. 11169
  200. 11170                         /* Work on determining which alarm is next. */
  201. 11171                         if (rp->p_alarm != 0 && rp->p_alarm < next_alarm)
  202. 11172                                 next_alarm = rp->p_alarm;
  203. 11173                 }
  204. 11174         }
  205. 11175   }
  206. 11176
  207. 11177   /* If a user process has been running too long, pick another one. */
  208. 11178   if (--sched_ticks == 0) {
  209. 11179         if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
  210. 11180         sched_ticks = SCHED_RATE;               /* reset quantum */
  211. 11181         prev_ptr = bill_ptr;                    /* new previous process */
  212. 11182   }
  213. 11183 }
  214. 11186 /*===========================================================================*
  215. 11187  *                              do_getuptime                                 *
  216. 11188  *===========================================================================*/
  217. 11189 PRIVATE void do_getuptime()
  218. 11190 {
  219. 11191 /* Get and return the current clock uptime in ticks. */
  220. 11192
  221. 11193   mc.NEW_TIME = realtime;       /* current uptime */
  222. 11194 }
  223. 11197 /*===========================================================================*
  224. 11198  *                              get_uptime                                   *
  225. 11199  *===========================================================================*/
  226. 11200 PUBLIC clock_t get_uptime()
  227. 11201 {
  228. 11202 /* Get and return the current clock uptime in ticks.  This function is
  229. 11203  * designed to be called from other tasks, so they can get uptime without
  230. 11204  * the overhead of messages. It has to be careful about pending_ticks.
  231. 11205  */
  232. 11206
  233. 11207   clock_t uptime;
  234. 11208
  235. 11209   lock();
  236. 11210   uptime = realtime + pending_ticks;
  237. 11211   unlock();
  238. 11212   return(uptime);
  239. 11213 }
  240. 11216 /*===========================================================================*
  241. 11217  *                              do_get_time                                  *
  242. 11218  *===========================================================================*/
  243. 11219 PRIVATE void do_get_time()
  244. 11220 {
  245. 11221 /* Get and return the current clock time in seconds. */
  246. 11222
  247. 11223   mc.NEW_TIME = boot_time + realtime/HZ;        /* current real time */
  248. 11224 }
  249. .Ep 148 src/kernel/clock.c
  250. 11227 /*===========================================================================*
  251. 11228  *                              do_set_time                                  *
  252. 11229  *===========================================================================*/
  253. 11230 PRIVATE void do_set_time(m_ptr)
  254. 11231 message *m_ptr;                 /* pointer to request message */
  255. 11232 {
  256. 11233 /* Set the real time clock.  Only the superuser can use this call. */
  257. 11234
  258. 11235   boot_time = m_ptr->NEW_TIME - realtime/HZ;
  259. 11236 }
  260. 11239 /*===========================================================================*
  261. 11240  *                              do_setalarm                                  *
  262. 11241  *===========================================================================*/
  263. 11242 PRIVATE void do_setalarm(m_ptr)
  264. 11243 message *m_ptr;                 /* pointer to request message */
  265. 11244 {
  266. 11245 /* A process wants an alarm signal or a task wants a given watch_dog function
  267. 11246  * called after a specified interval.
  268. 11247  */
  269. 11248
  270. 11249   register struct proc *rp;
  271. 11250   int proc_nr;                  /* which process wants the alarm */
  272. 11251   long delta_ticks;             /* in how many clock ticks does he want it? */
  273. 11252   watchdog_t function;          /* function to call (tasks only) */
  274. 11253
  275. 11254   /* Extract the parameters from the message. */
  276. 11255   proc_nr = m_ptr->CLOCK_PROC_NR;       /* process to interrupt later */
  277. 11256   delta_ticks = m_ptr->DELTA_TICKS;     /* how many ticks to wait */
  278. 11257   function = (watchdog_t) m_ptr->FUNC_TO_CALL;
  279. 11258                                         /* function to call (tasks only) */
  280. 11259   rp = proc_addr(proc_nr);
  281. 11260   mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
  282. 11261   if (!istaskp(rp)) function= 0;        /* user processes get signaled */
  283. 11262   common_setalarm(proc_nr, delta_ticks, function);
  284. 11263 }
  285. 11266 /*===========================================================================*
  286. 11267  *                              do_setsyn_alrm                               *
  287. 11268  *===========================================================================*/
  288. 11269 PRIVATE void do_setsyn_alrm(m_ptr)
  289. 11270 message *m_ptr;                 /* pointer to request message */
  290. 11271 {
  291. 11272 /* A process wants a synchronous alarm.
  292. 11273  */
  293. 11274
  294. 11275   register struct proc *rp;
  295. 11276   int proc_nr;                  /* which process wants the alarm */
  296. 11277   long delta_ticks;             /* in how many clock ticks does he want it? */
  297. 11278
  298. 11279   /* Extract the parameters from the message. */
  299. 11280   proc_nr = m_ptr->CLOCK_PROC_NR;       /* process to interrupt later */
  300. 11281   delta_ticks = m_ptr->DELTA_TICKS;     /* how many ticks to wait */
  301. 11282   rp = proc_addr(proc_nr);
  302. 11283   mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
  303. 11284   common_setalarm(proc_nr, delta_ticks, cause_alarm);
  304. .Op 149 src/kernel/clock.c
  305. 11285 }
  306. 11288 /*===========================================================================*
  307. 11289  *                              common_setalarm                              *
  308. 11290  *===========================================================================*/
  309. 11291 PRIVATE void common_setalarm(proc_nr, delta_ticks, function)
  310. 11292 int proc_nr;                    /* which process wants the alarm */
  311. 11293 long delta_ticks;               /* in how many clock ticks does he want it? */
  312. 11294 watchdog_t function;            /* function to call (0 if cause_sig is
  313. 11295                                  * to be called */
  314. 11296 {
  315. 11297 /* Finish up work of do_set_alarm and do_setsyn_alrm.  Record an alarm
  316. 11298  * request and check to see if it is the next alarm needed.
  317. 11299  */
  318. 11300
  319. 11301   register struct proc *rp;
  320. 11302
  321. 11303   rp = proc_addr(proc_nr);
  322. 11304   rp->p_alarm = (delta_ticks == 0 ? 0 : realtime + delta_ticks);
  323. 11305   watch_dog[proc_nr+NR_TASKS] = function;
  324. 11306
  325. 11307   /* Which alarm is next? */
  326. 11308   next_alarm = LONG_MAX;
  327. 11309   for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
  328. 11310         if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
  329. 11311
  330. 11312 }
  331. 11315 /*===========================================================================*
  332. 11316  *                              cause_alarm                                  *
  333. 11317  *===========================================================================*/
  334. 11318 PRIVATE void cause_alarm()
  335. 11319 {
  336. 11320 /* Routine called if a timer goes off and the process requested a synchronous
  337. 11321  * alarm. The process number is in the global variable watchdog_proc (HACK).
  338. 11322  */
  339. 11323   message mess;
  340. 11324
  341. 11325   syn_table[watchdog_proc + NR_TASKS]= TRUE;
  342. 11326   if (!syn_al_alive) send (SYN_ALRM_TASK, &mess);
  343. 11327 }
  344. 11330 /*===========================================================================*
  345. 11331  *                              syn_alrm_task                                *
  346. 11332  *===========================================================================*/
  347. 11333 PUBLIC void syn_alrm_task()
  348. 11334 {
  349. 11335 /* Main program of the synchronous alarm task.
  350. 11336  * This task receives messages only from cause_alarm in the clock task.
  351. 11337  * It sends a CLOCK_INT message to a process that requested a syn_alrm.
  352. 11338  * Synchronous alarms are so called because, unlike a signals or the
  353. 11339  * activation of a watchdog, a synchronous alarm is received by a process
  354. 11340  * when it is in a known part of its code, that is, when it has issued
  355. 11341  * a call to receive a message.
  356. 11342  */
  357. 11343
  358. 11344   message mess;
  359. .Ep 150 src/kernel/clock.c
  360. 11345   int work_done;        /* ready to sleep ? */
  361. 11346   int *al_ptr;          /* pointer in syn_table */
  362. 11347   int i;
  363. 11348
  364. 11349   syn_al_alive= TRUE;
  365. 11350   for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
  366. 11351         *al_ptr= FALSE;
  367. 11352
  368. 11353   while (TRUE) {
  369. 11354         work_done= TRUE;
  370. 11355         for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
  371. 11356                 if (*al_ptr) {
  372. 11357                         *al_ptr= FALSE;
  373. 11358                         mess.m_type= CLOCK_INT;
  374. 11359                         send (i-NR_TASKS, &mess);
  375. 11360                         work_done= FALSE;
  376. 11361                 }
  377. 11362         if (work_done) {
  378. 11363                 syn_al_alive= FALSE;
  379. 11364                 receive (CLOCK, &mess);
  380. 11365                 syn_al_alive= TRUE;
  381. 11366         }
  382. 11367   }
  383. 11368 }
  384. 11371 /*===========================================================================*
  385. 11372  *                              clock_handler                                *
  386. 11373  *===========================================================================*/
  387. 11374 PRIVATE int clock_handler(irq)
  388. 11375 int irq;
  389. 11376 {
  390. 11377 /* This executes on every clock tick (i.e., every time the timer chip
  391. 11378  * generates an interrupt). It does a little bit of work so the clock
  392. 11379  * task does not have to be called on every tick.
  393. 11380  *
  394. 11381  * Switch context to do_clocktick if an alarm has gone off.
  395. 11382  * Also switch there to reschedule if the reschedule will do something.
  396. 11383  * This happens when
  397. 11384  *      (1) quantum has expired
  398. 11385  *      (2) current process received full quantum (as clock sampled it!)
  399. 11386  *      (3) something else is ready to run.
  400. 11387  * Also call TTY and PRINTER and let them do whatever is necessary.
  401. 11388  *
  402. 11389  * Many global global and static variables are accessed here.  The safety
  403. 11390  * of this must be justified.  Most of them are not changed here:
  404. 11391  *      k_reenter:
  405. 11392  *              This safely tells if the clock interrupt is nested.
  406. 11393  *      proc_ptr, bill_ptr:
  407. 11394  *              These are used for accounting.  It does not matter if proc.c
  408. 11395  *              is changing them, provided they are always valid pointers,
  409. 11396  *              since at worst the previous process would be billed.
  410. 11397  *      next_alarm, realtime, sched_ticks, bill_ptr, prev_ptr,
  411. 11398  *      rdy_head[USER_Q]:
  412. 11399  *              These are tested to decide whether to call interrupt().  It
  413. 11400  *              does not matter if the test is sometimes (rarely) backwards
  414. 11401  *              due to a race, since this will only delay the high-level
  415. 11402  *              processing by one tick, or call the high level unnecessarily.
  416. 11403  * The variables which are changed require more care:
  417. 11404  *      rp->user_time, rp->sys_time:
  418. .Op 151 src/kernel/clock.c
  419. 11405  *              These are protected by explicit locks in system.c.  They are
  420. 11406  *              not properly protected in dmp.c (the increment here is not
  421. 11407  *              atomic) but that hardly matters.
  422. 11408  *      pending_ticks:
  423. 11409  *              This is protected by explicit locks in clock.c.  Don't
  424. 11410  *              update realtime directly, since there are too many
  425. 11411  *              references to it to guard conveniently.
  426. 11412  *      lost_ticks:
  427. 11413  *              Clock ticks counted outside the clock task.
  428. 11414  *      sched_ticks, prev_ptr:
  429. 11415  *              Updating these competes with similar code in do_clocktick().
  430. 11416  *              No lock is necessary, because if bad things happen here
  431. 11417  *              (like sched_ticks going negative), the code in do_clocktick()
  432. 11418  *              will restore the variables to reasonable values, and an
  433. 11419  *              occasional missed or extra sched() is harmless.
  434. 11420  *
  435. 11421  * Are these complications worth the trouble?  Well, they make the system 15%
  436. 11422  * faster on a 5MHz 8088, and make task debugging much easier since there are
  437. 11423  * no task switches on an inactive system.
  438. 11424  */
  439. 11425
  440. 11426   register struct proc *rp;
  441. 11427   register unsigned ticks;
  442. 11428   clock_t now;
  443. 11429
  444. 11430   if (ps_mca) {
  445. 11431         /* Acknowledge the PS/2 clock interrupt. */
  446. 11432         out_byte(PORT_B, in_byte(PORT_B) | CLOCK_ACK_BIT);
  447. 11433   }
  448. 11434
  449. 11435   /* Update user and system accounting times.
  450. 11436    * First charge the current process for user time.
  451. 11437    * If the current process is not the billable process (usually because it
  452. 11438    * is a task), charge the billable process for system time as well.
  453. 11439    * Thus the unbillable tasks' user time is the billable users' system time.
  454. 11440    */
  455. 11441   if (k_reenter != 0)
  456. 11442         rp = proc_addr(HARDWARE);
  457. 11443   else
  458. 11444         rp = proc_ptr;
  459. 11445   ticks = lost_ticks + 1;
  460. 11446   lost_ticks = 0;
  461. 11447   rp->user_time += ticks;
  462. 11448   if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;
  463. 11449
  464. 11450   pending_ticks += ticks;
  465. 11451   now = realtime + pending_ticks;
  466. 11452   if (tty_timeout <= now) tty_wakeup(now);      /* possibly wake up TTY */
  467. 11453   pr_restart();                                 /* possibly restart printer */
  468. 11454
  469. 11455   if (next_alarm <= now ||
  470. 11456       sched_ticks == 1 &&
  471. 11457       bill_ptr == prev_ptr &&
  472. 11458       rdy_head[USER_Q] != NIL_PROC) {
  473. 11459         interrupt(CLOCK);
  474. 11460         return 1;       /* Reenable interrupts */
  475. 11461   }
  476. 11462
  477. 11463   if (--sched_ticks == 0) {
  478. 11464         /* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
  479. .Ep 152 src/kernel/clock.c
  480. 11465         sched_ticks = SCHED_RATE;       /* reset quantum */
  481. 11466         prev_ptr = bill_ptr;            /* new previous process */
  482. 11467   }
  483. 11468   return 1;     /* Reenable clock interrupt */
  484. 11469 }
  485. 11471 /*===========================================================================*
  486. 11472  *                              init_clock                                   *
  487. 11473  *===========================================================================*/
  488. 11474 PRIVATE void init_clock()
  489. 11475 {
  490. 11476 /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
  491. 11477
  492. 11478   out_byte(TIMER_MODE, SQUARE_WAVE);    /* set timer to run continuously */
  493. 11479   out_byte(TIMER0, TIMER_COUNT);        /* load timer low byte */
  494. 11480   out_byte(TIMER0, TIMER_COUNT >> 8);   /* load timer high byte */
  495. 11481   put_irq_handler(CLOCK_IRQ, clock_handler);    /* set the interrupt handler */
  496. 11482   enable_irq(CLOCK_IRQ);                /* ready for clock interrupts */
  497. 11483 }
  498. 11486 /*===========================================================================*
  499. 11487  *                              clock_stop                                   *
  500. 11488  *===========================================================================*/
  501. 11489 PUBLIC void clock_stop()
  502. 11490 {
  503. 11491 /* Reset the clock to the BIOS rate. (For rebooting) */
  504. 11492
  505. 11493   out_byte(TIMER_MODE, 0x36);
  506. 11494   out_byte(TIMER0, 0);
  507. 11495   out_byte(TIMER0, 0);
  508. 11496 }
  509. 11499 /*==========================================================================*
  510. 11500  *                              milli_delay                                 *
  511. 11501  *==========================================================================*/
  512. 11502 PUBLIC void milli_delay(millisec)
  513. 11503 unsigned millisec;
  514. 11504 {
  515. 11505 /* Delay some milliseconds. */
  516. 11506
  517. 11507   struct milli_state ms;
  518. 11508
  519. 11509   milli_start(&ms);
  520. 11510   while (milli_elapsed(&ms) < millisec) {}
  521. 11511 }
  522. 11513 /*==========================================================================*
  523. 11514  *                              milli_start                                 *
  524. 11515  *==========================================================================*/
  525. 11516 PUBLIC void milli_start(msp)
  526. 11517 struct milli_state *msp;
  527. 11518 {
  528. 11519 /* Prepare for calls to milli_elapsed(). */
  529. 11520
  530. 11521   msp->prev_count = 0;
  531. 11522   msp->accum_count = 0;
  532. 11523 }
  533. .Op 153 src/kernel/clock.c
  534. 11526 /*==========================================================================*
  535. 11527  *                              milli_elapsed                               *
  536. 11528  *==========================================================================*/
  537. 11529 PUBLIC unsigned milli_elapsed(msp)
  538. 11530 struct milli_state *msp;
  539. 11531 {
  540. 11532 /* Return the number of milliseconds since the call to milli_start().  Must be
  541. 11533  * polled rapidly.
  542. 11534  */
  543. 11535   unsigned count;
  544. 11536
  545. 11537   /* Read the counter for channel 0 of the 8253A timer.  The counter
  546. 11538    * decrements at twice the timer frequency (one full cycle for each
  547. 11539    * half of square wave).  The counter normally has a value between 0
  548. 11540    * and TIMER_COUNT, but before the clock task has been initialized,
  549. 11541    * its maximum value is 65535, as set by the BIOS.
  550. 11542    */
  551. 11543   out_byte(TIMER_MODE, LATCH_COUNT);    /* make chip copy count to latch */
  552. 11544   count = in_byte(TIMER0);      /* countdown continues during 2-step read */
  553. 11545   count |= in_byte(TIMER0) << 8;
  554. 11546
  555. 11547   /* Add difference between previous and new count unless the counter has
  556. 11548    * increased (restarted its cycle).  We may lose a tick now and then, but
  557. 11549    * microsecond precision is not needed.
  558. 11550    */
  559. 11551   msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
  560. 11552   msp->prev_count = count;
  561. 11553
  562. 11554   return msp->accum_count / (TIMER_FREQ / 1000);
  563. 11555 }
  564. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  565. src/kernel/tty.h    
  566. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  567. 11600 /*      tty.h - Terminals       */
  568. 11601
  569. 11602 #define TTY_IN_BYTES     256    /* tty input queue size */
  570. 11603 #define TAB_SIZE           8    /* distance between tab stops */
  571. 11604 #define TAB_MASK           7    /* mask to compute a tab stop position */
  572. 11605
  573. 11606 #define ESC             '33'   /* escape */
  574. 11607
  575. 11608 #define O_NOCTTY       00400    /* from <fcntl.h>, or cc will choke */
  576. 11609 #define O_NONBLOCK     04000
  577. 11610
  578. 11611 typedef _PROTOTYPE( void (*devfun_t), (struct tty *tp) );
  579. 11612 typedef _PROTOTYPE( void (*devfunarg_t), (struct tty *tp, int c) );
  580. 11613
  581. 11614 typedef struct tty {
  582. 11615   int tty_events;               /* set when TTY should inspect this line */
  583. 11616
  584. 11617   /* Input queue.  Typed characters are stored here until read by a program. */
  585. 11618   u16_t *tty_inhead;            /* pointer to place where next char goes */
  586. 11619   u16_t *tty_intail;            /* pointer to next char to be given to prog */
  587. .Ep 154 src/kernel/tty.h
  588. 11620   int tty_incount;              /* # chars in the input queue */
  589. 11621   int tty_eotct;                /* number of "line breaks" in input queue */
  590. 11622   devfun_t tty_devread;         /* routine to read from low level buffers */
  591. 11623   devfun_t tty_icancel;         /* cancel any device input */
  592. 11624   int tty_min;                  /* minimum requested #chars in input queue */
  593. 11625   clock_t tty_time;             /* time when the input is available */
  594. 11626   struct tty *tty_timenext;     /* for a list of ttys with active timers */
  595. 11627
  596. 11628   /* Output section. */
  597. 11629   devfun_t tty_devwrite;        /* routine to start actual device output */
  598. 11630   devfunarg_t tty_echo;         /* routine to echo characters input */
  599. 11631   devfun_t tty_ocancel;         /* cancel any ongoing device output */
  600. 11632   devfun_t tty_break;           /* let the device send a break */
  601. 11633
  602. 11634   /* Terminal parameters and status. */
  603. 11635   int tty_position;             /* current position on the screen for echoing */
  604. 11636   char tty_reprint;             /* 1 when echoed input messed up, else 0 */
  605. 11637   char tty_escaped;             /* 1 when LNEXT (^V) just seen, else 0 */
  606. 11638   char tty_inhibited;           /* 1 when STOP (^S) just seen (stops output) */
  607. 11639   char tty_pgrp;                /* slot number of controlling process */
  608. 11640   char tty_openct;              /* count of number of opens of this tty */
  609. 11641
  610. 11642   /* Information about incomplete I/O requests is stored here. */
  611. 11643   char tty_inrepcode;           /* reply code, TASK_REPLY or REVIVE */
  612. 11644   char tty_incaller;            /* process that made the call (usually FS) */
  613. 11645   char tty_inproc;              /* process that wants to read from tty */
  614. 11646   vir_bytes tty_in_vir;         /* virtual address where data is to go */
  615. 11647   int tty_inleft;               /* how many chars are still needed */
  616. 11648   int tty_incum;                /* # chars input so far */
  617. 11649   char tty_outrepcode;          /* reply code, TASK_REPLY or REVIVE */
  618. 11650   char tty_outcaller;           /* process that made the call (usually FS) */
  619. 11651   char tty_outproc;             /* process that wants to write to tty */
  620. 11652   vir_bytes tty_out_vir;        /* virtual address where data comes from */
  621. 11653   int tty_outleft;              /* # chars yet to be output */
  622. 11654   int tty_outcum;               /* # chars output so far */
  623. 11655   char tty_iocaller;            /* process that made the call (usually FS) */
  624. 11656   char tty_ioproc;              /* process that wants to do an ioctl */
  625. 11657   int tty_ioreq;                /* ioctl request code */
  626. 11658   vir_bytes tty_iovir;          /* virtual address of ioctl buffer */
  627. 11659
  628. 11660   /* Miscellaneous. */
  629. 11661   devfun_t tty_ioctl;           /* set line speed, etc. at the device level */
  630. 11662   devfun_t tty_close;           /* tell the device that the tty is closed */
  631. 11663   void *tty_priv;               /* pointer to per device private data */
  632. 11664   struct termios tty_termios;   /* terminal attributes */
  633. 11665   struct winsize tty_winsize;   /* window size (#lines and #columns) */
  634. 11666
  635. 11667   u16_t tty_inbuf[TTY_IN_BYTES];/* tty input buffer */
  636. 11668 } tty_t;
  637. 11669
  638. 11670 EXTERN tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
  639. 11671
  640. 11672 /* Values for the fields. */
  641. 11673 #define NOT_ESCAPED        0    /* previous character is not LNEXT (^V) */
  642. 11674 #define ESCAPED            1    /* previous character was LNEXT (^V) */
  643. 11675 #define RUNNING            0    /* no STOP (^S) has been typed to stop output */
  644. 11676 #define STOPPED            1    /* STOP (^S) has been typed to stop output */
  645. 11677
  646. 11678 /* Fields and flags on characters in the input queue. */
  647. 11679 #define IN_CHAR       0x00FF    /* low 8 bits are the character itself */
  648. .Op 155 src/kernel/tty.h
  649. 11680 #define IN_LEN        0x0F00    /* length of char if it has been echoed */
  650. 11681 #define IN_LSHIFT          8    /* length = (c & IN_LEN) >> IN_LSHIFT */
  651. 11682 #define IN_EOT        0x1000    /* char is a line break (^D, LF) */
  652. 11683 #define IN_EOF        0x2000    /* char is EOF (^D), do not return to user */
  653. 11684 #define IN_ESC        0x4000    /* escaped by LNEXT (^V), no interpretation */
  654. 11685
  655. 11686 /* Times and timeouts. */
  656. 11687 #define TIME_NEVER      ((clock_t) -1 < 0 ? (clock_t) LONG_MAX : (clock_t) -1)
  657. 11688 #define force_timeout() ((void) (tty_timeout = 0))
  658. 11689
  659. 11690 EXTERN tty_t *tty_timelist;     /* list of ttys with active timers */
  660. 11691
  661. 11692 /* Number of elements and limit of a buffer. */
  662. 11693 #define buflen(buf)     (sizeof(buf) / sizeof((buf)[0]))
  663. 11694 #define bufend(buf)     ((buf) + buflen(buf))
  664. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  665. src/kernel/tty.c    
  666. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  667. 11700 /* This file contains the terminal driver, both for the IBM console and regular
  668. 11701  * ASCII terminals.  It handles only the device-independent part of a TTY, the
  669. 11702  * device dependent parts are in console.c, rs232.c, etc.  This file contains
  670. 11703  * two main entry points, tty_task() and tty_wakeup(), and several minor entry
  671. 11704  * points for use by the device-dependent code.
  672. 11705  *
  673. 11706  * The device-independent part accepts "keyboard" input from the device-
  674. 11707  * dependent part, performs input processing (special key interpretation),
  675. 11708  * and sends the input to a process reading from the TTY.  Output to a TTY
  676. 11709  * is sent to the device-dependent code for output processing and "screen"
  677. 11710  * display.  Input processing is done by the device by calling 'in_process'
  678. 11711  * on the input characters, output processing may be done by the device itself
  679. 11712  * or by calling 'out_process'.  The TTY takes care of input queuing, the
  680. 11713  * device does the output queuing.  If a device receives an external signal,
  681. 11714  * like an interrupt, then it causes tty_wakeup() to be run by the CLOCK task
  682. 11715  * to, you guessed it, wake up the TTY to check if input or output can
  683. 11716  * continue.
  684. 11717  *
  685. 11718  * The valid messages and their parameters are:
  686. 11719  *
  687. 11720  *   HARD_INT:     output has been completed or input has arrived
  688. 11721  *   DEV_READ:     a process wants to read from a terminal
  689. 11722  *   DEV_WRITE:    a process wants to write on a terminal
  690. 11723  *   DEV_IOCTL:    a process wants to change a terminal's parameters
  691. 11724  *   DEV_OPEN:     a tty line has been opened
  692. 11725  *   DEV_CLOSE:    a tty line has been closed
  693. 11726  *   CANCEL:       terminate a previous incomplete system call immediately
  694. 11727  *
  695. 11728  *    m_type      TTY_LINE   PROC_NR    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS
  696. 11729  * ---------------------------------------------------------------------------
  697. 11730  * | HARD_INT    |         |         |         |         |         |         |
  698. 11731  * |-------------+---------+---------+---------+---------+---------+---------|
  699. 11732  * | DEV_READ    |minor dev| proc nr |  count  |         O_NONBLOCK| buf ptr |
  700. 11733  * |-------------+---------+---------+---------+---------+---------+---------|
  701. 11734  * | DEV_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
  702. .Ep 156 src/kernel/tty.c
  703. 11735  * |-------------+---------+---------+---------+---------+---------+---------|
  704. 11736  * | DEV_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
  705. 11737  * |-------------+---------+---------+---------+---------+---------+---------|
  706. 11738  * | DEV_OPEN    |minor dev| proc nr | O_NOCTTY|         |         |         |
  707. 11739  * |-------------+---------+---------+---------+---------+---------+---------|
  708. 11740  * | DEV_CLOSE   |minor dev| proc nr |         |         |         |         |
  709. 11741  * |-------------+---------+---------+---------+---------+---------+---------|
  710. 11742  * | CANCEL      |minor dev| proc nr |         |         |         |         |
  711. 11743  * ---------------------------------------------------------------------------
  712. 11744  */
  713. 11745
  714. 11746 #include "kernel.h"
  715. 11747 #include <termios.h>
  716. 11748 #include <sys/ioctl.h>
  717. 11749 #include <signal.h>
  718. 11750 #include <minix/callnr.h>
  719. 11751 #include <minix/com.h>
  720. 11752 #include <minix/keymap.h>
  721. 11753 #include "tty.h"
  722. 11754 #include "proc.h"
  723. 11755
  724. 11756 /* Address of a tty structure. */
  725. 11757 #define tty_addr(line)  (&tty_table[line])
  726. 11758
  727. 11759 /* First minor numbers for the various classes of TTY devices. */
  728. 11760 #define CONS_MINOR        0
  729. 11761 #define LOG_MINOR        15
  730. 11762 #define RS232_MINOR      16
  731. 11763 #define TTYPX_MINOR     128
  732. 11764 #define PTYPX_MINOR     192
  733. 11765
  734. 11766 /* Macros for magic tty types. */
  735. 11767 #define isconsole(tp)   ((tp) < tty_addr(NR_CONS))
  736. 11768
  737. 11769 /* Macros for magic tty structure pointers. */
  738. 11770 #define FIRST_TTY       tty_addr(0)
  739. 11771 #define END_TTY         tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))
  740. 11772
  741. 11773 /* A device exists if at least its 'devread' function is defined. */
  742. 11774 #define tty_active(tp)  ((tp)->tty_devread != NULL)
  743. 11775
  744. 11776 /* RS232 lines or pseudo terminals can be completely configured out. */
  745. 11777 #if NR_RS_LINES == 0
  746. 11778 #define rs_init(tp)     ((void) 0)
  747. 11779 #endif
  748. 11780 #if NR_PTYS == 0
  749. 11781 #define pty_init(tp)    ((void) 0)
  750. 11782 #define do_pty(tp, mp)  ((void) 0)
  751. 11783 #endif
  752. 11784
  753. 11785 FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr)         );
  754. 11786 FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr)          );
  755. 11787 FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr)           );
  756. 11788 FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr)          );
  757. 11789 FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr)           );
  758. 11790 FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr)          );
  759. 11791 FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp)                       );
  760. 11792 FORWARD _PROTOTYPE( int echo, (tty_t *tp, int ch)                       );
  761. 11793 FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch)                   );
  762. 11794 FORWARD _PROTOTYPE( int back_over, (tty_t *tp)                          );
  763. .Op 157 src/kernel/tty.c
  764. 11795 FORWARD _PROTOTYPE( void reprint, (tty_t *tp)                           );
  765. 11796 FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp)                         );
  766. 11797 FORWARD _PROTOTYPE( void setattr, (tty_t *tp)                           );
  767. 11798 FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp)                       );
  768. 11799 FORWARD _PROTOTYPE( void tty_init, (tty_t *tp)                          );
  769. 11800 FORWARD _PROTOTYPE( void settimer, (tty_t *tp, int on)                  );
  770. 11801
  771. 11802 /* Default attributes. */
  772. 11803 PRIVATE struct termios termios_defaults = {
  773. 11804   TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
  774. 11805   {
  775. 11806         TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
  776. 11807         TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
  777. 11808         TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
  778. 11809   },
  779. 11810 };
  780. 11811 PRIVATE struct winsize winsize_defaults;        /* = all zeroes */
  781. 11812
  782. 11813
  783. 11814 /*===========================================================================*
  784. 11815  *                              tty_task                                     *
  785. 11816  *===========================================================================*/
  786. 11817 PUBLIC void tty_task()
  787. 11818 {
  788. 11819 /* Main routine of the terminal task. */
  789. 11820
  790. 11821   message tty_mess;             /* buffer for all incoming messages */
  791. 11822   register tty_t *tp;
  792. 11823   unsigned line;
  793. 11824
  794. 11825   /* Initialize the terminal lines. */
  795. 11826   for (tp = FIRST_TTY; tp < END_TTY; tp++) tty_init(tp);
  796. 11827
  797. 11828   /* Display the Minix startup banner. */
  798. 11829   printf("Minix %s.%s  Copyright 1997 Prentice-Hall, Inc.nn",
  799. 11830                                                 OS_RELEASE, OS_VERSION);
  800. 11831   printf("Executing in 32-bit protected modenn");
  801. 11832
  802. 11833   while (TRUE) {
  803. 11834         /* Handle any events on any of the ttys. */
  804. 11835         for (tp = FIRST_TTY; tp < END_TTY; tp++) {
  805. 11836                 if (tp->tty_events) handle_events(tp);
  806. 11837         }
  807. 11838
  808. 11839         receive(ANY, &tty_mess);
  809. 11840
  810. 11841         /* A hardware interrupt is an invitation to check for events. */
  811. 11842         if (tty_mess.m_type == HARD_INT) continue;
  812. 11843
  813. 11844         /* Check the minor device number. */
  814. 11845         line = tty_mess.TTY_LINE;
  815. 11846         if ((line - CONS_MINOR) < NR_CONS) {
  816. 11847                 tp = tty_addr(line - CONS_MINOR);
  817. 11848         } else
  818. 11849         if (line == LOG_MINOR) {
  819. 11850                 tp = tty_addr(0);
  820. 11851         } else
  821. 11852         if ((line - RS232_MINOR) < NR_RS_LINES) {
  822. 11853                 tp = tty_addr(line - RS232_MINOR + NR_CONS);
  823. 11854         } else
  824. .Ep 158 src/kernel/tty.c
  825. 11855         if ((line - TTYPX_MINOR) < NR_PTYS) {
  826. 11856                 tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
  827. 11857         } else
  828. 11858         if ((line - PTYPX_MINOR) < NR_PTYS) {
  829. 11859                 tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
  830. 11860                 do_pty(tp, &tty_mess);
  831. 11861                 continue;                       /* this is a pty, not a tty */
  832. 11862         } else {
  833. 11863                 tp = NULL;
  834. 11864         }
  835. 11865
  836. 11866         /* If the device doesn't exist or is not configured return ENXIO. */
  837. 11867         if (tp == NULL || !tty_active(tp)) {
  838. 11868                 tty_reply(TASK_REPLY, tty_mess.m_source,
  839. 11869                                                 tty_mess.PROC_NR, ENXIO);
  840. 11870                 continue;
  841. 11871         }
  842. 11872
  843. 11873         /* Execute the requested function. */
  844. 11874         switch (tty_mess.m_type) {
  845. 11875             case DEV_READ:      do_read(tp, &tty_mess);         break;
  846. 11876             case DEV_WRITE:     do_write(tp, &tty_mess);        break;
  847. 11877             case DEV_IOCTL:     do_ioctl(tp, &tty_mess);        break;
  848. 11878             case DEV_OPEN:      do_open(tp, &tty_mess);         break;
  849. 11879             case DEV_CLOSE:     do_close(tp, &tty_mess);        break;
  850. 11880             case CANCEL:        do_cancel(tp, &tty_mess);       break;
  851. 11881             default:            tty_reply(TASK_REPLY, tty_mess.m_source,
  852. 11882                                                 tty_mess.PROC_NR, EINVAL);
  853. 11883         }
  854. 11884   }
  855. 11885 }
  856. 11888 /*===========================================================================*
  857. 11889  *                              do_read                                      *
  858. 11890  *===========================================================================*/
  859. 11891 PRIVATE void do_read(tp, m_ptr)
  860. 11892 register tty_t *tp;             /* pointer to tty struct */
  861. 11893 message *m_ptr;                 /* pointer to message sent to the task */
  862. 11894 {
  863. 11895 /* A process wants to read from a terminal. */
  864. 11896   int r;
  865. 11897
  866. 11898   /* Check if there is already a process hanging in a read, check if the
  867. 11899    * parameters are correct, do I/O.
  868. 11900    */
  869. 11901   if (tp->tty_inleft > 0) {
  870. 11902         r = EIO;
  871. 11903   } else
  872. 11904   if (m_ptr->COUNT <= 0) {
  873. 11905         r = EINVAL;
  874. 11906   } else
  875. 11907   if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
  876. 11908         r = EFAULT;
  877. 11909   } else {
  878. 11910         /* Copy information from the message to the tty struct. */
  879. 11911         tp->tty_inrepcode = TASK_REPLY;
  880. 11912         tp->tty_incaller = m_ptr->m_source;
  881. 11913         tp->tty_inproc = m_ptr->PROC_NR;
  882. 11914         tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
  883. .Op 159 src/kernel/tty.c
  884. 11915         tp->tty_inleft = m_ptr->COUNT;
  885. 11916
  886. 11917         if (!(tp->tty_termios.c_lflag & ICANON)
  887. 11918                                         && tp->tty_termios.c_cc[VTIME] > 0) {
  888. 11919                 if (tp->tty_termios.c_cc[VMIN] == 0) {
  889. 11920                         /* MIN & TIME specify a read timer that finishes the
  890. 11921                          * read in TIME/10 seconds if no bytes are available.
  891. 11922                          */
  892. 11923                         lock();
  893. 11924                         settimer(tp, TRUE);
  894. 11925                         tp->tty_min = 1;
  895. 11926                         unlock();
  896. 11927                 } else {
  897. 11928                         /* MIN & TIME specify an inter-byte timer that may
  898. 11929                          * have to be cancelled if there are no bytes yet.
  899. 11930                          */
  900. 11931                         if (tp->tty_eotct == 0) {
  901. 11932                                 lock();
  902. 11933                                 settimer(tp, FALSE);
  903. 11934                                 unlock();
  904. 11935                                 tp->tty_min = tp->tty_termios.c_cc[VMIN];
  905. 11936                         }
  906. 11937                 }
  907. 11938         }
  908. 11939
  909. 11940         /* Anything waiting in the input buffer? Clear it out... */
  910. 11941         in_transfer(tp);
  911. 11942         /* ...then go back for more */
  912. 11943         handle_events(tp);
  913. 11944         if (tp->tty_inleft == 0) return;                /* already done */
  914. 11945
  915. 11946         /* There were no bytes in the input queue available, so either suspend
  916. 11947          * the caller or break off the read if nonblocking.
  917. 11948          */
  918. 11949         if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
  919. 11950                 r = EAGAIN;                             /* cancel the read */
  920. 11951                 tp->tty_inleft = tp->tty_incum = 0;
  921. 11952         } else {
  922. 11953                 r = SUSPEND;                            /* suspend the caller */
  923. 11954                 tp->tty_inrepcode = REVIVE;
  924. 11955         }
  925. 11956   }
  926. 11957   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
  927. 11958 }
  928. 11961 /*===========================================================================*
  929. 11962  *                              do_write                                     *
  930. 11963  *===========================================================================*/
  931. 11964 PRIVATE void do_write(tp, m_ptr)
  932. 11965 register tty_t *tp;
  933. 11966 register message *m_ptr;        /* pointer to message sent to the task */
  934. 11967 {
  935. 11968 /* A process wants to write on a terminal. */
  936. 11969   int r;
  937. 11970
  938. 11971   /* Check if there is already a process hanging in a write, check if the
  939. 11972    * parameters are correct, do I/O.
  940. 11973    */
  941. 11974   if (tp->tty_outleft > 0) {
  942. .Ep 160 src/kernel/tty.c
  943. 11975         r = EIO;
  944. 11976   } else
  945. 11977   if (m_ptr->COUNT <= 0) {
  946. 11978         r = EINVAL;
  947. 11979   } else
  948. 11980   if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
  949. 11981         r = EFAULT;
  950. 11982   } else {
  951. 11983         /* Copy message parameters to the tty structure. */
  952. 11984         tp->tty_outrepcode = TASK_REPLY;
  953. 11985         tp->tty_outcaller = m_ptr->m_source;
  954. 11986         tp->tty_outproc = m_ptr->PROC_NR;
  955. 11987         tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
  956. 11988         tp->tty_outleft = m_ptr->COUNT;
  957. 11989
  958. 11990         /* Try to write. */
  959. 11991         handle_events(tp);
  960. 11992         if (tp->tty_outleft == 0) return;               /* already done */
  961. 11993
  962. 11994         /* None or not all the bytes could be written, so either suspend the
  963. 11995          * caller or break off the write if nonblocking.
  964. 11996          */
  965. 11997         if (m_ptr->TTY_FLAGS & O_NONBLOCK) {            /* cancel the write */
  966. 11998                 r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
  967. 11999                 tp->tty_outleft = tp->tty_outcum = 0;
  968. 12000         } else {
  969. 12001                 r = SUSPEND;                            /* suspend the caller */
  970. 12002                 tp->tty_outrepcode = REVIVE;
  971. 12003         }
  972. 12004   }
  973. 12005   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
  974. 12006 }
  975. 12009 /*===========================================================================*
  976. 12010  *                              do_ioctl                                     *
  977. 12011  *===========================================================================*/
  978. 12012 PRIVATE void do_ioctl(tp, m_ptr)
  979. 12013 register tty_t *tp;
  980. 12014 message *m_ptr;                 /* pointer to message sent to task */
  981. 12015 {
  982. 12016 /* Perform an IOCTL on this terminal. Posix termios calls are handled
  983. 12017  * by the IOCTL system call
  984. 12018  */
  985. 12019
  986. 12020   int r;
  987. 12021   union {
  988. 12022         int i;
  989. 12023         /* these non-Posix params are not used now, but the union is retained
  990. 12024          * to minimize code differences with backward compatible version
  991. 12025          * struct sgttyb sg;
  992. 12026          * struct tchars tc;
  993. 12027          */
  994. 12028   } param;
  995. 12029   phys_bytes user_phys;
  996. 12030   size_t size;
  997. 12031
  998. 12032   /* Size of the ioctl parameter. */
  999. 12033   switch (m_ptr->TTY_REQUEST) {
  1000. 12034     case TCGETS:        /* Posix tcgetattr function */
  1001. .Op 161 src/kernel/tty.c
  1002. 12035     case TCSETS:        /* Posix tcsetattr function, TCSANOW option */ 
  1003. 12036     case TCSETSW:       /* Posix tcsetattr function, TCSADRAIN option */
  1004. 12037     case TCSETSF:       /* Posix tcsetattr function, TCSAFLUSH option */
  1005. 12038         size = sizeof(struct termios);
  1006. 12039         break;
  1007. 12040
  1008. 12041     case TCSBRK:        /* Posix tcsendbreak function */
  1009. 12042     case TCFLOW:        /* Posix tcflow function */
  1010. 12043     case TCFLSH:        /* Posix tcflush function */
  1011. 12044     case TIOCGPGRP:     /* Posix tcgetpgrp function */
  1012. 12045     case TIOCSPGRP:     /* Posix tcsetpgrp function */
  1013. 12046         size = sizeof(int);
  1014. 12047         break;
  1015. 12048
  1016. 12049     case TIOCGWINSZ:    /* get window size (not Posix) */
  1017. 12050     case TIOCSWINSZ:    /* set window size (not Posix) */
  1018. 12051         size = sizeof(struct winsize);
  1019. 12052         break;
  1020. 12053
  1021. 12054     case KIOCSMAP:      /* load keymap (Minix extension) */
  1022. 12055         size = sizeof(keymap_t);
  1023. 12056         break;
  1024. 12057
  1025. 12058     case TIOCSFON:      /* load font (Minix extension) */
  1026. 12059         size = sizeof(u8_t [8192]);
  1027. 12060         break;
  1028. 12061
  1029. 12062     case TCDRAIN:       /* Posix tcdrain function -- no parameter */
  1030. 12063     default:            size = 0;
  1031. 12064   }
  1032. 12065
  1033. 12066   if (size != 0) {
  1034. 12067         user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, size);
  1035. 12068         if (user_phys == 0) {
  1036. 12069                 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EFAULT);
  1037. 12070                 return;
  1038. 12071         }
  1039. 12072   }
  1040. 12073
  1041. 12074   r = OK;
  1042. 12075   switch (m_ptr->TTY_REQUEST) {
  1043. 12076     case TCGETS:
  1044. 12077         /* Get the termios attributes. */
  1045. 12078         phys_copy(vir2phys(&tp->tty_termios), user_phys, (phys_bytes) size);
  1046. 12079         break;
  1047. 12080
  1048. 12081     case TCSETSW:
  1049. 12082     case TCSETSF:
  1050. 12083     case TCDRAIN:
  1051. 12084         if (tp->tty_outleft > 0) {
  1052. 12085                 /* Wait for all ongoing output processing to finish. */
  1053. 12086                 tp->tty_iocaller = m_ptr->m_source;
  1054. 12087                 tp->tty_ioproc = m_ptr->PROC_NR;
  1055. 12088                 tp->tty_ioreq = m_ptr->REQUEST;
  1056. 12089                 tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
  1057. 12090                 r = SUSPEND;
  1058. 12091                 break;
  1059. 12092         }
  1060. 12093         if (m_ptr->TTY_REQUEST == TCDRAIN) break;
  1061. 12094         if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
  1062. .Ep 162 src/kernel/tty.c
  1063. 12095         /*FALL THROUGH*/
  1064. 12096     case TCSETS:
  1065. 12097         /* Set the termios attributes. */
  1066. 12098         phys_copy(user_phys, vir2phys(&tp->tty_termios), (phys_bytes) size);
  1067. 12099         setattr(tp);
  1068. 12100         break;
  1069. 12101
  1070. 12102     case TCFLSH:
  1071. 12103         phys_copy(user_phys, vir2phys(&param.i), (phys_bytes) size);
  1072. 12104         switch (param.i) {
  1073. 12105             case TCIFLUSH:      tty_icancel(tp);                        break;
  1074. 12106             case TCOFLUSH:      (*tp->tty_ocancel)(tp);                 break;
  1075. 12107             case TCIOFLUSH:     tty_icancel(tp); (*tp->tty_ocancel)(tp);break;
  1076. 12108             default:            r = EINVAL;
  1077. 12109         }
  1078. 12110         break;
  1079. 12111
  1080. 12112     case TCFLOW:
  1081. 12113         phys_copy(user_phys, vir2phys(&param.i), (phys_bytes) size);
  1082. 12114         switch (param.i) {
  1083. 12115             case TCOOFF:
  1084. 12116             case TCOON:
  1085. 12117                 tp->tty_inhibited = (param.i == TCOOFF);
  1086. 12118                 tp->tty_events = 1;
  1087. 12119                 break;
  1088. 12120             case TCIOFF:
  1089. 12121                 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]);
  1090. 12122                 break;
  1091. 12123             case TCION:
  1092. 12124                 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]);
  1093. 12125                 break;
  1094. 12126             default:
  1095. 12127                 r = EINVAL;
  1096. 12128         }
  1097. 12129         break;
  1098. 12130
  1099. 12131     case TCSBRK:
  1100. 12132         if (tp->tty_break != NULL) (*tp->tty_break)(tp);
  1101. 12133         break;
  1102. 12134
  1103. 12135     case TIOCGWINSZ:
  1104. 12136         phys_copy(vir2phys(&tp->tty_winsize), user_phys, (phys_bytes) size);
  1105. 12137         break;
  1106. 12138
  1107. 12139     case TIOCSWINSZ:
  1108. 12140         phys_copy(user_phys, vir2phys(&tp->tty_winsize), (phys_bytes) size);
  1109. 12141         /* SIGWINCH... */
  1110. 12142         break;
  1111. 12143
  1112. 12144     case KIOCSMAP:
  1113. 12145         /* Load a new keymap (only /dev/console). */
  1114. 12146         if (isconsole(tp)) r = kbd_loadmap(user_phys);
  1115. 12147         break;
  1116. 12148
  1117. 12149     case TIOCSFON:
  1118. 12150         /* Load a font into an EGA or VGA card (hs@hck.hr) */
  1119. 12151         if (isconsole(tp)) r = con_loadfont(user_phys);
  1120. 12152         break;
  1121. 12153
  1122. 12154 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is 
  1123. .Op 163 src/kernel/tty.c
  1124. 12155  * not defined.
  1125. 12156  */
  1126. 12157     case TIOCGPGRP:     
  1127. 12158     case TIOCSPGRP:     
  1128. 12159     default:
  1129. 12160         r = ENOTTY;
  1130. 12161   }
  1131. 12162
  1132. 12163   /* Send the reply. */
  1133. 12164   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
  1134. 12165 }
  1135. 12168 /*===========================================================================*
  1136. 12169  *                              do_open                                      *
  1137. 12170  *===========================================================================*/
  1138. 12171 PRIVATE void do_open(tp, m_ptr)
  1139. 12172 register tty_t *tp;
  1140. 12173 message *m_ptr;                 /* pointer to message sent to task */
  1141. 12174 {
  1142. 12175 /* A tty line has been opened.  Make it the callers controlling tty if
  1143. 12176  * O_NOCTTY is *not* set and it is not the log device.  1 is returned if
  1144. 12177  * the tty is made the controlling tty, otherwise OK or an error code.
  1145. 12178  */
  1146. 12179   int r = OK;
  1147. 12180
  1148. 12181   if (m_ptr->TTY_LINE == LOG_MINOR) {
  1149. 12182         /* The log device is a write-only diagnostics device. */
  1150. 12183         if (m_ptr->COUNT & R_BIT) r = EACCES;
  1151. 12184   } else {
  1152. 12185         if (!(m_ptr->COUNT & O_NOCTTY)) {
  1153. 12186                 tp->tty_pgrp = m_ptr->PROC_NR;
  1154. 12187                 r = 1;
  1155. 12188         }
  1156. 12189         tp->tty_openct++;
  1157. 12190   }
  1158. 12191   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
  1159. 12192 }
  1160. 12195 /*===========================================================================*
  1161. 12196  *                              do_close                                     *
  1162. 12197  *===========================================================================*/
  1163. 12198 PRIVATE void do_close(tp, m_ptr)
  1164. 12199 register tty_t *tp;
  1165. 12200 message *m_ptr;                 /* pointer to message sent to task */
  1166. 12201 {
  1167. 12202 /* A tty line has been closed.  Clean up the line if it is the last close. */
  1168. 12203
  1169. 12204   if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
  1170. 12205         tp->tty_pgrp = 0;
  1171. 12206         tty_icancel(tp);
  1172. 12207         (*tp->tty_ocancel)(tp);
  1173. 12208         (*tp->tty_close)(tp);
  1174. 12209         tp->tty_termios = termios_defaults;
  1175. 12210         tp->tty_winsize = winsize_defaults;
  1176. 12211         setattr(tp);
  1177. 12212   }
  1178. 12213   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
  1179. 12214 }
  1180. .Ep 164 src/kernel/tty.c
  1181. 12217 /*===========================================================================*
  1182. 12218  *                              do_cancel                                    *
  1183. 12219  *===========================================================================*/
  1184. 12220 PRIVATE void do_cancel(tp, m_ptr)
  1185. 12221 register tty_t *tp;
  1186. 12222 message *m_ptr;                 /* pointer to message sent to task */
  1187. 12223 {
  1188. 12224 /* A signal has been sent to a process that is hanging trying to read or write.
  1189. 12225  * The pending read or write must be finished off immediately.
  1190. 12226  */
  1191. 12227
  1192. 12228   int proc_nr;
  1193. 12229   int mode;
  1194. 12230
  1195. 12231   /* Check the parameters carefully, to avoid cancelling twice. */
  1196. 12232   proc_nr = m_ptr->PROC_NR;
  1197. 12233   mode = m_ptr->COUNT;
  1198. 12234   if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
  1199. 12235         /* Process was reading when killed.  Clean up input. */
  1200. 12236         tty_icancel(tp);
  1201. 12237         tp->tty_inleft = tp->tty_incum = 0;
  1202. 12238   }
  1203. 12239   if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
  1204. 12240         /* Process was writing when killed.  Clean up output. */
  1205. 12241         (*tp->tty_ocancel)(tp);
  1206. 12242         tp->tty_outleft = tp->tty_outcum = 0;
  1207. 12243   }
  1208. 12244   if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
  1209. 12245         /* Process was waiting for output to drain. */
  1210. 12246         tp->tty_ioreq = 0;
  1211. 12247   }
  1212. 12248   tp->tty_events = 1;
  1213. 12249   tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
  1214. 12250 }
  1215. 12253 /*===========================================================================*
  1216. 12254  *                              handle_events                                *
  1217. 12255  *===========================================================================*/
  1218. 12256 PUBLIC void handle_events(tp)
  1219. 12257 tty_t *tp;                      /* TTY to check for events. */
  1220. 12258 {
  1221. 12259 /* Handle any events pending on a TTY.  These events are usually device
  1222. 12260  * interrupts.
  1223. 12261  *
  1224. 12262  * Two kinds of events are prominent:
  1225. 12263  *      - a character has been received from the console or an RS232 line.
  1226. 12264  *      - an RS232 line has completed a write request (on behalf of a user).
  1227. 12265  * The interrupt handler may delay the interrupt message at its discretion
  1228. 12266  * to avoid swamping the TTY task.  Messages may be overwritten when the
  1229. 12267  * lines are fast or when there are races between different lines, input
  1230. 12268  * and output, because MINIX only provides single buffering for interrupt
  1231. 12269  * messages (in proc.c).  This is handled by explicitly checking each line
  1232. 12270  * for fresh input and completed output on each interrupt.
  1233. 12271  */
  1234. 12272   char *buf;
  1235. 12273   unsigned count;
  1236. 12274
  1237. .Op 165 src/kernel/tty.c
  1238. 12275   do {
  1239. 12276         tp->tty_events = 0;
  1240. 12277
  1241. 12278         /* Read input and perform input processing. */
  1242. 12279         (*tp->tty_devread)(tp);
  1243. 12280
  1244. 12281         /* Perform output processing and write output. */
  1245. 12282         (*tp->tty_devwrite)(tp);
  1246. 12283
  1247. 12284         /* Ioctl waiting for some event? */
  1248. 12285         if (tp->tty_ioreq != 0) dev_ioctl(tp);
  1249. 12286   } while (tp->tty_events);
  1250. 12287
  1251. 12288   /* Transfer characters from the input queue to a waiting process. */
  1252. 12289   in_transfer(tp);
  1253. 12290
  1254. 12291   /* Reply if enough bytes are available. */
  1255. 12292   if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
  1256. 12293         tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
  1257. 12294                                                                 tp->tty_incum);
  1258. 12295         tp->tty_inleft = tp->tty_incum = 0;
  1259. 12296   }
  1260. 12297 }
  1261. 12300 /*===========================================================================*
  1262. 12301  *                              in_transfer                                  *
  1263. 12302  *===========================================================================*/
  1264. 12303 PRIVATE void in_transfer(tp)
  1265. 12304 register tty_t *tp;             /* pointer to terminal to read from */
  1266. 12305 {
  1267. 12306 /* Transfer bytes from the input queue to a process reading from a terminal. */
  1268. 12307
  1269. 12308   int ch;
  1270. 12309   int count;
  1271. 12310   phys_bytes buf_phys, user_base;
  1272. 12311   char buf[64], *bp;
  1273. 12312
  1274. 12313   /* Anything to do? */
  1275. 12314   if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return;
  1276. 12315
  1277. 12316   buf_phys = vir2phys(buf);
  1278. 12317   user_base = proc_vir2phys(proc_addr(tp->tty_inproc), 0);
  1279. 12318   bp = buf;
  1280. 12319   while (tp->tty_inleft > 0 && tp->tty_eotct > 0) {
  1281. 12320         ch = *tp->tty_intail;
  1282. 12321
  1283. 12322         if (!(ch & IN_EOF)) {
  1284. 12323                 /* One character to be delivered to the user. */
  1285. 12324                 *bp = ch & IN_CHAR;
  1286. 12325                 tp->tty_inleft--;
  1287. 12326                 if (++bp == bufend(buf)) {
  1288. 12327                         /* Temp buffer full, copy to user space. */
  1289. 12328                         phys_copy(buf_phys, user_base + tp->tty_in_vir,
  1290. 12329                                                 (phys_bytes) buflen(buf));
  1291. 12330                         tp->tty_in_vir += buflen(buf);
  1292. 12331                         tp->tty_incum += buflen(buf);
  1293. 12332                         bp = buf;
  1294. 12333                 }
  1295. 12334         }
  1296. .Ep 166 src/kernel/tty.c
  1297. 12335
  1298. 12336         /* Remove the character from the input queue. */
  1299. 12337         if (++tp->tty_intail == bufend(tp->tty_inbuf))
  1300. 12338                 tp->tty_intail = tp->tty_inbuf;
  1301. 12339         tp->tty_incount--;
  1302. 12340         if (ch & IN_EOT) {
  1303. 12341                 tp->tty_eotct--;
  1304. 12342                 /* Don't read past a line break in canonical mode. */
  1305. 12343                 if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0;
  1306. 12344         }
  1307. 12345   }
  1308. 12346
  1309. 12347   if (bp > buf) {
  1310. 12348         /* Leftover characters in the buffer. */
  1311. 12349         count = bp - buf;
  1312. 12350         phys_copy(buf_phys, user_base + tp->tty_in_vir, (phys_bytes) count);
  1313. 12351         tp->tty_in_vir += count;
  1314. 12352         tp->tty_incum += count;
  1315. 12353   }
  1316. 12354
  1317. 12355   /* Usually reply to the reader, possibly even if incum == 0 (EOF). */
  1318. 12356   if (tp->tty_inleft == 0) {
  1319. 12357         tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
  1320. 12358                                                                 tp->tty_incum);
  1321. 12359         tp->tty_inleft = tp->tty_incum = 0;
  1322. 12360   }
  1323. 12361 }
  1324. 12364 /*===========================================================================*
  1325. 12365  *                              in_process                                   *
  1326. 12366  *===========================================================================*/
  1327. 12367 PUBLIC int in_process(tp, buf, count)
  1328. 12368 register tty_t *tp;             /* terminal on which character has arrived */
  1329. 12369 char *buf;                      /* buffer with input characters */
  1330. 12370 int count;                      /* number of input characters */
  1331. 12371 {
  1332. 12372 /* Characters have just been typed in.  Process, save, and echo them.  Return
  1333. 12373  * the number of characters processed.
  1334. 12374  */
  1335. 12375
  1336. 12376   int ch, sig, ct;
  1337. 12377   int timeset = FALSE;
  1338. 12378   static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF };
  1339. 12379
  1340. 12380   for (ct = 0; ct < count; ct++) {
  1341. 12381         /* Take one character. */
  1342. 12382         ch = *buf++ & BYTE;
  1343. 12383
  1344. 12384         /* Strip to seven bits? */
  1345. 12385         if (tp->tty_termios.c_iflag & ISTRIP) ch &= 0x7F;
  1346. 12386
  1347. 12387         /* Input extensions? */
  1348. 12388         if (tp->tty_termios.c_lflag & IEXTEN) {
  1349. 12389
  1350. 12390                 /* Previous character was a character escape? */
  1351. 12391                 if (tp->tty_escaped) {
  1352. 12392                         tp->tty_escaped = NOT_ESCAPED;
  1353. 12393                         ch |= IN_ESC;   /* protect character */
  1354. 12394                 }
  1355. .Op 167 src/kernel/tty.c
  1356. 12395
  1357. 12396                 /* LNEXT (^V) to escape the next character? */
  1358. 12397                 if (ch == tp->tty_termios.c_cc[VLNEXT]) {
  1359. 12398                         tp->tty_escaped = ESCAPED;
  1360. 12399                         rawecho(tp, '^');
  1361. 12400                         rawecho(tp, 'b');
  1362. 12401                         continue;       /* do not store the escape */
  1363. 12402                 }
  1364. 12403
  1365. 12404                 /* REPRINT (^R) to reprint echoed characters? */
  1366. 12405                 if (ch == tp->tty_termios.c_cc[VREPRINT]) {
  1367. 12406                         reprint(tp);
  1368. 12407                         continue;
  1369. 12408                 }
  1370. 12409         }
  1371. 12410
  1372. 12411         /* _POSIX_VDISABLE is a normal character value, so better escape it. */
  1373. 12412         if (ch == _POSIX_VDISABLE) ch |= IN_ESC;
  1374. 12413
  1375. 12414         /* Map CR to LF, ignore CR, or map LF to CR. */
  1376. 12415         if (ch == 'r') {
  1377. 12416                 if (tp->tty_termios.c_iflag & IGNCR) continue;
  1378. 12417                 if (tp->tty_termios.c_iflag & ICRNL) ch = 'n';
  1379. 12418         } else
  1380. 12419         if (ch == 'n') {
  1381. 12420                 if (tp->tty_termios.c_iflag & INLCR) ch = 'r';
  1382. 12421         }
  1383. 12422
  1384. 12423         /* Canonical mode? */
  1385. 12424         if (tp->tty_termios.c_lflag & ICANON) {
  1386. 12425
  1387. 12426                 /* Erase processing (rub out of last character). */
  1388. 12427                 if (ch == tp->tty_termios.c_cc[VERASE]) {
  1389. 12428                         (void) back_over(tp);
  1390. 12429                         if (!(tp->tty_termios.c_lflag & ECHOE)) {
  1391. 12430                                 (void) echo(tp, ch);
  1392. 12431                         }
  1393. 12432                         continue;
  1394. 12433                 }
  1395. 12434
  1396. 12435                 /* Kill processing (remove current line). */
  1397. 12436                 if (ch == tp->tty_termios.c_cc[VKILL]) {
  1398. 12437                         while (back_over(tp)) {}
  1399. 12438                         if (!(tp->tty_termios.c_lflag & ECHOE)) {
  1400. 12439                                 (void) echo(tp, ch);
  1401. 12440                                 if (tp->tty_termios.c_lflag & ECHOK)
  1402. 12441                                         rawecho(tp, 'n');
  1403. 12442                         }
  1404. 12443                         continue;
  1405. 12444                 }
  1406. 12445
  1407. 12446                 /* EOF (^D) means end-of-file, an invisible "line break". */
  1408. 12447                 if (ch == tp->tty_termios.c_cc[VEOF]) ch |= IN_EOT | IN_EOF;
  1409. 12448
  1410. 12449                 /* The line may be returned to the user after an LF. */
  1411. 12450                 if (ch == 'n') ch |= IN_EOT;
  1412. 12451
  1413. 12452                 /* Same thing with EOL, whatever it may be. */
  1414. 12453                 if (ch == tp->tty_termios.c_cc[VEOL]) ch |= IN_EOT;
  1415. 12454         }
  1416. .Ep 168 src/kernel/tty.c
  1417. 12455
  1418. 12456         /* Start/stop input control? */
  1419. 12457         if (tp->tty_termios.c_iflag & IXON) {
  1420. 12458
  1421. 12459                 /* Output stops on STOP (^S). */
  1422. 12460                 if (ch == tp->tty_termios.c_cc[VSTOP]) {
  1423. 12461                         tp->tty_inhibited = STOPPED;
  1424. 12462                         tp->tty_events = 1;
  1425. 12463                         continue;
  1426. 12464                 }
  1427. 12465
  1428. 12466                 /* Output restarts on START (^Q) or any character if IXANY. */
  1429. 12467                 if (tp->tty_inhibited) {
  1430. 12468                         if (ch == tp->tty_termios.c_cc[VSTART]
  1431. 12469                                         || (tp->tty_termios.c_iflag & IXANY)) {
  1432. 12470                                 tp->tty_inhibited = RUNNING;
  1433. 12471                                 tp->tty_events = 1;
  1434. 12472                                 if (ch == tp->tty_termios.c_cc[VSTART])
  1435. 12473                                         continue;
  1436. 12474                         }
  1437. 12475                 }
  1438. 12476         }
  1439. 12477
  1440. 12478         if (tp->tty_termios.c_lflag & ISIG) {
  1441. 12479                 /* Check for INTR (^?) and QUIT (^) characters. */
  1442. 12480                 if (ch == tp->tty_termios.c_cc[VINTR]
  1443. 12481                                         || ch == tp->tty_termios.c_cc[VQUIT]) {
  1444. 12482                         sig = SIGINT;
  1445. 12483                         if (ch == tp->tty_termios.c_cc[VQUIT]) sig = SIGQUIT;
  1446. 12484                         sigchar(tp, sig);
  1447. 12485                         (void) echo(tp, ch);
  1448. 12486                         continue;
  1449. 12487                 }
  1450. 12488         }
  1451. 12489
  1452. 12490         /* Is there space in the input buffer? */
  1453. 12491         if (tp->tty_incount == buflen(tp->tty_inbuf)) {
  1454. 12492                 /* No space; discard in canonical mode, keep in raw mode. */
  1455. 12493                 if (tp->tty_termios.c_lflag & ICANON) continue;
  1456. 12494                 break;
  1457. 12495         }
  1458. 12496
  1459. 12497         if (!(tp->tty_termios.c_lflag & ICANON)) {
  1460. 12498                 /* In raw mode all characters are "line breaks". */
  1461. 12499                 ch |= IN_EOT;
  1462. 12500
  1463. 12501                 /* Start an inter-byte timer? */
  1464. 12502                 if (!timeset && tp->tty_termios.c_cc[VMIN] > 0
  1465. 12503                                 && tp->tty_termios.c_cc[VTIME] > 0) {
  1466. 12504                         lock();
  1467. 12505                         settimer(tp, TRUE);
  1468. 12506                         unlock();
  1469. 12507                         timeset = TRUE;
  1470. 12508                 }
  1471. 12509         }
  1472. 12510
  1473. 12511         /* Perform the intricate function of echoing. */
  1474. 12512         if (tp->tty_termios.c_lflag & (ECHO|ECHONL)) ch = echo(tp, ch);
  1475. 12513
  1476. 12514         /* Save the character in the input queue. */
  1477. .Op 169 src/kernel/tty.c
  1478. 12515         *tp->tty_inhead++ = ch;
  1479. 12516         if (tp->tty_inhead == bufend(tp->tty_inbuf))
  1480. 12517                 tp->tty_inhead = tp->tty_inbuf;
  1481. 12518         tp->tty_incount++;
  1482. 12519         if (ch & IN_EOT) tp->tty_eotct++;
  1483. 12520
  1484. 12521         /* Try to finish input if the queue threatens to overflow. */
  1485. 12522         if (tp->tty_incount == buflen(tp->tty_inbuf)) in_transfer(tp);
  1486. 12523   }
  1487. 12524   return ct;
  1488. 12525 }
  1489. 12528 /*===========================================================================*
  1490. 12529  *                              echo                                         *
  1491. 12530  *===========================================================================*/
  1492. 12531 PRIVATE int echo(tp, ch)
  1493. 12532 register tty_t *tp;             /* terminal on which to echo */
  1494. 12533 register int ch;                /* pointer to character to echo */
  1495. 12534 {
  1496. 12535 /* Echo the character if echoing is on.  Some control characters are echoed
  1497. 12536  * with their normal effect, other control characters are echoed as "^X",
  1498. 12537  * normal characters are echoed normally.  EOF (^D) is echoed, but immediately
  1499. 12538  * backspaced over.  Return the character with the echoed length added to its
  1500. 12539  * attributes.
  1501. 12540  */
  1502. 12541   int len, rp;
  1503. 12542
  1504. 12543   ch &= ~IN_LEN;
  1505. 12544   if (!(tp->tty_termios.c_lflag & ECHO)) {
  1506. 12545         if (ch == ('n' | IN_EOT) && (tp->tty_termios.c_lflag
  1507. 12546                                         & (ICANON|ECHONL)) == (ICANON|ECHONL))
  1508. 12547                 (*tp->tty_echo)(tp, 'n');
  1509. 12548         return(ch);
  1510. 12549   }
  1511. 12550
  1512. 12551   /* "Reprint" tells if the echo output has been messed up by other output. */
  1513. 12552   rp = tp->tty_incount == 0 ? FALSE : tp->tty_reprint;
  1514. 12553
  1515. 12554   if ((ch & IN_CHAR) < ' ') {
  1516. 12555         switch (ch & (IN_ESC|IN_EOF|IN_EOT|IN_CHAR)) {
  1517. 12556             case 't':
  1518. 12557                 len = 0;
  1519. 12558                 do {
  1520. 12559                         (*tp->tty_echo)(tp, ' ');
  1521. 12560                         len++;
  1522. 12561                 } while (len < TAB_SIZE && (tp->tty_position & TAB_MASK) != 0);
  1523. 12562                 break;
  1524. 12563             case 'r' | IN_EOT:
  1525. 12564             case 'n' | IN_EOT:
  1526. 12565                 (*tp->tty_echo)(tp, ch & IN_CHAR);
  1527. 12566                 len = 0;
  1528. 12567                 break;
  1529. 12568             default:
  1530. 12569                 (*tp->tty_echo)(tp, '^');
  1531. 12570                 (*tp->tty_echo)(tp, '@' + (ch & IN_CHAR));
  1532. 12571                 len = 2;
  1533. 12572         }
  1534. 12573   } else
  1535. 12574   if ((ch & IN_CHAR) == '177') {
  1536. .Ep 170 src/kernel/tty.c
  1537. 12575         /* A DEL prints as "^?". */
  1538. 12576         (*tp->tty_echo)(tp, '^');
  1539. 12577         (*tp->tty_echo)(tp, '?');
  1540. 12578         len = 2;
  1541. 12579   } else {
  1542. 12580         (*tp->tty_echo)(tp, ch & IN_CHAR);
  1543. 12581         len = 1;
  1544. 12582   }
  1545. 12583   if (ch & IN_EOF) while (len > 0) { (*tp->tty_echo)(tp, 'b'); len--; }
  1546. 12584
  1547. 12585   tp->tty_reprint = rp;
  1548. 12586   return(ch | (len << IN_LSHIFT));
  1549. 12587 }
  1550. 12590 /*==========================================================================*
  1551. 12591  *                              rawecho                                     *
  1552. 12592  *==========================================================================*/
  1553. 12593 PRIVATE void rawecho(tp, ch)
  1554. 12594 register tty_t *tp;
  1555. 12595 int ch;
  1556. 12596 {
  1557. 12597 /* Echo without interpretation if ECHO is set. */
  1558. 12598   int rp = tp->tty_reprint;
  1559. 12599   if (tp->tty_termios.c_lflag & ECHO) (*tp->tty_echo)(tp, ch);
  1560. 12600   tp->tty_reprint = rp;
  1561. 12601 }
  1562. 12604 /*==========================================================================*
  1563. 12605  *                              back_over                                   *
  1564. 12606  *==========================================================================*/
  1565. 12607 PRIVATE int back_over(tp)
  1566. 12608 register tty_t *tp;
  1567. 12609 {
  1568. 12610 /* Backspace to previous character on screen and erase it. */
  1569. 12611   u16_t *head;
  1570. 12612   int len;
  1571. 12613
  1572. 12614   if (tp->tty_incount == 0) return(0);  /* queue empty */
  1573. 12615   head = tp->tty_inhead;
  1574. 12616   if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
  1575. 12617   if (*--head & IN_EOT) return(0);              /* can't erase "line breaks" */
  1576. 12618   if (tp->tty_reprint) reprint(tp);             /* reprint if messed up */
  1577. 12619   tp->tty_inhead = head;
  1578. 12620   tp->tty_incount--;
  1579. 12621   if (tp->tty_termios.c_lflag & ECHOE) {
  1580. 12622         len = (*head & IN_LEN) >> IN_LSHIFT;
  1581. 12623         while (len > 0) {
  1582. 12624                 rawecho(tp, 'b');
  1583. 12625                 rawecho(tp, ' ');
  1584. 12626                 rawecho(tp, 'b');
  1585. 12627                 len--;
  1586. 12628         }
  1587. 12629   }
  1588. 12630   return(1);                            /* one character erased */
  1589. 12631 }
  1590. 12634 /*==========================================================================*
  1591. .Op 171 src/kernel/tty.c
  1592. 12635  *                              reprint                                     *
  1593. 12636  *==========================================================================*/
  1594. 12637 PRIVATE void reprint(tp)
  1595. 12638 register tty_t *tp;             /* pointer to tty struct */
  1596. 12639 {
  1597. 12640 /* Restore what has been echoed to screen before if the user input has been
  1598. 12641  * messed up by output, or if REPRINT (^R) is typed.
  1599. 12642  */
  1600. 12643   int count;
  1601. 12644   u16_t *head;
  1602. 12645
  1603. 12646   tp->tty_reprint = FALSE;
  1604. 12647
  1605. 12648   /* Find the last line break in the input. */
  1606. 12649   head = tp->tty_inhead;
  1607. 12650   count = tp->tty_incount;
  1608. 12651   while (count > 0) {
  1609. 12652         if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
  1610. 12653         if (head[-1] & IN_EOT) break;
  1611. 12654         head--;
  1612. 12655         count--;
  1613. 12656   }
  1614. 12657   if (count == tp->tty_incount) return;         /* no reason to reprint */
  1615. 12658
  1616. 12659   /* Show REPRINT (^R) and move to a new line. */
  1617. 12660   (void) echo(tp, tp->tty_termios.c_cc[VREPRINT] | IN_ESC);
  1618. 12661   rawecho(tp, 'r');
  1619. 12662   rawecho(tp, 'n');
  1620. 12663
  1621. 12664   /* Reprint from the last break onwards. */
  1622. 12665   do {
  1623. 12666         if (head == bufend(tp->tty_inbuf)) head = tp->tty_inbuf;
  1624. 12667         *head = echo(tp, *head);
  1625. 12668         head++;
  1626. 12669         count++;
  1627. 12670   } while (count < tp->tty_incount);
  1628. 12671 }
  1629. 12674 /*==========================================================================*
  1630. 12675  *                              out_process                                 *
  1631. 12676  *==========================================================================*/
  1632. 12677 PUBLIC void out_process(tp, bstart, bpos, bend, icount, ocount)
  1633. 12678 tty_t *tp;
  1634. 12679 char *bstart, *bpos, *bend;     /* start/pos/end of circular buffer */
  1635. 12680 int *icount;                    /* # input chars / input chars used */
  1636. 12681 int *ocount;                    /* max output chars / output chars used */
  1637. 12682 {
  1638. 12683 /* Perform output processing on a circular buffer.  *icount is the number of
  1639. 12684  * bytes to process, and the number of bytes actually processed on return.
  1640. 12685  * *ocount is the space available on input and the space used on output.
  1641. 12686  * (Naturally *icount < *ocount.)  The column position is updated modulo
  1642. 12687  * the TAB size, because we really only need it for tabs.
  1643. 12688  */
  1644. 12689
  1645. 12690   int tablen;
  1646. 12691   int ict = *icount;
  1647. 12692   int oct = *ocount;
  1648. 12693   int pos = tp->tty_position;
  1649. 12694
  1650. .Ep 172 src/kernel/tty.c
  1651. 12695   while (ict > 0) {
  1652. 12696         switch (*bpos) {
  1653. 12697         case '7':
  1654. 12698                 break;
  1655. 12699         case 'b':
  1656. 12700                 pos--;
  1657. 12701                 break;
  1658. 12702         case 'r':
  1659. 12703                 pos = 0;
  1660. 12704                 break;
  1661. 12705         case 'n':
  1662. 12706                 if ((tp->tty_termios.c_oflag & (OPOST|ONLCR))
  1663. 12707                                                         == (OPOST|ONLCR)) {
  1664. 12708                         /* Map LF to CR+LF if there is space.  Note that the
  1665. 12709                          * next character in the buffer is overwritten, so
  1666. 12710                          * we stop at this point.
  1667. 12711                          */
  1668. 12712                         if (oct >= 2) {
  1669. 12713                                 *bpos = 'r';
  1670. 12714                                 if (++bpos == bend) bpos = bstart;
  1671. 12715                                 *bpos = 'n';
  1672. 12716                                 pos = 0;
  1673. 12717                                 ict--;
  1674. 12718                                 oct -= 2;
  1675. 12719                         }
  1676. 12720                         goto out_done;  /* no space or buffer got changed */
  1677. 12721                 }
  1678. 12722                 break;
  1679. 12723         case 't':
  1680. 12724                 /* Best guess for the tab length. */
  1681. 12725                 tablen = TAB_SIZE - (pos & TAB_MASK);
  1682. 12726
  1683. 12727                 if ((tp->tty_termios.c_oflag & (OPOST|XTABS))
  1684. 12728                                                         == (OPOST|XTABS)) {
  1685. 12729                         /* Tabs must be expanded. */
  1686. 12730                         if (oct >= tablen) {
  1687. 12731                                 pos += tablen;
  1688. 12732                                 ict--;
  1689. 12733                                 oct -= tablen;
  1690. 12734                                 do {
  1691. 12735                                         *bpos = ' ';
  1692. 12736                                         if (++bpos == bend) bpos = bstart;
  1693. 12737                                 } while (--tablen != 0);
  1694. 12738                         }
  1695. 12739                         goto out_done;
  1696. 12740                 }
  1697. 12741                 /* Tabs are output directly. */
  1698. 12742                 pos += tablen;
  1699. 12743                 break;
  1700. 12744         default:
  1701. 12745                 /* Assume any other character prints as one character. */
  1702. 12746                 pos++;
  1703. 12747         }
  1704. 12748         if (++bpos == bend) bpos = bstart;
  1705. 12749         ict--;
  1706. 12750         oct--;
  1707. 12751   }
  1708. 12752 out_done:
  1709. 12753   tp->tty_position = pos & TAB_MASK;
  1710. 12754
  1711. .Op 173 src/kernel/tty.c
  1712. 12755   *icount -= ict;       /* [io]ct are the number of chars not used */
  1713. 12756   *ocount -= oct;       /* *[io]count are the number of chars that are used */
  1714. 12757 }
  1715. 12760 /*===========================================================================*
  1716. 12761  *                              dev_ioctl                                    *
  1717. 12762  *===========================================================================*/
  1718. 12763 PRIVATE void dev_ioctl(tp)
  1719. 12764 tty_t *tp;
  1720. 12765 {
  1721. 12766 /* The ioctl's TCSETSW, TCSETSF and TCDRAIN wait for output to finish to make
  1722. 12767  * sure that an attribute change doesn't affect the processing of current
  1723. 12768  * output.  Once output finishes the ioctl is executed as in do_ioctl().
  1724. 12769  */
  1725. 12770   phys_bytes user_phys;
  1726. 12771
  1727. 12772   if (tp->tty_outleft > 0) return;              /* output not finished */
  1728. 12773
  1729. 12774   if (tp->tty_ioreq != TCDRAIN) {
  1730. 12775         if (tp->tty_ioreq == TCSETSF) tty_icancel(tp);
  1731. 12776         user_phys = proc_vir2phys(proc_addr(tp->tty_ioproc), tp->tty_iovir);
  1732. 12777         phys_copy(user_phys, vir2phys(&tp->tty_termios),
  1733. 12778                                         (phys_bytes) sizeof(tp->tty_termios));
  1734. 12779         setattr(tp);
  1735. 12780   }
  1736. 12781   tp->tty_ioreq = 0;
  1737. 12782   tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, OK);
  1738. 12783 }
  1739. 12786 /*===========================================================================*
  1740. 12787  *                              setattr                                      *
  1741. 12788  *===========================================================================*/
  1742. 12789 PRIVATE void setattr(tp)
  1743. 12790 tty_t *tp;
  1744. 12791 {
  1745. 12792 /* Apply the new line attributes (raw/canonical, line speed, etc.) */
  1746. 12793   u16_t *inp;
  1747. 12794   int count;
  1748. 12795
  1749. 12796   if (!(tp->tty_termios.c_lflag & ICANON)) {
  1750. 12797         /* Raw mode; put a "line break" on all characters in the input queue.
  1751. 12798          * It is undefined what happens to the input queue when ICANON is
  1752. 12799          * switched off, a process should use TCSAFLUSH to flush the queue.
  1753. 12800          * Keeping the queue to preserve typeahead is the Right Thing, however
  1754. 12801          * when a process does use TCSANOW to switch to raw mode.
  1755. 12802          */
  1756. 12803         count = tp->tty_eotct = tp->tty_incount;
  1757. 12804         inp = tp->tty_intail;
  1758. 12805         while (count > 0) {
  1759. 12806                 *inp |= IN_EOT;
  1760. 12807                 if (++inp == bufend(tp->tty_inbuf)) inp = tp->tty_inbuf;
  1761. 12808                 --count;
  1762. 12809         }
  1763. 12810   }
  1764. 12811
  1765. 12812   /* Inspect MIN and TIME. */
  1766. 12813   lock();
  1767. 12814   settimer(tp, FALSE);
  1768. .Ep 174 src/kernel/tty.c
  1769. 12815   unlock();
  1770. 12816   if (tp->tty_termios.c_lflag & ICANON) {
  1771. 12817         /* No MIN & TIME in canonical mode. */
  1772. 12818         tp->tty_min = 1;
  1773. 12819   } else {
  1774. 12820         /* In raw mode MIN is the number of chars wanted, and TIME how long
  1775. 12821          * to wait for them.  With interesting exceptions if either is zero.
  1776. 12822          */
  1777. 12823         tp->tty_min = tp->tty_termios.c_cc[VMIN];
  1778. 12824         if (tp->tty_min == 0 && tp->tty_termios.c_cc[VTIME] > 0)
  1779. 12825                 tp->tty_min = 1;
  1780. 12826   }
  1781. 12827
  1782. 12828   if (!(tp->tty_termios.c_iflag & IXON)) {
  1783. 12829         /* No start/stop output control, so don't leave output inhibited. */
  1784. 12830         tp->tty_inhibited = RUNNING;
  1785. 12831         tp->tty_events = 1;
  1786. 12832   }
  1787. 12833
  1788. 12834   /* Setting the output speed to zero hangs up the phone. */
  1789. 12835   if (tp->tty_termios.c_ospeed == B0) sigchar(tp, SIGHUP);
  1790. 12836
  1791. 12837   /* Set new line speed, character size, etc at the device level. */
  1792. 12838   (*tp->tty_ioctl)(tp);
  1793. 12839 }
  1794. 12842 /*===========================================================================*
  1795. 12843  *                              tty_reply                                    *
  1796. 12844  *===========================================================================*/
  1797. 12845 PUBLIC void tty_reply(code, replyee, proc_nr, status)
  1798. 12846 int code;                       /* TASK_REPLY or REVIVE */
  1799. 12847 int replyee;                    /* destination address for the reply */
  1800. 12848 int proc_nr;                    /* to whom should the reply go? */
  1801. 12849 int status;                     /* reply code */
  1802. 12850 {
  1803. 12851 /* Send a reply to a process that wanted to read or write data. */
  1804. 12852
  1805. 12853   message tty_mess;
  1806. 12854
  1807. 12855   tty_mess.m_type = code;
  1808. 12856   tty_mess.REP_PROC_NR = proc_nr;
  1809. 12857   tty_mess.REP_STATUS = status;
  1810. 12858   if ((status = send(replyee, &tty_mess)) != OK)
  1811. 12859         panic("tty_reply failed, statusn", status);
  1812. 12860 }
  1813. 12863 /*===========================================================================*
  1814. 12864  *                              sigchar                                      *
  1815. 12865  *===========================================================================*/
  1816. 12866 PUBLIC void sigchar(tp, sig)
  1817. 12867 register tty_t *tp;
  1818. 12868 int sig;                        /* SIGINT, SIGQUIT, SIGKILL or SIGHUP */
  1819. 12869 {
  1820. 12870 /* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard or SIGHUP from
  1821. 12871  * a tty close, "stty 0", or a real RS-232 hangup.  MM will send the signal to
  1822. 12872  * the process group (INT, QUIT), all processes (KILL), or the session leader
  1823. 12873  * (HUP).
  1824. 12874  */
  1825. .Op 175 src/kernel/tty.c
  1826. 12875
  1827. 12876   if (tp->tty_pgrp != 0) cause_sig(tp->tty_pgrp, sig);
  1828. 12877
  1829. 12878   if (!(tp->tty_termios.c_lflag & NOFLSH)) {
  1830. 12879         tp->tty_incount = tp->tty_eotct = 0;    /* kill earlier input */
  1831. 12880         tp->tty_intail = tp->tty_inhead;
  1832. 12881         (*tp->tty_ocancel)(tp);                 /* kill all output */
  1833. 12882         tp->tty_inhibited = RUNNING;
  1834. 12883         tp->tty_events = 1;
  1835. 12884   }
  1836. 12885 }
  1837. 12888 /*==========================================================================*
  1838. 12889  *                              tty_icancel                                 *
  1839. 12890  *==========================================================================*/
  1840. 12891 PRIVATE void tty_icancel(tp)
  1841. 12892 register tty_t *tp;
  1842. 12893 {
  1843. 12894 /* Discard all pending input, tty buffer or device. */
  1844. 12895
  1845. 12896   tp->tty_incount = tp->tty_eotct = 0;
  1846. 12897   tp->tty_intail = tp->tty_inhead;
  1847. 12898   (*tp->tty_icancel)(tp);
  1848. 12899 }
  1849. 12902 /*==========================================================================*
  1850. 12903  *                              tty_init                                    *
  1851. 12904  *==========================================================================*/
  1852. 12905 PRIVATE void tty_init(tp)
  1853. 12906 tty_t *tp;                      /* TTY line to initialize. */
  1854. 12907 {
  1855. 12908 /* Initialize tty structure and call device initialization routines. */
  1856. 12909
  1857. 12910   tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
  1858. 12911   tp->tty_min = 1;
  1859. 12912   tp->tty_termios = termios_defaults;
  1860. 12913   tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
  1861. 12914                                                                 tty_devnop;
  1862. 12915   if (tp < tty_addr(NR_CONS)) {
  1863. 12916         scr_init(tp);
  1864. 12917   } else
  1865. 12918   if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
  1866. 12919         rs_init(tp);
  1867. 12920   } else {
  1868. 12921         pty_init(tp);
  1869. 12922   }
  1870. 12923 }
  1871. 12926 /*==========================================================================*
  1872. 12927  *                              tty_wakeup                                  *
  1873. 12928  *==========================================================================*/
  1874. 12929 PUBLIC void tty_wakeup(now)
  1875. 12930 clock_t now;                            /* current time */
  1876. 12931 {
  1877. 12932 /* Wake up TTY when something interesting is happening on one of the terminal
  1878. 12933  * lines, like a character arriving on an RS232 line, a key being typed, or
  1879. 12934  * a timer on a line expiring by TIME.
  1880. .Ep 176 src/kernel/tty.c
  1881. 12935  */
  1882. 12936   tty_t *tp;
  1883. 12937
  1884. 12938   /* Scan the timerlist for expired timers and compute the next timeout time. */
  1885. 12939   tty_timeout = TIME_NEVER;
  1886. 12940   while ((tp = tty_timelist) != NULL) {
  1887. 12941         if (tp->tty_time > now) {
  1888. 12942                 tty_timeout = tp->tty_time;     /* this timer is next */
  1889. 12943                 break;
  1890. 12944         }
  1891. 12945         tp->tty_min = 0;                        /* force read to succeed */
  1892. 12946         tp->tty_events = 1;
  1893. 12947         tty_timelist = tp->tty_timenext;
  1894. 12948   }
  1895. 12949
  1896. 12950   /* Let TTY know there is something afoot. */
  1897. 12951   interrupt(TTY);
  1898. 12952 }
  1899. 12955 /*===========================================================================*
  1900. 12956  *                              settimer                                     *
  1901. 12957  *===========================================================================*/
  1902. 12958 PRIVATE void settimer(tp, on)
  1903. 12959 tty_t *tp;                      /* line to set or unset a timer on */
  1904. 12960 int on;                         /* set timer if true, otherwise unset */
  1905. 12961 {
  1906. 12962 /* Set or unset a TIME inspired timer.  This function is interrupt sensitive
  1907. 12963  * due to tty_wakeup(), so it must be called from within lock()/unlock().
  1908. 12964  */
  1909. 12965   tty_t **ptp;
  1910. 12966
  1911. 12967   /* Take tp out of the timerlist if present. */
  1912. 12968   for (ptp = &tty_timelist; *ptp != NULL; ptp = &(*ptp)->tty_timenext) {
  1913. 12969         if (tp == *ptp) {
  1914. 12970                 *ptp = tp->tty_timenext;        /* take tp out of the list */
  1915. 12971                 break;
  1916. 12972         }
  1917. 12973   }
  1918. 12974   if (!on) return;                              /* unsetting it is enough */
  1919. 12975
  1920. 12976   /* Timeout occurs TIME deciseconds from now. */
  1921. 12977   tp->tty_time = get_uptime() + tp->tty_termios.c_cc[VTIME] * (HZ/10);
  1922. 12978
  1923. 12979   /* Find a new place in the list. */
  1924. 12980   for (ptp = &tty_timelist; *ptp != NULL; ptp = &(*ptp)->tty_timenext) {
  1925. 12981         if (tp->tty_time <= (*ptp)->tty_time) break;
  1926. 12982   }
  1927. 12983   tp->tty_timenext = *ptp;
  1928. 12984   *ptp = tp;
  1929. 12985   if (tp->tty_time < tty_timeout) tty_timeout = tp->tty_time;
  1930. 12986 }
  1931. 12989 /*==========================================================================*
  1932. 12990  *                              tty_devnop                                  *
  1933. 12991  *==========================================================================*/
  1934. 12992 PUBLIC void tty_devnop(tp)
  1935. 12993 tty_t *tp;
  1936. 12994 {
  1937. .Op 177 src/kernel/tty.c
  1938. 12995   /* Some functions need not be implemented at the device level. */
  1939. 12996 }
  1940. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1941. src/kernel/keyboard.c    
  1942. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1943. 13000 /* Keyboard driver for PC's and AT's.
  1944. 13001  *
  1945. 13002  * Changed by Marcus Hampel     (04/02/1994)
  1946. 13003  *  - Loadable keymaps
  1947. 13004  */
  1948. 13005
  1949. 13006 #include "kernel.h"
  1950. 13007 #include <termios.h>
  1951. 13008 #include <signal.h>
  1952. 13009 #include <unistd.h>
  1953. 13010 #include <minix/callnr.h>
  1954. 13011 #include <minix/com.h>
  1955. 13012 #include <minix/keymap.h>
  1956. 13013 #include "tty.h"
  1957. 13014 #include "keymaps/us-std.src"
  1958. 13015
  1959. 13016 /* Standard and AT keyboard.  (PS/2 MCA implies AT throughout.) */
  1960. 13017 #define KEYBD           0x60    /* I/O port for keyboard data */
  1961. 13018
  1962. 13019 /* AT keyboard. */
  1963. 13020 #define KB_COMMAND      0x64    /* I/O port for commands on AT */
  1964. 13021 #define KB_GATE_A20     0x02    /* bit in output port to enable A20 line */
  1965. 13022 #define KB_PULSE_OUTPUT 0xF0    /* base for commands to pulse output port */
  1966. 13023 #define KB_RESET        0x01    /* bit in output port to reset CPU */
  1967. 13024 #define KB_STATUS       0x64    /* I/O port for status on AT */
  1968. 13025 #define KB_ACK          0xFA    /* keyboard ack response */
  1969. 13026 #define KB_BUSY         0x02    /* status bit set when KEYBD port ready */
  1970. 13027 #define LED_CODE        0xED    /* command to keyboard to set LEDs */
  1971. 13028 #define MAX_KB_ACK_RETRIES 0x1000       /* max #times to wait for kb ack */
  1972. 13029 #define MAX_KB_BUSY_RETRIES 0x1000      /* max #times to loop while kb busy */
  1973. 13030 #define KBIT            0x80    /* bit used to ack characters to keyboard */
  1974. 13031
  1975. 13032 /* Miscellaneous. */
  1976. 13033 #define ESC_SCAN           1    /* Reboot key when panicking */
  1977. 13034 #define SLASH_SCAN        53    /* to recognize numeric slash */
  1978. 13035 #define HOME_SCAN         71    /* first key on the numeric keypad */
  1979. 13036 #define DEL_SCAN          83    /* DEL for use in CTRL-ALT-DEL reboot */
  1980. 13037 #define CONSOLE            0    /* line number for console */
  1981. 13038 #define MEMCHECK_ADR   0x472    /* address to stop memory check after reboot */
  1982. 13039 #define MEMCHECK_MAG  0x1234    /* magic number to stop memory check */
  1983. 13040
  1984. 13041 #define kb_addr()       (&kb_lines[0])  /* there is only one keyboard */
  1985. 13042 #define KB_IN_BYTES       32    /* size of keyboard input buffer */
  1986. 13043
  1987. 13044 PRIVATE int alt1;               /* left alt key state */
  1988. 13045 PRIVATE int alt2;               /* right alt key state */
  1989. 13046 PRIVATE int capslock;           /* caps lock key state */
  1990. 13047 PRIVATE int esc;                /* escape scan code detected? */
  1991. 13048 PRIVATE int control;            /* control key state */
  1992. 13049 PRIVATE int caps_off;           /* 1 = normal position, 0 = depressed */
  1993. .Ep 178 src/kernel/keyboard.c
  1994. 13050 PRIVATE int numlock;            /* number lock key state */
  1995. 13051 PRIVATE int num_off;            /* 1 = normal position, 0 = depressed */
  1996. 13052 PRIVATE int slock;              /* scroll lock key state */
  1997. 13053 PRIVATE int slock_off;          /* 1 = normal position, 0 = depressed */
  1998. 13054 PRIVATE int shift;              /* shift key state */
  1999. 13055
  2000. 13056 PRIVATE char numpad_map[] =
  2001. 13057                 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
  2002. 13058
  2003. 13059 /* Keyboard structure, 1 per console. */
  2004. 13060 struct kb_s {
  2005. 13061   char *ihead;                  /* next free spot in input buffer */
  2006. 13062   char *itail;                  /* scan code to return to TTY */
  2007. 13063   int icount;                   /* # codes in buffer */
  2008. 13064   char ibuf[KB_IN_BYTES];       /* input buffer */
  2009. 13065 };
  2010. 13066
  2011. 13067 PRIVATE struct kb_s kb_lines[NR_CONS];
  2012. 13068
  2013. 13069 FORWARD _PROTOTYPE( int kb_ack, (void) );
  2014. 13070 FORWARD _PROTOTYPE( int kb_wait, (void) );
  2015. 13071 FORWARD _PROTOTYPE( int func_key, (int scode) );
  2016. 13072 FORWARD _PROTOTYPE( int scan_keyboard, (void) );
  2017. 13073 FORWARD _PROTOTYPE( unsigned make_break, (int scode) );
  2018. 13074 FORWARD _PROTOTYPE( void set_leds, (void) );
  2019. 13075 FORWARD _PROTOTYPE( int kbd_hw_int, (int irq) );
  2020. 13076 FORWARD _PROTOTYPE( void kb_read, (struct tty *tp) );
  2021. 13077 FORWARD _PROTOTYPE( unsigned map_key, (int scode) );
  2022. 13078
  2023. 13079
  2024. 13080 /*===========================================================================*
  2025. 13081  *                              map_key0                                     *
  2026. 13082  *===========================================================================*/
  2027. 13083 /* Map a scan code to an ASCII code ignoring modifiers. */
  2028. 13084 #define map_key0(scode)  
  2029. 13085         ((unsigned) keymap[(scode) * MAP_COLS])
  2030. 13086
  2031. 13087
  2032. 13088 /*===========================================================================*
  2033. 13089  *                              map_key                                      *
  2034. 13090  *===========================================================================*/
  2035. 13091 PRIVATE unsigned map_key(scode)
  2036. 13092 int scode;
  2037. 13093 {
  2038. 13094 /* Map a scan code to an ASCII code. */
  2039. 13095
  2040. 13096   int caps, column;
  2041. 13097   u16_t *keyrow;
  2042. 13098
  2043. 13099   if (scode == SLASH_SCAN && esc) return '/';   /* don't map numeric slash */
  2044. 13100
  2045. 13101   keyrow = &keymap[scode * MAP_COLS];
  2046. 13102
  2047. 13103   caps = shift;
  2048. 13104   if (numlock && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
  2049. 13105   if (capslock && (keyrow[0] & HASCAPS)) caps = !caps;
  2050. 13106
  2051. 13107   if (alt1 || alt2) {
  2052. 13108         column = 2;
  2053. 13109         if (control || alt2) column = 3;        /* Ctrl + Alt1 == Alt2 */
  2054. .Op 179 src/kernel/keyboard.c
  2055. 13110         if (caps) column = 4;
  2056. 13111   } else {
  2057. 13112         column = 0;
  2058. 13113         if (caps) column = 1;
  2059. 13114         if (control) column = 5;
  2060. 13115   }
  2061. 13116   return keyrow[column] & ~HASCAPS;
  2062. 13117 }
  2063. 13120 /*===========================================================================*
  2064. 13121  *                              kbd_hw_int                                   *
  2065. 13122  *===========================================================================*/
  2066. 13123 PRIVATE int kbd_hw_int(irq)
  2067. 13124 int irq;
  2068. 13125 {
  2069. 13126 /* A keyboard interrupt has occurred.  Process it. */
  2070. 13127
  2071. 13128   int code;
  2072. 13129   unsigned km;
  2073. 13130   register struct kb_s *kb;
  2074. 13131
  2075. 13132   /* Fetch the character from the keyboard hardware and acknowledge it. */
  2076. 13133   code = scan_keyboard();
  2077. 13134
  2078. 13135   /* The IBM keyboard interrupts twice per key, once when depressed, once when
  2079. 13136    * released.  Filter out the latter, ignoring all but the shift-type keys.
  2080. 13137    * The shift-type keys 29, 42, 54, 56, 58, and 69 must be processed normally.
  2081. 13138    */
  2082. 13139
  2083. 13140   if (code & 0200) {
  2084. 13141         /* A key has been released (high bit is set). */
  2085. 13142         km = map_key0(code & 0177);
  2086. 13143         if (km != CTRL && km != SHIFT && km != ALT && km != CALOCK
  2087. 13144                         && km != NLOCK && km != SLOCK && km != EXTKEY)
  2088. 13145                 return 1;
  2089. 13146   }
  2090. 13147
  2091. 13148   /* Store the character in memory so the task can get at it later. */
  2092. 13149   kb = kb_addr();
  2093. 13150   if (kb->icount < KB_IN_BYTES) {
  2094. 13151         *kb->ihead++ = code;
  2095. 13152         if (kb->ihead == kb->ibuf + KB_IN_BYTES) kb->ihead = kb->ibuf;
  2096. 13153         kb->icount++;
  2097. 13154         tty_table[current].tty_events = 1;
  2098. 13155         force_timeout();
  2099. 13156   }
  2100. 13157   /* Else it doesn't fit - discard it. */
  2101. 13158   return 1;     /* Reenable keyboard interrupt */
  2102. 13159 }
  2103. 13162 /*==========================================================================*
  2104. 13163  *                              kb_read                                     *
  2105. 13164  *==========================================================================*/
  2106. 13165 PRIVATE void kb_read(tp)
  2107. 13166 tty_t *tp;
  2108. 13167 {
  2109. 13168 /* Process characters from the circular keyboard buffer. */
  2110. 13169
  2111. .Ep 180 src/kernel/keyboard.c
  2112. 13170   struct kb_s *kb;
  2113. 13171   char buf[3];
  2114. 13172   int scode;
  2115. 13173   unsigned ch;
  2116. 13174
  2117. 13175   kb = kb_addr();
  2118. 13176   tp = &tty_table[current];             /* always use the current console */
  2119. 13177
  2120. 13178   while (kb->icount > 0) {
  2121. 13179         scode = *kb->itail++;                   /* take one key scan code */
  2122. 13180         if (kb->itail == kb->ibuf + KB_IN_BYTES) kb->itail = kb->ibuf;
  2123. 13181         lock();
  2124. 13182         kb->icount--;
  2125. 13183         unlock();
  2126. 13184
  2127. 13185         /* Function keys are being used for debug dumps. */
  2128. 13186         if (func_key(scode)) continue;
  2129. 13187
  2130. 13188         /* Perform make/break processing. */
  2131. 13189         ch = make_break(scode);
  2132. 13190
  2133. 13191         if (ch <= 0xFF) {
  2134. 13192                 /* A normal character. */
  2135. 13193                 buf[0] = ch;
  2136. 13194                 (void) in_process(tp, buf, 1);
  2137. 13195         } else
  2138. 13196         if (HOME <= ch && ch <= INSRT) {
  2139. 13197                 /* An ASCII escape sequence generated by the numeric pad. */
  2140. 13198                 buf[0] = ESC;
  2141. 13199                 buf[1] = '[';
  2142. 13200                 buf[2] = numpad_map[ch - HOME];
  2143. 13201                 (void) in_process(tp, buf, 3);
  2144. 13202         } else
  2145. 13203         if (ch == ALEFT) {
  2146. 13204                 /* Choose lower numbered console as current console. */
  2147. 13205                 select_console(current - 1);
  2148. 13206         } else
  2149. 13207         if (ch == ARIGHT) {
  2150. 13208                 /* Choose higher numbered console as current console. */
  2151. 13209                 select_console(current + 1);
  2152. 13210         } else
  2153. 13211         if (AF1 <= ch && ch <= AF12) {
  2154. 13212                 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
  2155. 13213                 select_console(ch - AF1);
  2156. 13214         }
  2157. 13215   }
  2158. 13216 }
  2159. 13219 /*===========================================================================*
  2160. 13220  *                              make_break                                   *
  2161. 13221  *===========================================================================*/
  2162. 13222 PRIVATE unsigned make_break(scode)
  2163. 13223 int scode;                      /* scan code of key just struck or released */
  2164. 13224 {
  2165. 13225 /* This routine can handle keyboards that interrupt only on key depression,
  2166. 13226  * as well as keyboards that interrupt on key depression and key release.
  2167. 13227  * For efficiency, the interrupt routine filters out most key releases.
  2168. 13228  */
  2169. 13229   int ch, make;
  2170. .Op 181 src/kernel/keyboard.c
  2171. 13230   static int CAD_count = 0;
  2172. 13231
  2173. 13232   /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
  2174. 13233    * be better done in keyboard() in case TTY is hung, except control and
  2175. 13234    * alt are set in the high level code.
  2176. 13235    */
  2177. 13236   if (control && (alt1 || alt2) && scode == DEL_SCAN)
  2178. 13237   {
  2179. 13238         if (++CAD_count == 3) wreboot(RBT_HALT);
  2180. 13239         cause_sig(INIT_PROC_NR, SIGABRT);
  2181. 13240         return -1;
  2182. 13241   }
  2183. 13242
  2184. 13243   /* High-order bit set on key release. */
  2185. 13244   make = (scode & 0200 ? 0 : 1);        /* 0 = release, 1 = press */
  2186. 13245
  2187. 13246   ch = map_key(scode & 0177);           /* map to ASCII */
  2188. 13247
  2189. 13248   switch (ch) {
  2190. 13249         case CTRL:
  2191. 13250                 control = make;
  2192. 13251                 ch = -1;
  2193. 13252                 break;
  2194. 13253         case SHIFT:
  2195. 13254                 shift = make;
  2196. 13255                 ch = -1;
  2197. 13256                 break;
  2198. 13257         case ALT:
  2199. 13258                 if (make) {
  2200. 13259                         if (esc) alt2 = 1; else alt1 = 1;
  2201. 13260                 } else {
  2202. 13261                         alt1 = alt2 = 0;
  2203. 13262                 }
  2204. 13263                 ch = -1;
  2205. 13264                 break;
  2206. 13265         case CALOCK:
  2207. 13266                 if (make && caps_off) {
  2208. 13267                         capslock = 1 - capslock;
  2209. 13268                         set_leds();
  2210. 13269                 }
  2211. 13270                 caps_off = 1 - make;
  2212. 13271                 ch = -1;
  2213. 13272                 break;
  2214. 13273         case NLOCK:
  2215. 13274                 if (make && num_off) {
  2216. 13275                         numlock = 1 - numlock;
  2217. 13276                         set_leds();
  2218. 13277                 }
  2219. 13278                 num_off = 1 - make;
  2220. 13279                 ch = -1;
  2221. 13280                 break;
  2222. 13281         case SLOCK:
  2223. 13282                 if (make & slock_off) {
  2224. 13283                         slock = 1 - slock;
  2225. 13284                         set_leds();
  2226. 13285                 }
  2227. 13286                 slock_off = 1 - make;
  2228. 13287                 ch = -1;
  2229. 13288                 break;
  2230. 13289         case EXTKEY:
  2231. .Ep 182 src/kernel/keyboard.c
  2232. 13290                 esc = 1;
  2233. 13291                 return(-1);
  2234. 13292         default:
  2235. 13293                 if (!make) ch = -1;
  2236. 13294   }
  2237. 13295   esc = 0;
  2238. 13296   return(ch);
  2239. 13297 }
  2240. 13300 /*===========================================================================*
  2241. 13301  *                              set_leds                                     *
  2242. 13302  *===========================================================================*/
  2243. 13303 PRIVATE void set_leds()
  2244. 13304 {
  2245. 13305 /* Set the LEDs on the caps lock and num lock keys */
  2246. 13306
  2247. 13307   unsigned leds;
  2248. 13308
  2249. 13309   if (!pc_at) return;   /* PC/XT doesn't have LEDs */
  2250. 13310
  2251. 13311   /* encode LED bits */
  2252. 13312   leds = (slock << 0) | (numlock << 1) | (capslock << 2);
  2253. 13313
  2254. 13314   kb_wait();                    /* wait for buffer empty  */
  2255. 13315   out_byte(KEYBD, LED_CODE);    /* prepare keyboard to accept LED values */
  2256. 13316   kb_ack();                     /* wait for ack response  */
  2257. 13317
  2258. 13318   kb_wait();                    /* wait for buffer empty  */
  2259. 13319   out_byte(KEYBD, leds);        /* give keyboard LED values */
  2260. 13320   kb_ack();                     /* wait for ack response  */
  2261. 13321 }
  2262. 13324 /*==========================================================================*
  2263. 13325  *                              kb_wait                                     *
  2264. 13326  *==========================================================================*/
  2265. 13327 PRIVATE int kb_wait()
  2266. 13328 {
  2267. 13329 /* Wait until the controller is ready; return zero if this times out. */
  2268. 13330
  2269. 13331   int retries;
  2270. 13332
  2271. 13333   retries = MAX_KB_BUSY_RETRIES + 1;
  2272. 13334   while (--retries != 0 && in_byte(KB_STATUS) & KB_BUSY)
  2273. 13335         ;                       /* wait until not busy */
  2274. 13336   return(retries);              /* nonzero if ready */
  2275. 13337 }
  2276. 13340 /*==========================================================================*
  2277. 13341  *                              kb_ack                                      *
  2278. 13342  *==========================================================================*/
  2279. 13343 PRIVATE int kb_ack()
  2280. 13344 {
  2281. 13345 /* Wait until kbd acknowledges last command; return zero if this times out. */
  2282. 13346
  2283. 13347   int retries;
  2284. 13348
  2285. 13349   retries = MAX_KB_ACK_RETRIES + 1;
  2286. .Op 183 src/kernel/keyboard.c
  2287. 13350   while (--retries != 0 && in_byte(KEYBD) != KB_ACK)
  2288. 13351         ;                       /* wait for ack */
  2289. 13352   return(retries);              /* nonzero if ack received */
  2290. 13353 }
  2291. 13356 /*===========================================================================*
  2292. 13357  *                              kb_init                                      *
  2293. 13358  *===========================================================================*/
  2294. 13359 PUBLIC void kb_init(tp)
  2295. 13360 tty_t *tp;
  2296. 13361 {
  2297. 13362 /* Initialize the keyboard driver. */
  2298. 13363
  2299. 13364   register struct kb_s *kb;
  2300. 13365
  2301. 13366   /* Input function. */
  2302. 13367   tp->tty_devread = kb_read;
  2303. 13368
  2304. 13369   kb = kb_addr();
  2305. 13370
  2306. 13371   /* Set up input queue. */
  2307. 13372   kb->ihead = kb->itail = kb->ibuf;
  2308. 13373
  2309. 13374   /* Set initial values. */
  2310. 13375   caps_off = 1;
  2311. 13376   num_off = 1;
  2312. 13377   slock_off = 1;
  2313. 13378   esc = 0;
  2314. 13379
  2315. 13380   set_leds();                   /* turn off numlock led */
  2316. 13381
  2317. 13382   scan_keyboard();              /* stop lockup from leftover keystroke */
  2318. 13383
  2319. 13384   put_irq_handler(KEYBOARD_IRQ, kbd_hw_int);    /* set the interrupt handler */
  2320. 13385   enable_irq(KEYBOARD_IRQ);     /* safe now everything initialised! */
  2321. 13386 }
  2322. 13389 /*===========================================================================*
  2323. 13390  *                              kbd_loadmap                                  *
  2324. 13391  *===========================================================================*/
  2325. 13392 PUBLIC int kbd_loadmap(user_phys)
  2326. 13393 phys_bytes user_phys;
  2327. 13394 {
  2328. 13395 /* Load a new keymap. */
  2329. 13396
  2330. 13397   phys_copy(user_phys, vir2phys(keymap), (phys_bytes) sizeof(keymap));
  2331. 13398   return(OK);
  2332. 13399 }
  2333. 13402 /*===========================================================================*
  2334. 13403  *                              func_key                                     *
  2335. 13404  *===========================================================================*/
  2336. 13405 PRIVATE int func_key(scode)
  2337. 13406 int scode;                      /* scan code for a function key */
  2338. 13407 {
  2339. 13408 /* This procedure traps function keys for debugging and control purposes. */
  2340. 13409
  2341. .Ep 184 src/kernel/keyboard.c
  2342. 13410   unsigned code;
  2343. 13411
  2344. 13412   code = map_key0(scode);                       /* first ignore modifiers */
  2345. 13413   if (code < F1 || code > F12) return(FALSE);   /* not our job */
  2346. 13414
  2347. 13415   switch (map_key(scode)) {                     /* include modifiers */
  2348. 13416
  2349. 13417   case F1:      p_dmp(); break;         /* print process table */
  2350. 13418   case F2:      map_dmp(); break;       /* print memory map */
  2351. 13419   case F3:      toggle_scroll(); break; /* hardware vs. software scrolling */
  2352. 13420   case CF7:     sigchar(&tty_table[CONSOLE], SIGQUIT); break;
  2353. 13421   case CF8:     sigchar(&tty_table[CONSOLE], SIGINT); break;
  2354. 13422   case CF9:     sigchar(&tty_table[CONSOLE], SIGKILL); break;
  2355. 13423   default:      return(FALSE);
  2356. 13424   }
  2357. 13425   return(TRUE);
  2358. 13426 }
  2359. 13429 /*==========================================================================*
  2360. 13430  *                              scan_keyboard                               *
  2361. 13431  *==========================================================================*/
  2362. 13432 PRIVATE int scan_keyboard()
  2363. 13433 {
  2364. 13434 /* Fetch the character from the keyboard hardware and acknowledge it. */
  2365. 13435
  2366. 13436   int code;
  2367. 13437   int val;
  2368. 13438
  2369. 13439   code = in_byte(KEYBD);        /* get the scan code for the key struck */
  2370. 13440   val = in_byte(PORT_B);        /* strobe the keyboard to ack the char */
  2371. 13441   out_byte(PORT_B, val | KBIT); /* strobe the bit high */
  2372. 13442   out_byte(PORT_B, val);        /* now strobe it low */
  2373. 13443   return code;
  2374. 13444 }
  2375. 13447 /*==========================================================================*
  2376. 13448  *                              wreboot                                     *
  2377. 13449  *==========================================================================*/
  2378. 13450 PUBLIC void wreboot(how)
  2379. 13451 int how;                /* 0 = halt, 1 = reboot, 2 = panic!, ... */
  2380. 13452 {
  2381. 13453 /* Wait for keystrokes for printing debugging info and reboot. */
  2382. 13454
  2383. 13455   int quiet, code;
  2384. 13456   static u16_t magic = MEMCHECK_MAG;
  2385. 13457   struct tasktab *ttp;
  2386. 13458
  2387. 13459   /* Mask all interrupts. */
  2388. 13460   out_byte(INT_CTLMASK, ~0);
  2389. 13461
  2390. 13462   /* Tell several tasks to stop. */
  2391. 13463   cons_stop();
  2392. 13464   floppy_stop();
  2393. 13465   clock_stop();
  2394. 13466
  2395. 13467   if (how == RBT_HALT) {
  2396. 13468         printf("System Haltedn");
  2397. 13469         if (!mon_return) how = RBT_PANIC;
  2398. .Op 185 src/kernel/keyboard.c
  2399. 13470   }
  2400. 13471
  2401. 13472   if (how == RBT_PANIC) {
  2402. 13473         /* A panic! */
  2403. 13474         printf("Hit ESC to reboot, F-keys for debug dumpsn");
  2404. 13475
  2405. 13476         (void) scan_keyboard(); /* ack any old input */
  2406. 13477         quiet = scan_keyboard();/* quiescent value (0 on PC, last code on AT)*/
  2407. 13478         for (;;) {
  2408. 13479                 milli_delay(100);       /* pause for a decisecond */
  2409. 13480                 code = scan_keyboard();
  2410. 13481                 if (code != quiet) {
  2411. 13482                         /* A key has been pressed. */
  2412. 13483                         if (code == ESC_SCAN) break; /* reboot if ESC typed */
  2413. 13484                         (void) func_key(code);       /* process function key */
  2414. 13485                         quiet = scan_keyboard();
  2415. 13486                 }
  2416. 13487         }
  2417. 13488         how = RBT_REBOOT;
  2418. 13489   }
  2419. 13490
  2420. 13491   if (how == RBT_REBOOT) printf("Rebootingn");
  2421. 13492
  2422. 13493   if (mon_return && how != RBT_RESET) {
  2423. 13494         /* Reinitialize the interrupt controllers to the BIOS defaults. */
  2424. 13495         intr_init(0);
  2425. 13496         out_byte(INT_CTLMASK, 0);
  2426. 13497         out_byte(INT2_CTLMASK, 0);
  2427. 13498
  2428. 13499         /* Return to the boot monitor. */
  2429. 13500         if (how == RBT_HALT) {
  2430. 13501                 reboot_code = vir2phys("");
  2431. 13502         } else
  2432. 13503         if (how == RBT_REBOOT) {
  2433. 13504                 reboot_code = vir2phys("delay;boot");
  2434. 13505         }
  2435. 13506         level0(monitor);
  2436. 13507   }
  2437. 13508
  2438. 13509   /* Stop BIOS memory test. */
  2439. 13510   phys_copy(vir2phys(&magic), (phys_bytes) MEMCHECK_ADR,
  2440. 13511                                                 (phys_bytes) sizeof(magic));
  2441. 13512
  2442. 13513   if (protected_mode) {
  2443. 13514         /* Use the AT keyboard controller to reset the processor.
  2444. 13515          * The A20 line is kept enabled in case this code is ever
  2445. 13516          * run from extended memory, and because some machines
  2446. 13517          * appear to drive the fake A20 high instead of low just
  2447. 13518          * after reset, leading to an illegal opode trap.  This bug
  2448. 13519          * is more of a problem if the fake A20 is in use, as it
  2449. 13520          * would be if the keyboard reset were used for real mode.
  2450. 13521          */
  2451. 13522         kb_wait();
  2452. 13523         out_byte(KB_COMMAND,
  2453. 13524                  KB_PULSE_OUTPUT | (0x0F & ~(KB_GATE_A20 | KB_RESET)));
  2454. 13525         milli_delay(10);
  2455. 13526
  2456. 13527         /* If the nice method fails then do a reset.  In protected
  2457. 13528          * mode this means a processor shutdown.
  2458. 13529          */
  2459. .Ep 186 src/kernel/keyboard.c
  2460. 13530         printf("Hard reset...n");
  2461. 13531         milli_delay(250);
  2462. 13532   }
  2463. 13533   /* In real mode, jumping to the reset address is good enough. */
  2464. 13534   level0(reset);
  2465. 13535 }
  2466. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2467. src/kernel/console.c    
  2468. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2469. 13600 /* Code and data for the IBM console driver.
  2470. 13601  *
  2471. 13602  * The 6845 video controller used by the IBM PC shares its video memory with
  2472. 13603  * the CPU somewhere in the 0xB0000 memory bank.  To the 6845 this memory
  2473. 13604  * consists of 16-bit words.  Each word has a character code in the low byte
  2474. 13605  * and a so-called attribute byte in the high byte.  The CPU directly modifies
  2475. 13606  * video memory to display characters, and sets two registers on the 6845 that
  2476. 13607  * specify the video origin and the cursor position.  The video origin is the
  2477. 13608  * place in video memory where the first character (upper left corner) can
  2478. 13609  * be found.  Moving the origin is a fast way to scroll the screen.  Some
  2479. 13610  * video adapters wrap around the top of video memory, so the origin can
  2480. 13611  * move without bounds.  For other adapters screen memory must sometimes be
  2481. 13612  * moved to reset the origin.  All computations on video memory use character
  2482. 13613  * (word) addresses for simplicity and assume there is no wrapping.  The
  2483. 13614  * assembly support functions translate the word addresses to byte addresses
  2484. 13615  * and the scrolling function worries about wrapping.
  2485. 13616  */
  2486. 13617
  2487. 13618 #include "kernel.h"
  2488. 13619 #include <termios.h>
  2489. 13620 #include <minix/callnr.h>
  2490. 13621 #include <minix/com.h>
  2491. 13622 #include "protect.h"
  2492. 13623 #include "tty.h"
  2493. 13624 #include "proc.h"
  2494. 13625
  2495. 13626 /* Definitions used by the console driver. */
  2496. 13627 #define MONO_BASE    0xB0000L   /* base of mono video memory */
  2497. 13628 #define COLOR_BASE   0xB8000L   /* base of color video memory */
  2498. 13629 #define MONO_SIZE     0x1000    /* 4K mono video memory */
  2499. 13630 #define COLOR_SIZE    0x4000    /* 16K color video memory */
  2500. 13631 #define EGA_SIZE      0x8000    /* EGA & VGA have at least 32K */
  2501. 13632 #define BLANK_COLOR   0x0700    /* determines cursor color on blank screen */
  2502. 13633 #define SCROLL_UP          0    /* scroll forward */
  2503. 13634 #define SCROLL_DOWN        1    /* scroll backward */
  2504. 13635 #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
  2505. 13636 #define CONS_RAM_WORDS    80    /* video ram buffer size */
  2506. 13637 #define MAX_ESC_PARMS      2    /* number of escape sequence params allowed */
  2507. 13638
  2508. 13639 /* Constants relating to the controller chips. */
  2509. 13640 #define M_6845         0x3B4    /* port for 6845 mono */
  2510. 13641 #define C_6845         0x3D4    /* port for 6845 color */
  2511. 13642 #define EGA            0x3C4    /* port for EGA or VGA card */
  2512. 13643 #define INDEX              0    /* 6845's index register */
  2513. 13644 #define DATA               1    /* 6845's data register */
  2514. .Op 187 src/kernel/console.c
  2515. 13645 #define VID_ORG           12    /* 6845's origin register */
  2516. 13646 #define CURSOR            14    /* 6845's cursor register */
  2517. 13647
  2518. 13648 /* Beeper. */
  2519. 13649 #define BEEP_FREQ     0x0533    /* value to put into timer to set beep freq */
  2520. 13650 #define B_TIME             3    /* length of CTRL-G beep is ticks */
  2521. 13651
  2522. 13652 /* definitions used for font management */
  2523. 13653 #define GA_SEQUENCER_INDEX      0x3C4
  2524. 13654 #define GA_SEQUENCER_DATA       0x3C5
  2525. 13655 #define GA_GRAPHICS_INDEX       0x3CE
  2526. 13656 #define GA_GRAPHICS_DATA        0x3CF
  2527. 13657 #define GA_VIDEO_ADDRESS        0xA0000L
  2528. 13658 #define GA_FONT_SIZE            8192
  2529. 13659
  2530. 13660 /* Global variables used by the console driver. */
  2531. 13661 PUBLIC unsigned vid_seg;        /* video ram selector (0xB0000 or 0xB8000) */
  2532. 13662 PUBLIC unsigned vid_size;       /* 0x2000 for color or 0x0800 for mono */
  2533. 13663 PUBLIC unsigned vid_mask;       /* 0x1FFF for color or 0x07FF for mono */
  2534. 13664 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
  2535. 13665
  2536. 13666 /* Private variables used by the console driver. */
  2537. 13667 PRIVATE int vid_port;           /* I/O port for accessing 6845 */
  2538. 13668 PRIVATE int wrap;               /* hardware can wrap? */
  2539. 13669 PRIVATE int softscroll;         /* 1 = software scrolling, 0 = hardware */
  2540. 13670 PRIVATE unsigned vid_base;      /* base of video ram (0xB000 or 0xB800) */
  2541. 13671 PRIVATE int beeping;            /* speaker is beeping? */
  2542. 13672 #define scr_width       80      /* # characters on a line */
  2543. 13673 #define scr_lines       25      /* # lines on the screen */
  2544. 13674 #define scr_size        (80*25) /* # characters on the screen */
  2545. 13675
  2546. 13676 /* Per console data. */
  2547. 13677 typedef struct console {
  2548. 13678   tty_t *c_tty;                 /* associated TTY struct */
  2549. 13679   int c_column;                 /* current column number (0-origin) */
  2550. 13680   int c_row;                    /* current row (0 at top of screen) */
  2551. 13681   int c_rwords;                 /* number of WORDS (not bytes) in outqueue */
  2552. 13682   unsigned c_start;             /* start of video memory of this console */
  2553. 13683   unsigned c_limit;             /* limit of this console's video memory */
  2554. 13684   unsigned c_org;               /* location in RAM where 6845 base points */
  2555. 13685   unsigned c_cur;               /* current position of cursor in video RAM */
  2556. 13686   unsigned c_attr;              /* character attribute */
  2557. 13687   unsigned c_blank;             /* blank attribute */
  2558. 13688   char c_esc_state;             /* 0=normal, 1=ESC, 2=ESC[ */
  2559. 13689   char c_esc_intro;             /* Distinguishing character following ESC */
  2560. 13690   int *c_esc_parmp;             /* pointer to current escape parameter */
  2561. 13691   int c_esc_parmv[MAX_ESC_PARMS];       /* list of escape parameters */
  2562. 13692   u16_t c_ramqueue[CONS_RAM_WORDS];     /* buffer for video RAM */
  2563. 13693 } console_t;
  2564. 13694
  2565. 13695 PRIVATE int nr_cons= 1;         /* actual number of consoles */
  2566. 13696 PRIVATE console_t cons_table[NR_CONS];
  2567. 13697 PRIVATE console_t *curcons;     /* currently visible */
  2568. 13698
  2569. 13699 /* Color if using a color controller. */
  2570. 13700 #define color   (vid_port == C_6845)
  2571. 13701
  2572. 13702 /* Map from ANSI colors to the attributes used by the PC */
  2573. 13703 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
  2574. 13704
  2575. .Ep 188 src/kernel/console.c
  2576. 13705 /* Structure used for font management */
  2577. 13706 struct sequence {
  2578. 13707         unsigned short index;
  2579. 13708         unsigned char port;
  2580. 13709         unsigned char value;
  2581. 13710 };
  2582. 13711
  2583. 13712 FORWARD _PROTOTYPE( void cons_write, (struct tty *tp)                   );
  2584. 13713 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c)                  );
  2585. 13714 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c)             );
  2586. 13715 FORWARD _PROTOTYPE( void beep, (void)                                   );
  2587. 13716 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c)            );
  2588. 13717 FORWARD _PROTOTYPE( void flush, (console_t *cons)                       );
  2589. 13718 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c)         );
  2590. 13719 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir)      );
  2591. 13720 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val)              );
  2592. 13721 FORWARD _PROTOTYPE( void stop_beep, (void)                              );
  2593. 13722 FORWARD _PROTOTYPE( void cons_org0, (void)                              );
  2594. 13723 FORWARD _PROTOTYPE( void ga_program, (struct sequence *seq) );
  2595. 13724
  2596. 13725
  2597. 13726 /*===========================================================================*
  2598. 13727  *                              cons_write                                   *
  2599. 13728  *===========================================================================*/
  2600. 13729 PRIVATE void cons_write(tp)
  2601. 13730 register struct tty *tp;        /* tells which terminal is to be used */
  2602. 13731 {
  2603. 13732 /* Copy as much data as possible to the output queue, then start I/O.  On
  2604. 13733  * memory-mapped terminals, such as the IBM console, the I/O will also be
  2605. 13734  * finished, and the counts updated.  Keep repeating until all I/O done.
  2606. 13735  */
  2607. 13736
  2608. 13737   int count;
  2609. 13738   register char *tbuf;
  2610. 13739   char buf[64];
  2611. 13740   phys_bytes user_phys;
  2612. 13741   console_t *cons = tp->tty_priv;
  2613. 13742
  2614. 13743   /* Check quickly for nothing to do, so this can be called often without
  2615. 13744    * unmodular tests elsewhere.
  2616. 13745    */
  2617. 13746   if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
  2618. 13747
  2619. 13748   /* Copy the user bytes to buf[] for decent addressing. Loop over the
  2620. 13749    * copies, since the user buffer may be much larger than buf[].
  2621. 13750    */
  2622. 13751   do {
  2623. 13752         if (count > sizeof(buf)) count = sizeof(buf);
  2624. 13753         user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir);
  2625. 13754         phys_copy(user_phys, vir2phys(buf), (phys_bytes) count);
  2626. 13755         tbuf = buf;
  2627. 13756
  2628. 13757         /* Update terminal data structure. */
  2629. 13758         tp->tty_out_vir += count;
  2630. 13759         tp->tty_outcum += count;
  2631. 13760         tp->tty_outleft -= count;
  2632. 13761
  2633. 13762         /* Output each byte of the copy to the screen.  Avoid calling
  2634. 13763          * out_char() for the "easy" characters, put them into the buffer
  2635. 13764          * directly.
  2636. .Op 189 src/kernel/console.c
  2637. 13765          */
  2638. 13766         do {
  2639. 13767                 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
  2640. 13768                         || cons->c_column >= scr_width
  2641. 13769                         || cons->c_rwords >= buflen(cons->c_ramqueue))
  2642. 13770                 {
  2643. 13771                         out_char(cons, *tbuf++);
  2644. 13772                 } else {
  2645. 13773                         cons->c_ramqueue[cons->c_rwords++] =
  2646. 13774                                         cons->c_attr | (*tbuf++ & BYTE);
  2647. 13775                         cons->c_column++;
  2648. 13776                 }
  2649. 13777         } while (--count != 0);
  2650. 13778   } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
  2651. 13779
  2652. 13780   flush(cons);                  /* transfer anything buffered to the screen */
  2653. 13781
  2654. 13782   /* Reply to the writer if all output is finished. */
  2655. 13783   if (tp->tty_outleft == 0) {
  2656. 13784         tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
  2657. 13785                                                         tp->tty_outcum);
  2658. 13786         tp->tty_outcum = 0;
  2659. 13787   }
  2660. 13788 }
  2661. 13791 /*===========================================================================*
  2662. 13792  *                              cons_echo                                    *
  2663. 13793  *===========================================================================*/
  2664. 13794 PRIVATE void cons_echo(tp, c)
  2665. 13795 register tty_t *tp;             /* pointer to tty struct */
  2666. 13796 int c;                          /* character to be echoed */
  2667. 13797 {
  2668. 13798 /* Echo keyboard input (print & flush). */
  2669. 13799   console_t *cons = tp->tty_priv;
  2670. 13800
  2671. 13801   out_char(cons, c);
  2672. 13802   flush(cons);
  2673. 13803 }
  2674. 13806 /*===========================================================================*
  2675. 13807  *                              out_char                                     *
  2676. 13808  *===========================================================================*/
  2677. 13809 PRIVATE void out_char(cons, c)
  2678. 13810 register console_t *cons;       /* pointer to console struct */
  2679. 13811 int c;                          /* character to be output */
  2680. 13812 {
  2681. 13813 /* Output a character on the console.  Check for escape sequences first. */
  2682. 13814   if (cons->c_esc_state > 0) {
  2683. 13815         parse_escape(cons, c);
  2684. 13816         return;
  2685. 13817   }
  2686. 13818
  2687. 13819   switch(c) {
  2688. 13820         case 000:               /* null is typically used for padding */
  2689. 13821                 return;         /* better not do anything */
  2690. 13822
  2691. 13823         case 007:               /* ring the bell */
  2692. 13824                 flush(cons);    /* print any chars queued for output */
  2693. .Ep 190 src/kernel/console.c
  2694. 13825                 beep();
  2695. 13826                 return;
  2696. 13827
  2697. 13828         case 'b':              /* backspace */
  2698. 13829                 if (--cons->c_column < 0) {
  2699. 13830                         if (--cons->c_row >= 0) cons->c_column += scr_width;
  2700. 13831                 }
  2701. 13832                 flush(cons);
  2702. 13833                 return;
  2703. 13834
  2704. 13835         case 'n':              /* line feed */
  2705. 13836                 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
  2706. 13837                                                 == (OPOST|ONLCR)) {
  2707. 13838                         cons->c_column = 0;
  2708. 13839                 }
  2709. 13840                 /*FALL THROUGH*/
  2710. 13841         case 013:               /* CTRL-K */
  2711. 13842         case 014:               /* CTRL-L */
  2712. 13843                 if (cons->c_row == scr_lines-1) {
  2713. 13844                         scroll_screen(cons, SCROLL_UP);
  2714. 13845                 } else {
  2715. 13846                         cons->c_row++;
  2716. 13847                 }
  2717. 13848                 flush(cons);
  2718. 13849                 return;
  2719. 13850
  2720. 13851         case 'r':              /* carriage return */
  2721. 13852                 cons->c_column = 0;
  2722. 13853                 flush(cons);
  2723. 13854                 return;
  2724. 13855
  2725. 13856         case 't':              /* tab */
  2726. 13857                 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
  2727. 13858                 if (cons->c_column > scr_width) {
  2728. 13859                         cons->c_column -= scr_width;
  2729. 13860                         if (cons->c_row == scr_lines-1) {
  2730. 13861                                 scroll_screen(cons, SCROLL_UP);
  2731. 13862                         } else {
  2732. 13863                                 cons->c_row++;
  2733. 13864                         }
  2734. 13865                 }
  2735. 13866                 flush(cons);
  2736. 13867                 return;
  2737. 13868
  2738. 13869         case 033:               /* ESC - start of an escape sequence */
  2739. 13870                 flush(cons);    /* print any chars queued for output */
  2740. 13871                 cons->c_esc_state = 1;  /* mark ESC as seen */
  2741. 13872                 return;
  2742. 13873
  2743. 13874         default:                /* printable chars are stored in ramqueue */
  2744. 13875                 if (cons->c_column >= scr_width) {
  2745. 13876                         if (!LINEWRAP) return;
  2746. 13877                         if (cons->c_row == scr_lines-1) {
  2747. 13878                                 scroll_screen(cons, SCROLL_UP);
  2748. 13879                         } else {
  2749. 13880                                 cons->c_row++;