BOOK.TXT
上传用户:jnzhq888
上传日期:2007-01-18
资源大小:51694k
文件大小:1020k
源码类别:

操作系统开发

开发平台:

WINDOWS

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