BOOK.TXT
资源名称:os_source.zip [点击查看]
上传用户:datang2001
上传日期:2007-02-01
资源大小:53269k
文件大小:999k
源码类别:
操作系统开发
开发平台:
C/C++
- 11019 * | GET_TIME | | | |
- 11020 * |------------+----------+---------+---------|
- 11021 * | SET_TIME | | | newtime |
- 11022 * |------------+----------+---------+---------|
- 11023 * | SET_ALARM | proc_nr |f to call| delta |
- 11024 * |------------+----------+---------+---------|
- 11025 * | SET_SYN_AL | proc_nr | | delta |
- 11026 * ---------------------------------------------
- 11027 * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
- 11028 * the message, depending upon the message type.
- 11029 *
- 11030 * Reply messages are of type OK, except in the case of a HARD_INT, to
- 11031 * which no reply is generated. For the GET_* messages the time is returned
- 11032 * in the NEW_TIME field, and for the SET_ALARM and SET_SYN_AL the time
- 11033 * in seconds remaining until the alarm is returned is returned in the same
- 11034 * field.
- 11035 *
- 11036 * When an alarm goes off, if the caller is a user process, a SIGALRM signal
- 11037 * is sent to it. If it is a task, a function specified by the caller will
- 11038 * be invoked. This function may, for example, send a message, but only if
- 11039 * it is certain that the task will be blocked when the timer goes off. A
- 11040 * synchronous alarm sends a message to the synchronous alarm task, which
- 11041 * in turn can dispatch a message to another server. This is the only way
- 11042 * to send an alarm to a server, since servers cannot use the function-call
- 11043 * mechanism available to tasks and servers cannot receive signals.
- 11044 */
- 11045
- 11046 #include "kernel.h"
- 11047 #include <signal.h>
- 11048 #include <minix/callnr.h>
- 11049 #include <minix/com.h>
- 11050 #include "proc.h"
- 11051
- 11052 /* Constant definitions. */
- 11053 #define MILLISEC 100 /* how often to call the scheduler (msec) */
- 11054 #define SCHED_RATE (MILLISEC*HZ/1000) /* number of ticks per schedule */
- 11055
- 11056 /* Clock parameters. */
- 11057 #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using sqare wave*/
- 11058 #define LATCH_COUNT 0x00 /* cc00xxxx, c = channel, x = any */
- 11059 #define SQUARE_WAVE 0x36 /* ccaammmb, a = access, m = mode, b = BCD */
- 11060 /* 11x11, 11 = LSB then MSB, x11 = sq wave */
- 11061 #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
- 11062 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
- 11063
- 11064 #define CLOCK_ACK_BIT 0x80 /* PS/2 clock interrupt acknowledge bit */
- 11065
- 11066 /* Clock task variables. */
- 11067 PRIVATE clock_t realtime; /* real time clock */
- 11068 PRIVATE time_t boot_time; /* time in seconds of system boot */
- 11069 PRIVATE clock_t next_alarm; /* probable time of next alarm */
- 11070 PRIVATE message mc; /* message buffer for both input and output */
- 11071 PRIVATE int watchdog_proc; /* contains proc_nr at call of *watch_dog[]*/
- 11072 PRIVATE watchdog_t watch_dog[NR_TASKS+NR_PROCS];
- 11073
- 11074 /* Variables used by both clock task and synchronous alarm task */
- 11075 PRIVATE int syn_al_alive= TRUE; /* don't wake syn_alrm_task before inited*/
- 11076 PRIVATE int syn_table[NR_TASKS+NR_PROCS]; /* which tasks get CLOCK_INT*/
- 11077
- 11078 /* Variables changed by interrupt handler */
- 11079 PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
- 11080 PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
- 11081 PRIVATE struct proc *prev_ptr; /* last user process run by clock task */
- 11082
- 11083 FORWARD _PROTOTYPE( void common_setalarm, (int proc_nr,
- 11084 long delta_ticks, watchdog_t fuction) );
- 11085 FORWARD _PROTOTYPE( void do_clocktick, (void) );
- 11086 FORWARD _PROTOTYPE( void do_get_time, (void) );
- 11087 FORWARD _PROTOTYPE( void do_getuptime, (void) );
- 11088 FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
- 11089 FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr) );
- 11090 FORWARD _PROTOTYPE( void init_clock, (void) );
- 11091 FORWARD _PROTOTYPE( void cause_alarm, (void) );
- 11092 FORWARD _PROTOTYPE( void do_setsyn_alrm, (message *m_ptr) );
- 11093 FORWARD _PROTOTYPE( int clock_handler, (int irq) );
- 11094
- 11095 /*===========================================================================*
- 11096 * clock_task *
- 11097 *===========================================================================*/
- 11098 PUBLIC void clock_task()
- 11099 {
- 11100 /* Main program of clock task. It corrects realtime by adding pending
- 11101 * ticks seen only by the interrupt service, then it determines which
- 11102 * of the 6 possible calls this is by looking at 'mc.m_type'. Then
- 11103 * it dispatches.
- 11104 */
- 11105
- 11106 int opcode;
- 11107
- 11108 init_clock(); /* initialize clock task */
- 11109
- 11110 /* Main loop of the clock task. Get work, process it, sometimes reply. */
- 11111 while (TRUE) {
- 11112 receive(ANY, &mc); /* go get a message */
- 11113 opcode = mc.m_type; /* extract the function code */
- 11114
- 11115 lock();
- 11116 realtime += pending_ticks; /* transfer ticks from low level handler */
- 11117 pending_ticks = 0; /* so we don't have to worry about them */
- 11118 unlock();
- 11119
- 11120 switch (opcode) {
- 11121 case HARD_INT: do_clocktick(); break;
- 11122 case GET_UPTIME: do_getuptime(); break;
- 11123 case GET_TIME: do_get_time(); break;
- 11124 case SET_TIME: do_set_time(&mc); break;
- 11125 case SET_ALARM: do_setalarm(&mc); break;
- 11126 case SET_SYNC_AL:do_setsyn_alrm(&mc); break;
- 11127 default: panic("clock task got bad message", mc.m_type);
- 11128 }
- 11129
- 11130 /* Send reply, except for clock tick. */
- 11131 mc.m_type = OK;
- 11132 if (opcode != HARD_INT) send(mc.m_source, &mc);
- 11133 }
- 11134 }
- 11137 /*===========================================================================*
- 11138 * do_clocktick *
- 11139 *===========================================================================*/
- 11140 PRIVATE void do_clocktick()
- 11141 {
- 11142 /* Despite its name, this routine is not called on every clock tick. It
- 11143 * is called on those clock ticks when a lot of work needs to be done.
- 11144 */
- 11145
- 11146 register struct proc *rp;
- 11147 register int proc_nr;
- 11148
- 11149 if (next_alarm <= realtime) {
- 11150 /* An alarm may have gone off, but proc may have exited, so check. */
- 11151 next_alarm = LONG_MAX; /* start computing next alarm */
- 11152 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
- 11153 if (rp->p_alarm != 0) {
- 11154 /* See if this alarm time has been reached. */
- 11155 if (rp->p_alarm <= realtime) {
- 11156 /* A timer has gone off. If it is a user proc,
- 11157 * send it a signal. If it is a task, call the
- 11158 * function previously specified by the task.
- 11159 */
- 11160 proc_nr = proc_number(rp);
- 11161 if (watch_dog[proc_nr+NR_TASKS]) {
- 11162 watchdog_proc= proc_nr;
- 11163 (*watch_dog[proc_nr+NR_TASKS])();
- 11164 }
- 11165 else
- 11166 cause_sig(proc_nr, SIGALRM);
- 11167 rp->p_alarm = 0;
- 11168 }
- 11169
- 11170 /* Work on determining which alarm is next. */
- 11171 if (rp->p_alarm != 0 && rp->p_alarm < next_alarm)
- 11172 next_alarm = rp->p_alarm;
- 11173 }
- 11174 }
- 11175 }
- 11176
- 11177 /* If a user process has been running too long, pick another one. */
- 11178 if (--sched_ticks == 0) {
- 11179 if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
- 11180 sched_ticks = SCHED_RATE; /* reset quantum */
- 11181 prev_ptr = bill_ptr; /* new previous process */
- 11182 }
- 11183 }
- 11186 /*===========================================================================*
- 11187 * do_getuptime *
- 11188 *===========================================================================*/
- 11189 PRIVATE void do_getuptime()
- 11190 {
- 11191 /* Get and return the current clock uptime in ticks. */
- 11192
- 11193 mc.NEW_TIME = realtime; /* current uptime */
- 11194 }
- 11197 /*===========================================================================*
- 11198 * get_uptime *
- 11199 *===========================================================================*/
- 11200 PUBLIC clock_t get_uptime()
- 11201 {
- 11202 /* Get and return the current clock uptime in ticks. This function is
- 11203 * designed to be called from other tasks, so they can get uptime without
- 11204 * the overhead of messages. It has to be careful about pending_ticks.
- 11205 */
- 11206
- 11207 clock_t uptime;
- 11208
- 11209 lock();
- 11210 uptime = realtime + pending_ticks;
- 11211 unlock();
- 11212 return(uptime);
- 11213 }
- 11216 /*===========================================================================*
- 11217 * do_get_time *
- 11218 *===========================================================================*/
- 11219 PRIVATE void do_get_time()
- 11220 {
- 11221 /* Get and return the current clock time in seconds. */
- 11222
- 11223 mc.NEW_TIME = boot_time + realtime/HZ; /* current real time */
- 11224 }
- 11227 /*===========================================================================*
- 11228 * do_set_time *
- 11229 *===========================================================================*/
- 11230 PRIVATE void do_set_time(m_ptr)
- 11231 message *m_ptr; /* pointer to request message */
- 11232 {
- 11233 /* Set the real time clock. Only the superuser can use this call. */
- 11234
- 11235 boot_time = m_ptr->NEW_TIME - realtime/HZ;
- 11236 }
- 11239 /*===========================================================================*
- 11240 * do_setalarm *
- 11241 *===========================================================================*/
- 11242 PRIVATE void do_setalarm(m_ptr)
- 11243 message *m_ptr; /* pointer to request message */
- 11244 {
- 11245 /* A process wants an alarm signal or a task wants a given watch_dog function
- 11246 * called after a specified interval.
- 11247 */
- 11248
- 11249 register struct proc *rp;
- 11250 int proc_nr; /* which process wants the alarm */
- 11251 long delta_ticks; /* in how many clock ticks does he want it? */
- 11252 watchdog_t function; /* function to call (tasks only) */
- 11253
- 11254 /* Extract the parameters from the message. */
- 11255 proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
- 11256 delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
- 11257 function = (watchdog_t) m_ptr->FUNC_TO_CALL;
- 11258 /* function to call (tasks only) */
- 11259 rp = proc_addr(proc_nr);
- 11260 mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
- 11261 if (!istaskp(rp)) function= 0; /* user processes get signaled */
- 11262 common_setalarm(proc_nr, delta_ticks, function);
- 11263 }
- 11266 /*===========================================================================*
- 11267 * do_setsyn_alrm *
- 11268 *===========================================================================*/
- 11269 PRIVATE void do_setsyn_alrm(m_ptr)
- 11270 message *m_ptr; /* pointer to request message */
- 11271 {
- 11272 /* A process wants a synchronous alarm.
- 11273 */
- 11274
- 11275 register struct proc *rp;
- 11276 int proc_nr; /* which process wants the alarm */
- 11277 long delta_ticks; /* in how many clock ticks does he want it? */
- 11278
- 11279 /* Extract the parameters from the message. */
- 11280 proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
- 11281 delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
- 11282 rp = proc_addr(proc_nr);
- 11283 mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
- 11284 common_setalarm(proc_nr, delta_ticks, cause_alarm);
- 11285 }
- 11288 /*===========================================================================*
- 11289 * common_setalarm *
- 11290 *===========================================================================*/
- 11291 PRIVATE void common_setalarm(proc_nr, delta_ticks, function)
- 11292 int proc_nr; /* which process wants the alarm */
- 11293 long delta_ticks; /* in how many clock ticks does he want it? */
- 11294 watchdog_t function; /* function to call (0 if cause_sig is
- 11295 * to be called */
- 11296 {
- 11297 /* Finish up work of do_set_alarm and do_setsyn_alrm. Record an alarm
- 11298 * request and check to see if it is the next alarm needed.
- 11299 */
- 11300
- 11301 register struct proc *rp;
- 11302
- 11303 rp = proc_addr(proc_nr);
- 11304 rp->p_alarm = (delta_ticks == 0 ? 0 : realtime + delta_ticks);
- 11305 watch_dog[proc_nr+NR_TASKS] = function;
- 11306
- 11307 /* Which alarm is next? */
- 11308 next_alarm = LONG_MAX;
- 11309 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
- 11310 if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
- 11311
- 11312 }
- 11315 /*===========================================================================*
- 11316 * cause_alarm *
- 11317 *===========================================================================*/
- 11318 PRIVATE void cause_alarm()
- 11319 {
- 11320 /* Routine called if a timer goes off and the process requested a synchronous
- 11321 * alarm. The process number is in the global variable watchdog_proc (HACK).
- 11322 */
- 11323 message mess;
- 11324
- 11325 syn_table[watchdog_proc + NR_TASKS]= TRUE;
- 11326 if (!syn_al_alive) send (SYN_ALRM_TASK, &mess);
- 11327 }
- 11330 /*===========================================================================*
- 11331 * syn_alrm_task *
- 11332 *===========================================================================*/
- 11333 PUBLIC void syn_alrm_task()
- 11334 {
- 11335 /* Main program of the synchronous alarm task.
- 11336 * This task receives messages only from cause_alarm in the clock task.
- 11337 * It sends a CLOCK_INT message to a process that requested a syn_alrm.
- 11338 * Synchronous alarms are so called because, unlike a signals or the
- 11339 * activation of a watchdog, a synchronous alarm is received by a process
- 11340 * when it is in a known part of its code, that is, when it has issued
- 11341 * a call to receive a message.
- 11342 */
- 11343
- 11344 message mess;
- 11345 int work_done; /* ready to sleep ? */
- 11346 int *al_ptr; /* pointer in syn_table */
- 11347 int i;
- 11348
- 11349 syn_al_alive= TRUE;
- 11350 for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
- 11351 *al_ptr= FALSE;
- 11352
- 11353 while (TRUE) {
- 11354 work_done= TRUE;
- 11355 for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
- 11356 if (*al_ptr) {
- 11357 *al_ptr= FALSE;
- 11358 mess.m_type= CLOCK_INT;
- 11359 send (i-NR_TASKS, &mess);
- 11360 work_done= FALSE;
- 11361 }
- 11362 if (work_done) {
- 11363 syn_al_alive= FALSE;
- 11364 receive (CLOCK, &mess);
- 11365 syn_al_alive= TRUE;
- 11366 }
- 11367 }
- 11368 }
- 11371 /*===========================================================================*
- 11372 * clock_handler *
- 11373 *===========================================================================*/
- 11374 PRIVATE int clock_handler(irq)
- 11375 int irq;
- 11376 {
- 11377 /* This executes on every clock tick (i.e., every time the timer chip
- 11378 * generates an interrupt). It does a little bit of work so the clock
- 11379 * task does not have to be called on every tick.
- 11380 *
- 11381 * Switch context to do_clocktick if an alarm has gone off.
- 11382 * Also switch there to reschedule if the reschedule will do something.
- 11383 * This happens when
- 11384 * (1) quantum has expired
- 11385 * (2) current process received full quantum (as clock sampled it!)
- 11386 * (3) something else is ready to run.
- 11387 * Also call TTY and PRINTER and let them do whatever is necessary.
- 11388 *
- 11389 * Many global global and static variables are accessed here. The safety
- 11390 * of this must be justified. Most of them are not changed here:
- 11391 * k_reenter:
- 11392 * This safely tells if the clock interrupt is nested.
- 11393 * proc_ptr, bill_ptr:
- 11394 * These are used for accounting. It does not matter if proc.c
- 11395 * is changing them, provided they are always valid pointers,
- 11396 * since at worst the previous process would be billed.
- 11397 * next_alarm, realtime, sched_ticks, bill_ptr, prev_ptr,
- 11398 * rdy_head[USER_Q]:
- 11399 * These are tested to decide whether to call interrupt(). It
- 11400 * does not matter if the test is sometimes (rarely) backwards
- 11401 * due to a race, since this will only delay the high-level
- 11402 * processing by one tick, or call the high level unnecessarily.
- 11403 * The variables which are changed require more care:
- 11404 * rp->user_time, rp->sys_time:
- 11405 * These are protected by explicit locks in system.c. They are
- 11406 * not properly protected in dmp.c (the increment here is not
- 11407 * atomic) but that hardly matters.
- 11408 * pending_ticks:
- 11409 * This is protected by explicit locks in clock.c. Don't
- 11410 * update realtime directly, since there are too many
- 11411 * references to it to guard conveniently.
- 11412 * lost_ticks:
- 11413 * Clock ticks counted outside the clock task.
- 11414 * sched_ticks, prev_ptr:
- 11415 * Updating these competes with similar code in do_clocktick().
- 11416 * No lock is necessary, because if bad things happen here
- 11417 * (like sched_ticks going negative), the code in do_clocktick()
- 11418 * will restore the variables to reasonable values, and an
- 11419 * occasional missed or extra sched() is harmless.
- 11420 *
- 11421 * Are these complications worth the trouble? Well, they make the system 15%
- 11422 * faster on a 5MHz 8088, and make task debugging much easier since there are
- 11423 * no task switches on an inactive system.
- 11424 */
- 11425
- 11426 register struct proc *rp;
- 11427 register unsigned ticks;
- 11428 clock_t now;
- 11429
- 11430 if (ps_mca) {
- 11431 /* Acknowledge the PS/2 clock interrupt. */
- 11432 out_byte(PORT_B, in_byte(PORT_B) | CLOCK_ACK_BIT);
- 11433 }
- 11434
- 11435 /* Update user and system accounting times.
- 11436 * First charge the current process for user time.
- 11437 * If the current process is not the billable process (usually because it
- 11438 * is a task), charge the billable process for system time as well.
- 11439 * Thus the unbillable tasks' user time is the billable users' system time.
- 11440 */
- 11441 if (k_reenter != 0)
- 11442 rp = proc_addr(HARDWARE);
- 11443 else
- 11444 rp = proc_ptr;
- 11445 ticks = lost_ticks + 1;
- 11446 lost_ticks = 0;
- 11447 rp->user_time += ticks;
- 11448 if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;
- 11449
- 11450 pending_ticks += ticks;
- 11451 now = realtime + pending_ticks;
- 11452 if (tty_timeout <= now) tty_wakeup(now); /* possibly wake up TTY */
- 11453 pr_restart(); /* possibly restart printer */
- 11454
- 11455 if (next_alarm <= now ||
- 11456 sched_ticks == 1 &&
- 11457 bill_ptr == prev_ptr &&
- 11458 rdy_head[USER_Q] != NIL_PROC) {
- 11459 interrupt(CLOCK);
- 11460 return 1; /* Reenable interrupts */
- 11461 }
- 11462
- 11463 if (--sched_ticks == 0) {
- 11464 /* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
- 11465 sched_ticks = SCHED_RATE; /* reset quantum */
- 11466 prev_ptr = bill_ptr; /* new previous process */
- 11467 }
- 11468 return 1; /* Reenable clock interrupt */
- 11469 }
- 11471 /*===========================================================================*
- 11472 * init_clock *
- 11473 *===========================================================================*/
- 11474 PRIVATE void init_clock()
- 11475 {
- 11476 /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
- 11477
- 11478 out_byte(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
- 11479 out_byte(TIMER0, TIMER_COUNT); /* load timer low byte */
- 11480 out_byte(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
- 11481 put_irq_handler(CLOCK_IRQ, clock_handler); /* set the interrupt handler */
- 11482 enable_irq(CLOCK_IRQ); /* ready for clock interrupts */
- 11483 }
- 11486 /*===========================================================================*
- 11487 * clock_stop *
- 11488 *===========================================================================*/
- 11489 PUBLIC void clock_stop()
- 11490 {
- 11491 /* Reset the clock to the BIOS rate. (For rebooting) */
- 11492
- 11493 out_byte(TIMER_MODE, 0x36);
- 11494 out_byte(TIMER0, 0);
- 11495 out_byte(TIMER0, 0);
- 11496 }
- 11499 /*==========================================================================*
- 11500 * milli_delay *
- 11501 *==========================================================================*/
- 11502 PUBLIC void milli_delay(millisec)
- 11503 unsigned millisec;
- 11504 {
- 11505 /* Delay some milliseconds. */
- 11506
- 11507 struct milli_state ms;
- 11508
- 11509 milli_start(&ms);
- 11510 while (milli_elapsed(&ms) < millisec) {}
- 11511 }
- 11513 /*==========================================================================*
- 11514 * milli_start *
- 11515 *==========================================================================*/
- 11516 PUBLIC void milli_start(msp)
- 11517 struct milli_state *msp;
- 11518 {
- 11519 /* Prepare for calls to milli_elapsed(). */
- 11520
- 11521 msp->prev_count = 0;
- 11522 msp->accum_count = 0;
- 11523 }
- 11526 /*==========================================================================*
- 11527 * milli_elapsed *
- 11528 *==========================================================================*/
- 11529 PUBLIC unsigned milli_elapsed(msp)
- 11530 struct milli_state *msp;
- 11531 {
- 11532 /* Return the number of milliseconds since the call to milli_start(). Must be
- 11533 * polled rapidly.
- 11534 */
- 11535 unsigned count;
- 11536
- 11537 /* Read the counter for channel 0 of the 8253A timer. The counter
- 11538 * decrements at twice the timer frequency (one full cycle for each
- 11539 * half of square wave). The counter normally has a value between 0
- 11540 * and TIMER_COUNT, but before the clock task has been initialized,
- 11541 * its maximum value is 65535, as set by the BIOS.
- 11542 */
- 11543 out_byte(TIMER_MODE, LATCH_COUNT); /* make chip copy count to latch */
- 11544 count = in_byte(TIMER0); /* countdown continues during 2-step read */
- 11545 count |= in_byte(TIMER0) << 8;
- 11546
- 11547 /* Add difference between previous and new count unless the counter has
- 11548 * increased (restarted its cycle). We may lose a tick now and then, but
- 11549 * microsecond precision is not needed.
- 11550 */
- 11551 msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
- 11552 msp->prev_count = count;
- 11553
- 11554 return msp->accum_count / (TIMER_FREQ / 1000);
- 11555 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/tty.h
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 11600 /* tty.h - Terminals */
- 11601
- 11602 #define TTY_IN_BYTES 256 /* tty input queue size */
- 11603 #define TAB_SIZE 8 /* distance between tab stops */
- 11604 #define TAB_MASK 7 /* mask to compute a tab stop position */
- 11605
- 11606 #define ESC '33' /* escape */
- 11607
- 11608 #define O_NOCTTY 00400 /* from <fcntl.h>, or cc will choke */
- 11609 #define O_NONBLOCK 04000
- 11610
- 11611 typedef _PROTOTYPE( void (*devfun_t), (struct tty *tp) );
- 11612 typedef _PROTOTYPE( void (*devfunarg_t), (struct tty *tp, int c) );
- 11613
- 11614 typedef struct tty {
- 11615 int tty_events; /* set when TTY should inspect this line */
- 11616
- 11617 /* Input queue. Typed characters are stored here until read by a program. */
- 11618 u16_t *tty_inhead; /* pointer to place where next char goes */
- 11619 u16_t *tty_intail; /* pointer to next char to be given to prog */
- 11620 int tty_incount; /* # chars in the input queue */
- 11621 int tty_eotct; /* number of "line breaks" in input queue */
- 11622 devfun_t tty_devread; /* routine to read from low level buffers */
- 11623 devfun_t tty_icancel; /* cancel any device input */
- 11624 int tty_min; /* minimum requested #chars in input queue */
- 11625 clock_t tty_time; /* time when the input is available */
- 11626 struct tty *tty_timenext; /* for a list of ttys with active timers */
- 11627
- 11628 /* Output section. */
- 11629 devfun_t tty_devwrite; /* routine to start actual device output */
- 11630 devfunarg_t tty_echo; /* routine to echo characters input */
- 11631 devfun_t tty_ocancel; /* cancel any ongoing device output */
- 11632 devfun_t tty_break; /* let the device send a break */
- 11633
- 11634 /* Terminal parameters and status. */
- 11635 int tty_position; /* current position on the screen for echoing */
- 11636 char tty_reprint; /* 1 when echoed input messed up, else 0 */
- 11637 char tty_escaped; /* 1 when LNEXT (^V) just seen, else 0 */
- 11638 char tty_inhibited; /* 1 when STOP (^S) just seen (stops output) */
- 11639 char tty_pgrp; /* slot number of controlling process */
- 11640 char tty_openct; /* count of number of opens of this tty */
- 11641
- 11642 /* Information about incomplete I/O requests is stored here. */
- 11643 char tty_inrepcode; /* reply code, TASK_REPLY or REVIVE */
- 11644 char tty_incaller; /* process that made the call (usually FS) */
- 11645 char tty_inproc; /* process that wants to read from tty */
- 11646 vir_bytes tty_in_vir; /* virtual address where data is to go */
- 11647 int tty_inleft; /* how many chars are still needed */
- 11648 int tty_incum; /* # chars input so far */
- 11649 char tty_outrepcode; /* reply code, TASK_REPLY or REVIVE */
- 11650 char tty_outcaller; /* process that made the call (usually FS) */
- 11651 char tty_outproc; /* process that wants to write to tty */
- 11652 vir_bytes tty_out_vir; /* virtual address where data comes from */
- 11653 int tty_outleft; /* # chars yet to be output */
- 11654 int tty_outcum; /* # chars output so far */
- 11655 char tty_iocaller; /* process that made the call (usually FS) */
- 11656 char tty_ioproc; /* process that wants to do an ioctl */
- 11657 int tty_ioreq; /* ioctl request code */
- 11658 vir_bytes tty_iovir; /* virtual address of ioctl buffer */
- 11659
- 11660 /* Miscellaneous. */
- 11661 devfun_t tty_ioctl; /* set line speed, etc. at the device level */
- 11662 devfun_t tty_close; /* tell the device that the tty is closed */
- 11663 void *tty_priv; /* pointer to per device private data */
- 11664 struct termios tty_termios; /* terminal attributes */
- 11665 struct winsize tty_winsize; /* window size (#lines and #columns) */
- 11666
- 11667 u16_t tty_inbuf[TTY_IN_BYTES];/* tty input buffer */
- 11668 } tty_t;
- 11669
- 11670 EXTERN tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
- 11671
- 11672 /* Values for the fields. */
- 11673 #define NOT_ESCAPED 0 /* previous character is not LNEXT (^V) */
- 11674 #define ESCAPED 1 /* previous character was LNEXT (^V) */
- 11675 #define RUNNING 0 /* no STOP (^S) has been typed to stop output */
- 11676 #define STOPPED 1 /* STOP (^S) has been typed to stop output */
- 11677
- 11678 /* Fields and flags on characters in the input queue. */
- 11679 #define IN_CHAR 0x00FF /* low 8 bits are the character itself */
- 11680 #define IN_LEN 0x0F00 /* length of char if it has been echoed */
- 11681 #define IN_LSHIFT 8 /* length = (c & IN_LEN) >> IN_LSHIFT */
- 11682 #define IN_EOT 0x1000 /* char is a line break (^D, LF) */
- 11683 #define IN_EOF 0x2000 /* char is EOF (^D), do not return to user */
- 11684 #define IN_ESC 0x4000 /* escaped by LNEXT (^V), no interpretation */
- 11685
- 11686 /* Times and timeouts. */
- 11687 #define TIME_NEVER ((clock_t) -1 < 0 ? (clock_t) LONG_MAX : (clock_t) -1)
- 11688 #define force_timeout() ((void) (tty_timeout = 0))
- 11689
- 11690 EXTERN tty_t *tty_timelist; /* list of ttys with active timers */
- 11691
- 11692 /* Number of elements and limit of a buffer. */
- 11693 #define buflen(buf) (sizeof(buf) / sizeof((buf)[0]))
- 11694 #define bufend(buf) ((buf) + buflen(buf))
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/tty.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 11700 /* This file contains the terminal driver, both for the IBM console and regular
- 11701 * ASCII terminals. It handles only the device-independent part of a TTY, the
- 11702 * device dependent parts are in console.c, rs232.c, etc. This file contains
- 11703 * two main entry points, tty_task() and tty_wakeup(), and several minor entry
- 11704 * points for use by the device-dependent code.
- 11705 *
- 11706 * The device-independent part accepts "keyboard" input from the device-
- 11707 * dependent part, performs input processing (special key interpretation),
- 11708 * and sends the input to a process reading from the TTY. Output to a TTY
- 11709 * is sent to the device-dependent code for output processing and "screen"
- 11710 * display. Input processing is done by the device by calling 'in_process'
- 11711 * on the input characters, output processing may be done by the device itself
- 11712 * or by calling 'out_process'. The TTY takes care of input queuing, the
- 11713 * device does the output queuing. If a device receives an external signal,
- 11714 * like an interrupt, then it causes tty_wakeup() to be run by the CLOCK task
- 11715 * to, you guessed it, wake up the TTY to check if input or output can
- 11716 * continue.
- 11717 *
- 11718 * The valid messages and their parameters are:
- 11719 *
- 11720 * HARD_INT: output has been completed or input has arrived
- 11721 * DEV_READ: a process wants to read from a terminal
- 11722 * DEV_WRITE: a process wants to write on a terminal
- 11723 * DEV_IOCTL: a process wants to change a terminal's parameters
- 11724 * DEV_OPEN: a tty line has been opened
- 11725 * DEV_CLOSE: a tty line has been closed
- 11726 * CANCEL: terminate a previous incomplete system call immediately
- 11727 *
- 11728 * m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS
- 11729 * ---------------------------------------------------------------------------
- 11730 * | HARD_INT | | | | | | |
- 11731 * |-------------+---------+---------+---------+---------+---------+---------|
- 11732 * | DEV_READ |minor dev| proc nr | count | O_NONBLOCK| buf ptr |
- 11733 * |-------------+---------+---------+---------+---------+---------+---------|
- 11734 * | DEV_WRITE |minor dev| proc nr | count | | | buf ptr |
- 11735 * |-------------+---------+---------+---------+---------+---------+---------|
- 11736 * | DEV_IOCTL |minor dev| proc nr |func code|erase etc| flags | |
- 11737 * |-------------+---------+---------+---------+---------+---------+---------|
- 11738 * | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | | |
- 11739 * |-------------+---------+---------+---------+---------+---------+---------|
- 11740 * | DEV_CLOSE |minor dev| proc nr | | | | |
- 11741 * |-------------+---------+---------+---------+---------+---------+---------|
- 11742 * | CANCEL |minor dev| proc nr | | | | |
- 11743 * ---------------------------------------------------------------------------
- 11744 */
- 11745
- 11746 #include "kernel.h"
- 11747 #include <termios.h>
- 11748 #include <sys/ioctl.h>
- 11749 #include <signal.h>
- 11750 #include <minix/callnr.h>
- 11751 #include <minix/com.h>
- 11752 #include <minix/keymap.h>
- 11753 #include "tty.h"
- 11754 #include "proc.h"
- 11755
- 11756 /* Address of a tty structure. */
- 11757 #define tty_addr(line) (&tty_table[line])
- 11758
- 11759 /* First minor numbers for the various classes of TTY devices. */
- 11760 #define CONS_MINOR 0
- 11761 #define LOG_MINOR 15
- 11762 #define RS232_MINOR 16
- 11763 #define TTYPX_MINOR 128
- 11764 #define PTYPX_MINOR 192
- 11765
- 11766 /* Macros for magic tty types. */
- 11767 #define isconsole(tp) ((tp) < tty_addr(NR_CONS))
- 11768
- 11769 /* Macros for magic tty structure pointers. */
- 11770 #define FIRST_TTY tty_addr(0)
- 11771 #define END_TTY tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))
- 11772
- 11773 /* A device exists if at least its 'devread' function is defined. */
- 11774 #define tty_active(tp) ((tp)->tty_devread != NULL)
- 11775
- 11776 /* RS232 lines or pseudo terminals can be completely configured out. */
- 11777 #if NR_RS_LINES == 0
- 11778 #define rs_init(tp) ((void) 0)
- 11779 #endif
- 11780 #if NR_PTYS == 0
- 11781 #define pty_init(tp) ((void) 0)
- 11782 #define do_pty(tp, mp) ((void) 0)
- 11783 #endif
- 11784
- 11785 FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr) );
- 11786 FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr) );
- 11787 FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr) );
- 11788 FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr) );
- 11789 FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr) );
- 11790 FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr) );
- 11791 FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp) );
- 11792 FORWARD _PROTOTYPE( int echo, (tty_t *tp, int ch) );
- 11793 FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch) );
- 11794 FORWARD _PROTOTYPE( int back_over, (tty_t *tp) );
- 11795 FORWARD _PROTOTYPE( void reprint, (tty_t *tp) );
- 11796 FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp) );
- 11797 FORWARD _PROTOTYPE( void setattr, (tty_t *tp) );
- 11798 FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp) );
- 11799 FORWARD _PROTOTYPE( void tty_init, (tty_t *tp) );
- 11800 FORWARD _PROTOTYPE( void settimer, (tty_t *tp, int on) );
- 11801
- 11802 /* Default attributes. */
- 11803 PRIVATE struct termios termios_defaults = {
- 11804 TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
- 11805 {
- 11806 TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
- 11807 TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
- 11808 TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
- 11809 },
- 11810 };
- 11811 PRIVATE struct winsize winsize_defaults; /* = all zeroes */
- 11812
- 11813
- 11814 /*===========================================================================*
- 11815 * tty_task *
- 11816 *===========================================================================*/
- 11817 PUBLIC void tty_task()
- 11818 {
- 11819 /* Main routine of the terminal task. */
- 11820
- 11821 message tty_mess; /* buffer for all incoming messages */
- 11822 register tty_t *tp;
- 11823 unsigned line;
- 11824
- 11825 /* Initialize the terminal lines. */
- 11826 for (tp = FIRST_TTY; tp < END_TTY; tp++) tty_init(tp);
- 11827
- 11828 /* Display the Minix startup banner. */
- 11829 printf("Minix %s.%s Copyright 1997 Prentice-Hall, Inc.nn",
- 11830 OS_RELEASE, OS_VERSION);
- 11831 printf("Executing in 32-bit protected modenn");
- 11832
- 11833 while (TRUE) {
- 11834 /* Handle any events on any of the ttys. */
- 11835 for (tp = FIRST_TTY; tp < END_TTY; tp++) {
- 11836 if (tp->tty_events) handle_events(tp);
- 11837 }
- 11838
- 11839 receive(ANY, &tty_mess);
- 11840
- 11841 /* A hardware interrupt is an invitation to check for events. */
- 11842 if (tty_mess.m_type == HARD_INT) continue;
- 11843
- 11844 /* Check the minor device number. */
- 11845 line = tty_mess.TTY_LINE;
- 11846 if ((line - CONS_MINOR) < NR_CONS) {
- 11847 tp = tty_addr(line - CONS_MINOR);
- 11848 } else
- 11849 if (line == LOG_MINOR) {
- 11850 tp = tty_addr(0);
- 11851 } else
- 11852 if ((line - RS232_MINOR) < NR_RS_LINES) {
- 11853 tp = tty_addr(line - RS232_MINOR + NR_CONS);
- 11854 } else
- 11855 if ((line - TTYPX_MINOR) < NR_PTYS) {
- 11856 tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
- 11857 } else
- 11858 if ((line - PTYPX_MINOR) < NR_PTYS) {
- 11859 tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
- 11860 do_pty(tp, &tty_mess);
- 11861 continue; /* this is a pty, not a tty */
- 11862 } else {
- 11863 tp = NULL;
- 11864 }
- 11865
- 11866 /* If the device doesn't exist or is not configured return ENXIO. */
- 11867 if (tp == NULL || !tty_active(tp)) {
- 11868 tty_reply(TASK_REPLY, tty_mess.m_source,
- 11869 tty_mess.PROC_NR, ENXIO);
- 11870 continue;
- 11871 }
- 11872
- 11873 /* Execute the requested function. */
- 11874 switch (tty_mess.m_type) {
- 11875 case DEV_READ: do_read(tp, &tty_mess); break;
- 11876 case DEV_WRITE: do_write(tp, &tty_mess); break;
- 11877 case DEV_IOCTL: do_ioctl(tp, &tty_mess); break;
- 11878 case DEV_OPEN: do_open(tp, &tty_mess); break;
- 11879 case DEV_CLOSE: do_close(tp, &tty_mess); break;
- 11880 case CANCEL: do_cancel(tp, &tty_mess); break;
- 11881 default: tty_reply(TASK_REPLY, tty_mess.m_source,
- 11882 tty_mess.PROC_NR, EINVAL);
- 11883 }
- 11884 }
- 11885 }
- 11888 /*===========================================================================*
- 11889 * do_read *
- 11890 *===========================================================================*/
- 11891 PRIVATE void do_read(tp, m_ptr)
- 11892 register tty_t *tp; /* pointer to tty struct */
- 11893 message *m_ptr; /* pointer to message sent to the task */
- 11894 {
- 11895 /* A process wants to read from a terminal. */
- 11896 int r;
- 11897
- 11898 /* Check if there is already a process hanging in a read, check if the
- 11899 * parameters are correct, do I/O.
- 11900 */
- 11901 if (tp->tty_inleft > 0) {
- 11902 r = EIO;
- 11903 } else
- 11904 if (m_ptr->COUNT <= 0) {
- 11905 r = EINVAL;
- 11906 } else
- 11907 if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
- 11908 r = EFAULT;
- 11909 } else {
- 11910 /* Copy information from the message to the tty struct. */
- 11911 tp->tty_inrepcode = TASK_REPLY;
- 11912 tp->tty_incaller = m_ptr->m_source;
- 11913 tp->tty_inproc = m_ptr->PROC_NR;
- 11914 tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
- 11915 tp->tty_inleft = m_ptr->COUNT;
- 11916
- 11917 if (!(tp->tty_termios.c_lflag & ICANON)
- 11918 && tp->tty_termios.c_cc[VTIME] > 0) {
- 11919 if (tp->tty_termios.c_cc[VMIN] == 0) {
- 11920 /* MIN & TIME specify a read timer that finishes the
- 11921 * read in TIME/10 seconds if no bytes are available.
- 11922 */
- 11923 lock();
- 11924 settimer(tp, TRUE);
- 11925 tp->tty_min = 1;
- 11926 unlock();
- 11927 } else {
- 11928 /* MIN & TIME specify an inter-byte timer that may
- 11929 * have to be cancelled if there are no bytes yet.
- 11930 */
- 11931 if (tp->tty_eotct == 0) {
- 11932 lock();
- 11933 settimer(tp, FALSE);
- 11934 unlock();
- 11935 tp->tty_min = tp->tty_termios.c_cc[VMIN];
- 11936 }
- 11937 }
- 11938 }
- 11939
- 11940 /* Anything waiting in the input buffer? Clear it out... */
- 11941 in_transfer(tp);
- 11942 /* ...then go back for more */
- 11943 handle_events(tp);
- 11944 if (tp->tty_inleft == 0) return; /* already done */
- 11945
- 11946 /* There were no bytes in the input queue available, so either suspend
- 11947 * the caller or break off the read if nonblocking.
- 11948 */
- 11949 if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
- 11950 r = EAGAIN; /* cancel the read */
- 11951 tp->tty_inleft = tp->tty_incum = 0;
- 11952 } else {
- 11953 r = SUSPEND; /* suspend the caller */
- 11954 tp->tty_inrepcode = REVIVE;
- 11955 }
- 11956 }
- 11957 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
- 11958 }
- 11961 /*===========================================================================*
- 11962 * do_write *
- 11963 *===========================================================================*/
- 11964 PRIVATE void do_write(tp, m_ptr)
- 11965 register tty_t *tp;
- 11966 register message *m_ptr; /* pointer to message sent to the task */
- 11967 {
- 11968 /* A process wants to write on a terminal. */
- 11969 int r;
- 11970
- 11971 /* Check if there is already a process hanging in a write, check if the
- 11972 * parameters are correct, do I/O.
- 11973 */
- 11974 if (tp->tty_outleft > 0) {
- 11975 r = EIO;
- 11976 } else
- 11977 if (m_ptr->COUNT <= 0) {
- 11978 r = EINVAL;
- 11979 } else
- 11980 if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
- 11981 r = EFAULT;
- 11982 } else {
- 11983 /* Copy message parameters to the tty structure. */
- 11984 tp->tty_outrepcode = TASK_REPLY;
- 11985 tp->tty_outcaller = m_ptr->m_source;
- 11986 tp->tty_outproc = m_ptr->PROC_NR;
- 11987 tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
- 11988 tp->tty_outleft = m_ptr->COUNT;
- 11989
- 11990 /* Try to write. */
- 11991 handle_events(tp);
- 11992 if (tp->tty_outleft == 0) return; /* already done */
- 11993
- 11994 /* None or not all the bytes could be written, so either suspend the
- 11995 * caller or break off the write if nonblocking.
- 11996 */
- 11997 if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* cancel the write */
- 11998 r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
- 11999 tp->tty_outleft = tp->tty_outcum = 0;
- 12000 } else {
- 12001 r = SUSPEND; /* suspend the caller */
- 12002 tp->tty_outrepcode = REVIVE;
- 12003 }
- 12004 }
- 12005 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
- 12006 }
- 12009 /*===========================================================================*
- 12010 * do_ioctl *
- 12011 *===========================================================================*/
- 12012 PRIVATE void do_ioctl(tp, m_ptr)
- 12013 register tty_t *tp;
- 12014 message *m_ptr; /* pointer to message sent to task */
- 12015 {
- 12016 /* Perform an IOCTL on this terminal. Posix termios calls are handled
- 12017 * by the IOCTL system call
- 12018 */
- 12019
- 12020 int r;
- 12021 union {
- 12022 int i;
- 12023 /* these non-Posix params are not used now, but the union is retained
- 12024 * to minimize code differences with backward compatible version
- 12025 * struct sgttyb sg;
- 12026 * struct tchars tc;
- 12027 */
- 12028 } param;
- 12029 phys_bytes user_phys;
- 12030 size_t size;
- 12031
- 12032 /* Size of the ioctl parameter. */
- 12033 switch (m_ptr->TTY_REQUEST) {
- 12034 case TCGETS: /* Posix tcgetattr function */
- 12035 case TCSETS: /* Posix tcsetattr function, TCSANOW option */
- 12036 case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
- 12037 case TCSETSF: /* Posix tcsetattr function, TCSAFLUSH option */
- 12038 size = sizeof(struct termios);
- 12039 break;
- 12040
- 12041 case TCSBRK: /* Posix tcsendbreak function */
- 12042 case TCFLOW: /* Posix tcflow function */
- 12043 case TCFLSH: /* Posix tcflush function */
- 12044 case TIOCGPGRP: /* Posix tcgetpgrp function */
- 12045 case TIOCSPGRP: /* Posix tcsetpgrp function */
- 12046 size = sizeof(int);
- 12047 break;
- 12048
- 12049 case TIOCGWINSZ: /* get window size (not Posix) */
- 12050 case TIOCSWINSZ: /* set window size (not Posix) */
- 12051 size = sizeof(struct winsize);
- 12052 break;
- 12053
- 12054 case KIOCSMAP: /* load keymap (Minix extension) */
- 12055 size = sizeof(keymap_t);
- 12056 break;
- 12057
- 12058 case TIOCSFON: /* load font (Minix extension) */
- 12059 size = sizeof(u8_t [8192]);
- 12060 break;
- 12061
- 12062 case TCDRAIN: /* Posix tcdrain function -- no parameter */
- 12063 default: size = 0;
- 12064 }
- 12065
- 12066 if (size != 0) {
- 12067 user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, size);
- 12068 if (user_phys == 0) {
- 12069 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EFAULT);
- 12070 return;
- 12071 }
- 12072 }
- 12073
- 12074 r = OK;
- 12075 switch (m_ptr->TTY_REQUEST) {
- 12076 case TCGETS:
- 12077 /* Get the termios attributes. */
- 12078 phys_copy(vir2phys(&tp->tty_termios), user_phys, (phys_bytes) size);
- 12079 break;
- 12080
- 12081 case TCSETSW:
- 12082 case TCSETSF:
- 12083 case TCDRAIN:
- 12084 if (tp->tty_outleft > 0) {
- 12085 /* Wait for all ongoing output processing to finish. */
- 12086 tp->tty_iocaller = m_ptr->m_source;
- 12087 tp->tty_ioproc = m_ptr->PROC_NR;
- 12088 tp->tty_ioreq = m_ptr->REQUEST;
- 12089 tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
- 12090 r = SUSPEND;
- 12091 break;
- 12092 }
- 12093 if (m_ptr->TTY_REQUEST == TCDRAIN) break;
- 12094 if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
- 12095 /*FALL THROUGH*/
- 12096 case TCSETS:
- 12097 /* Set the termios attributes. */
- 12098 phys_copy(user_phys, vir2phys(&tp->tty_termios), (phys_bytes) size);
- 12099 setattr(tp);
- 12100 break;
- 12101
- 12102 case TCFLSH:
- 12103 phys_copy(user_phys, vir2phys(¶m.i), (phys_bytes) size);
- 12104 switch (param.i) {
- 12105 case TCIFLUSH: tty_icancel(tp); break;
- 12106 case TCOFLUSH: (*tp->tty_ocancel)(tp); break;
- 12107 case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp);break;
- 12108 default: r = EINVAL;
- 12109 }
- 12110 break;
- 12111
- 12112 case TCFLOW:
- 12113 phys_copy(user_phys, vir2phys(¶m.i), (phys_bytes) size);
- 12114 switch (param.i) {
- 12115 case TCOOFF:
- 12116 case TCOON:
- 12117 tp->tty_inhibited = (param.i == TCOOFF);
- 12118 tp->tty_events = 1;
- 12119 break;
- 12120 case TCIOFF:
- 12121 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]);
- 12122 break;
- 12123 case TCION:
- 12124 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]);
- 12125 break;
- 12126 default:
- 12127 r = EINVAL;
- 12128 }
- 12129 break;
- 12130
- 12131 case TCSBRK:
- 12132 if (tp->tty_break != NULL) (*tp->tty_break)(tp);
- 12133 break;
- 12134
- 12135 case TIOCGWINSZ:
- 12136 phys_copy(vir2phys(&tp->tty_winsize), user_phys, (phys_bytes) size);
- 12137 break;
- 12138
- 12139 case TIOCSWINSZ:
- 12140 phys_copy(user_phys, vir2phys(&tp->tty_winsize), (phys_bytes) size);
- 12141 /* SIGWINCH... */
- 12142 break;
- 12143
- 12144 case KIOCSMAP:
- 12145 /* Load a new keymap (only /dev/console). */
- 12146 if (isconsole(tp)) r = kbd_loadmap(user_phys);
- 12147 break;
- 12148
- 12149 case TIOCSFON:
- 12150 /* Load a font into an EGA or VGA card (hs@hck.hr) */
- 12151 if (isconsole(tp)) r = con_loadfont(user_phys);
- 12152 break;
- 12153
- 12154 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is
- 12155 * not defined.
- 12156 */
- 12157 case TIOCGPGRP:
- 12158 case TIOCSPGRP:
- 12159 default:
- 12160 r = ENOTTY;
- 12161 }
- 12162
- 12163 /* Send the reply. */
- 12164 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
- 12165 }
- 12168 /*===========================================================================*
- 12169 * do_open *
- 12170 *===========================================================================*/
- 12171 PRIVATE void do_open(tp, m_ptr)
- 12172 register tty_t *tp;
- 12173 message *m_ptr; /* pointer to message sent to task */
- 12174 {
- 12175 /* A tty line has been opened. Make it the callers controlling tty if
- 12176 * O_NOCTTY is *not* set and it is not the log device. 1 is returned if
- 12177 * the tty is made the controlling tty, otherwise OK or an error code.
- 12178 */
- 12179 int r = OK;
- 12180
- 12181 if (m_ptr->TTY_LINE == LOG_MINOR) {
- 12182 /* The log device is a write-only diagnostics device. */
- 12183 if (m_ptr->COUNT & R_BIT) r = EACCES;
- 12184 } else {
- 12185 if (!(m_ptr->COUNT & O_NOCTTY)) {
- 12186 tp->tty_pgrp = m_ptr->PROC_NR;
- 12187 r = 1;
- 12188 }
- 12189 tp->tty_openct++;
- 12190 }
- 12191 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
- 12192 }
- 12195 /*===========================================================================*
- 12196 * do_close *
- 12197 *===========================================================================*/
- 12198 PRIVATE void do_close(tp, m_ptr)
- 12199 register tty_t *tp;
- 12200 message *m_ptr; /* pointer to message sent to task */
- 12201 {
- 12202 /* A tty line has been closed. Clean up the line if it is the last close. */
- 12203
- 12204 if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
- 12205 tp->tty_pgrp = 0;
- 12206 tty_icancel(tp);
- 12207 (*tp->tty_ocancel)(tp);
- 12208 (*tp->tty_close)(tp);
- 12209 tp->tty_termios = termios_defaults;
- 12210 tp->tty_winsize = winsize_defaults;
- 12211 setattr(tp);
- 12212 }
- 12213 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
- 12214 }
- 12217 /*===========================================================================*
- 12218 * do_cancel *
- 12219 *===========================================================================*/
- 12220 PRIVATE void do_cancel(tp, m_ptr)
- 12221 register tty_t *tp;
- 12222 message *m_ptr; /* pointer to message sent to task */
- 12223 {
- 12224 /* A signal has been sent to a process that is hanging trying to read or write.
- 12225 * The pending read or write must be finished off immediately.
- 12226 */
- 12227
- 12228 int proc_nr;
- 12229 int mode;
- 12230
- 12231 /* Check the parameters carefully, to avoid cancelling twice. */
- 12232 proc_nr = m_ptr->PROC_NR;
- 12233 mode = m_ptr->COUNT;
- 12234 if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
- 12235 /* Process was reading when killed. Clean up input. */
- 12236 tty_icancel(tp);
- 12237 tp->tty_inleft = tp->tty_incum = 0;
- 12238 }
- 12239 if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
- 12240 /* Process was writing when killed. Clean up output. */
- 12241 (*tp->tty_ocancel)(tp);
- 12242 tp->tty_outleft = tp->tty_outcum = 0;
- 12243 }
- 12244 if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
- 12245 /* Process was waiting for output to drain. */
- 12246 tp->tty_ioreq = 0;
- 12247 }
- 12248 tp->tty_events = 1;
- 12249 tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
- 12250 }
- 12253 /*===========================================================================*
- 12254 * handle_events *
- 12255 *===========================================================================*/
- 12256 PUBLIC void handle_events(tp)
- 12257 tty_t *tp; /* TTY to check for events. */
- 12258 {
- 12259 /* Handle any events pending on a TTY. These events are usually device
- 12260 * interrupts.
- 12261 *
- 12262 * Two kinds of events are prominent:
- 12263 * - a character has been received from the console or an RS232 line.
- 12264 * - an RS232 line has completed a write request (on behalf of a user).
- 12265 * The interrupt handler may delay the interrupt message at its discretion
- 12266 * to avoid swamping the TTY task. Messages may be overwritten when the
- 12267 * lines are fast or when there are races between different lines, input
- 12268 * and output, because MINIX only provides single buffering for interrupt
- 12269 * messages (in proc.c). This is handled by explicitly checking each line
- 12270 * for fresh input and completed output on each interrupt.
- 12271 */
- 12272 char *buf;
- 12273 unsigned count;
- 12274
- 12275 do {
- 12276 tp->tty_events = 0;
- 12277
- 12278 /* Read input and perform input processing. */
- 12279 (*tp->tty_devread)(tp);
- 12280
- 12281 /* Perform output processing and write output. */
- 12282 (*tp->tty_devwrite)(tp);
- 12283
- 12284 /* Ioctl waiting for some event? */
- 12285 if (tp->tty_ioreq != 0) dev_ioctl(tp);
- 12286 } while (tp->tty_events);
- 12287
- 12288 /* Transfer characters from the input queue to a waiting process. */
- 12289 in_transfer(tp);
- 12290
- 12291 /* Reply if enough bytes are available. */
- 12292 if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
- 12293 tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
- 12294 tp->tty_incum);
- 12295 tp->tty_inleft = tp->tty_incum = 0;
- 12296 }
- 12297 }
- 12300 /*===========================================================================*
- 12301 * in_transfer *
- 12302 *===========================================================================*/
- 12303 PRIVATE void in_transfer(tp)
- 12304 register tty_t *tp; /* pointer to terminal to read from */
- 12305 {
- 12306 /* Transfer bytes from the input queue to a process reading from a terminal. */
- 12307
- 12308 int ch;
- 12309 int count;
- 12310 phys_bytes buf_phys, user_base;
- 12311 char buf[64], *bp;
- 12312
- 12313 /* Anything to do? */
- 12314 if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return;
- 12315
- 12316 buf_phys = vir2phys(buf);
- 12317 user_base = proc_vir2phys(proc_addr(tp->tty_inproc), 0);
- 12318 bp = buf;
- 12319 while (tp->tty_inleft > 0 && tp->tty_eotct > 0) {
- 12320 ch = *tp->tty_intail;
- 12321
- 12322 if (!(ch & IN_EOF)) {
- 12323 /* One character to be delivered to the user. */
- 12324 *bp = ch & IN_CHAR;
- 12325 tp->tty_inleft--;
- 12326 if (++bp == bufend(buf)) {
- 12327 /* Temp buffer full, copy to user space. */
- 12328 phys_copy(buf_phys, user_base + tp->tty_in_vir,
- 12329 (phys_bytes) buflen(buf));
- 12330 tp->tty_in_vir += buflen(buf);
- 12331 tp->tty_incum += buflen(buf);
- 12332 bp = buf;
- 12333 }
- 12334 }
- 12335
- 12336 /* Remove the character from the input queue. */
- 12337 if (++tp->tty_intail == bufend(tp->tty_inbuf))
- 12338 tp->tty_intail = tp->tty_inbuf;
- 12339 tp->tty_incount--;
- 12340 if (ch & IN_EOT) {
- 12341 tp->tty_eotct--;
- 12342 /* Don't read past a line break in canonical mode. */
- 12343 if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0;
- 12344 }
- 12345 }
- 12346
- 12347 if (bp > buf) {
- 12348 /* Leftover characters in the buffer. */
- 12349 count = bp - buf;
- 12350 phys_copy(buf_phys, user_base + tp->tty_in_vir, (phys_bytes) count);
- 12351 tp->tty_in_vir += count;
- 12352 tp->tty_incum += count;
- 12353 }
- 12354
- 12355 /* Usually reply to the reader, possibly even if incum == 0 (EOF). */
- 12356 if (tp->tty_inleft == 0) {
- 12357 tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
- 12358 tp->tty_incum);
- 12359 tp->tty_inleft = tp->tty_incum = 0;
- 12360 }
- 12361 }
- 12364 /*===========================================================================*
- 12365 * in_process *
- 12366 *===========================================================================*/
- 12367 PUBLIC int in_process(tp, buf, count)
- 12368 register tty_t *tp; /* terminal on which character has arrived */
- 12369 char *buf; /* buffer with input characters */
- 12370 int count; /* number of input characters */
- 12371 {
- 12372 /* Characters have just been typed in. Process, save, and echo them. Return
- 12373 * the number of characters processed.
- 12374 */
- 12375
- 12376 int ch, sig, ct;
- 12377 int timeset = FALSE;
- 12378 static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF };
- 12379
- 12380 for (ct = 0; ct < count; ct++) {
- 12381 /* Take one character. */
- 12382 ch = *buf++ & BYTE;
- 12383
- 12384 /* Strip to seven bits? */
- 12385 if (tp->tty_termios.c_iflag & ISTRIP) ch &= 0x7F;
- 12386
- 12387 /* Input extensions? */
- 12388 if (tp->tty_termios.c_lflag & IEXTEN) {
- 12389
- 12390 /* Previous character was a character escape? */
- 12391 if (tp->tty_escaped) {
- 12392 tp->tty_escaped = NOT_ESCAPED;
- 12393 ch |= IN_ESC; /* protect character */
- 12394 }
- 12395
- 12396 /* LNEXT (^V) to escape the next character? */
- 12397 if (ch == tp->tty_termios.c_cc[VLNEXT]) {
- 12398 tp->tty_escaped = ESCAPED;
- 12399 rawecho(tp, '^');
- 12400 rawecho(tp, 'b');
- 12401 continue; /* do not store the escape */
- 12402 }
- 12403
- 12404 /* REPRINT (^R) to reprint echoed characters? */
- 12405 if (ch == tp->tty_termios.c_cc[VREPRINT]) {
- 12406 reprint(tp);
- 12407 continue;
- 12408 }
- 12409 }
- 12410
- 12411 /* _POSIX_VDISABLE is a normal character value, so better escape it. */
- 12412 if (ch == _POSIX_VDISABLE) ch |= IN_ESC;
- 12413
- 12414 /* Map CR to LF, ignore CR, or map LF to CR. */
- 12415 if (ch == 'r') {
- 12416 if (tp->tty_termios.c_iflag & IGNCR) continue;
- 12417 if (tp->tty_termios.c_iflag & ICRNL) ch = 'n';
- 12418 } else
- 12419 if (ch == 'n') {
- 12420 if (tp->tty_termios.c_iflag & INLCR) ch = 'r';
- 12421 }
- 12422
- 12423 /* Canonical mode? */
- 12424 if (tp->tty_termios.c_lflag & ICANON) {
- 12425
- 12426 /* Erase processing (rub out of last character). */
- 12427 if (ch == tp->tty_termios.c_cc[VERASE]) {
- 12428 (void) back_over(tp);
- 12429 if (!(tp->tty_termios.c_lflag & ECHOE)) {
- 12430 (void) echo(tp, ch);
- 12431 }
- 12432 continue;
- 12433 }
- 12434
- 12435 /* Kill processing (remove current line). */
- 12436 if (ch == tp->tty_termios.c_cc[VKILL]) {
- 12437 while (back_over(tp)) {}
- 12438 if (!(tp->tty_termios.c_lflag & ECHOE)) {
- 12439 (void) echo(tp, ch);
- 12440 if (tp->tty_termios.c_lflag & ECHOK)
- 12441 rawecho(tp, 'n');
- 12442 }
- 12443 continue;
- 12444 }
- 12445
- 12446 /* EOF (^D) means end-of-file, an invisible "line break". */
- 12447 if (ch == tp->tty_termios.c_cc[VEOF]) ch |= IN_EOT | IN_EOF;
- 12448
- 12449 /* The line may be returned to the user after an LF. */
- 12450 if (ch == 'n') ch |= IN_EOT;
- 12451
- 12452 /* Same thing with EOL, whatever it may be. */
- 12453 if (ch == tp->tty_termios.c_cc[VEOL]) ch |= IN_EOT;
- 12454 }
- 12455
- 12456 /* Start/stop input control? */
- 12457 if (tp->tty_termios.c_iflag & IXON) {
- 12458
- 12459 /* Output stops on STOP (^S). */
- 12460 if (ch == tp->tty_termios.c_cc[VSTOP]) {
- 12461 tp->tty_inhibited = STOPPED;
- 12462 tp->tty_events = 1;
- 12463 continue;
- 12464 }
- 12465
- 12466 /* Output restarts on START (^Q) or any character if IXANY. */
- 12467 if (tp->tty_inhibited) {
- 12468 if (ch == tp->tty_termios.c_cc[VSTART]
- 12469 || (tp->tty_termios.c_iflag & IXANY)) {
- 12470 tp->tty_inhibited = RUNNING;
- 12471 tp->tty_events = 1;
- 12472 if (ch == tp->tty_termios.c_cc[VSTART])
- 12473 continue;
- 12474 }
- 12475 }
- 12476 }
- 12477
- 12478 if (tp->tty_termios.c_lflag & ISIG) {
- 12479 /* Check for INTR (^?) and QUIT (^) characters. */
- 12480 if (ch == tp->tty_termios.c_cc[VINTR]
- 12481 || ch == tp->tty_termios.c_cc[VQUIT]) {
- 12482 sig = SIGINT;
- 12483 if (ch == tp->tty_termios.c_cc[VQUIT]) sig = SIGQUIT;
- 12484 sigchar(tp, sig);
- 12485 (void) echo(tp, ch);
- 12486 continue;
- 12487 }
- 12488 }
- 12489
- 12490 /* Is there space in the input buffer? */
- 12491 if (tp->tty_incount == buflen(tp->tty_inbuf)) {
- 12492 /* No space; discard in canonical mode, keep in raw mode. */
- 12493 if (tp->tty_termios.c_lflag & ICANON) continue;
- 12494 break;
- 12495 }
- 12496
- 12497 if (!(tp->tty_termios.c_lflag & ICANON)) {
- 12498 /* In raw mode all characters are "line breaks". */
- 12499 ch |= IN_EOT;
- 12500
- 12501 /* Start an inter-byte timer? */
- 12502 if (!timeset && tp->tty_termios.c_cc[VMIN] > 0
- 12503 && tp->tty_termios.c_cc[VTIME] > 0) {
- 12504 lock();
- 12505 settimer(tp, TRUE);
- 12506 unlock();
- 12507 timeset = TRUE;
- 12508 }
- 12509 }
- 12510
- 12511 /* Perform the intricate function of echoing. */
- 12512 if (tp->tty_termios.c_lflag & (ECHO|ECHONL)) ch = echo(tp, ch);
- 12513
- 12514 /* Save the character in the input queue. */
- 12515 *tp->tty_inhead++ = ch;
- 12516 if (tp->tty_inhead == bufend(tp->tty_inbuf))
- 12517 tp->tty_inhead = tp->tty_inbuf;
- 12518 tp->tty_incount++;
- 12519 if (ch & IN_EOT) tp->tty_eotct++;
- 12520
- 12521 /* Try to finish input if the queue threatens to overflow. */
- 12522 if (tp->tty_incount == buflen(tp->tty_inbuf)) in_transfer(tp);
- 12523 }
- 12524 return ct;
- 12525 }
- 12528 /*===========================================================================*
- 12529 * echo *
- 12530 *===========================================================================*/
- 12531 PRIVATE int echo(tp, ch)
- 12532 register tty_t *tp; /* terminal on which to echo */
- 12533 register int ch; /* pointer to character to echo */
- 12534 {
- 12535 /* Echo the character if echoing is on. Some control characters are echoed
- 12536 * with their normal effect, other control characters are echoed as "^X",
- 12537 * normal characters are echoed normally. EOF (^D) is echoed, but immediately
- 12538 * backspaced over. Return the character with the echoed length added to its
- 12539 * attributes.
- 12540 */
- 12541 int len, rp;
- 12542
- 12543 ch &= ~IN_LEN;
- 12544 if (!(tp->tty_termios.c_lflag & ECHO)) {
- 12545 if (ch == ('n' | IN_EOT) && (tp->tty_termios.c_lflag
- 12546 & (ICANON|ECHONL)) == (ICANON|ECHONL))
- 12547 (*tp->tty_echo)(tp, 'n');
- 12548 return(ch);
- 12549 }
- 12550
- 12551 /* "Reprint" tells if the echo output has been messed up by other output. */
- 12552 rp = tp->tty_incount == 0 ? FALSE : tp->tty_reprint;
- 12553
- 12554 if ((ch & IN_CHAR) < ' ') {
- 12555 switch (ch & (IN_ESC|IN_EOF|IN_EOT|IN_CHAR)) {
- 12556 case 't':
- 12557 len = 0;
- 12558 do {
- 12559 (*tp->tty_echo)(tp, ' ');
- 12560 len++;
- 12561 } while (len < TAB_SIZE && (tp->tty_position & TAB_MASK) != 0);
- 12562 break;
- 12563 case 'r' | IN_EOT:
- 12564 case 'n' | IN_EOT:
- 12565 (*tp->tty_echo)(tp, ch & IN_CHAR);
- 12566 len = 0;
- 12567 break;
- 12568 default:
- 12569 (*tp->tty_echo)(tp, '^');
- 12570 (*tp->tty_echo)(tp, '@' + (ch & IN_CHAR));
- 12571 len = 2;
- 12572 }
- 12573 } else
- 12574 if ((ch & IN_CHAR) == '177') {
- 12575 /* A DEL prints as "^?". */
- 12576 (*tp->tty_echo)(tp, '^');
- 12577 (*tp->tty_echo)(tp, '?');
- 12578 len = 2;
- 12579 } else {
- 12580 (*tp->tty_echo)(tp, ch & IN_CHAR);
- 12581 len = 1;
- 12582 }
- 12583 if (ch & IN_EOF) while (len > 0) { (*tp->tty_echo)(tp, 'b'); len--; }
- 12584
- 12585 tp->tty_reprint = rp;
- 12586 return(ch | (len << IN_LSHIFT));
- 12587 }
- 12590 /*==========================================================================*
- 12591 * rawecho *
- 12592 *==========================================================================*/
- 12593 PRIVATE void rawecho(tp, ch)
- 12594 register tty_t *tp;
- 12595 int ch;
- 12596 {
- 12597 /* Echo without interpretation if ECHO is set. */
- 12598 int rp = tp->tty_reprint;
- 12599 if (tp->tty_termios.c_lflag & ECHO) (*tp->tty_echo)(tp, ch);
- 12600 tp->tty_reprint = rp;
- 12601 }
- 12604 /*==========================================================================*
- 12605 * back_over *
- 12606 *==========================================================================*/
- 12607 PRIVATE int back_over(tp)
- 12608 register tty_t *tp;
- 12609 {
- 12610 /* Backspace to previous character on screen and erase it. */
- 12611 u16_t *head;
- 12612 int len;
- 12613
- 12614 if (tp->tty_incount == 0) return(0); /* queue empty */
- 12615 head = tp->tty_inhead;
- 12616 if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
- 12617 if (*--head & IN_EOT) return(0); /* can't erase "line breaks" */
- 12618 if (tp->tty_reprint) reprint(tp); /* reprint if messed up */
- 12619 tp->tty_inhead = head;
- 12620 tp->tty_incount--;
- 12621 if (tp->tty_termios.c_lflag & ECHOE) {
- 12622 len = (*head & IN_LEN) >> IN_LSHIFT;
- 12623 while (len > 0) {
- 12624 rawecho(tp, 'b');
- 12625 rawecho(tp, ' ');
- 12626 rawecho(tp, 'b');
- 12627 len--;
- 12628 }
- 12629 }
- 12630 return(1); /* one character erased */
- 12631 }
- 12634 /*==========================================================================*
- 12635 * reprint *
- 12636 *==========================================================================*/
- 12637 PRIVATE void reprint(tp)
- 12638 register tty_t *tp; /* pointer to tty struct */
- 12639 {
- 12640 /* Restore what has been echoed to screen before if the user input has been
- 12641 * messed up by output, or if REPRINT (^R) is typed.
- 12642 */
- 12643 int count;
- 12644 u16_t *head;
- 12645
- 12646 tp->tty_reprint = FALSE;
- 12647
- 12648 /* Find the last line break in the input. */
- 12649 head = tp->tty_inhead;
- 12650 count = tp->tty_incount;
- 12651 while (count > 0) {
- 12652 if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
- 12653 if (head[-1] & IN_EOT) break;
- 12654 head--;
- 12655 count--;
- 12656 }
- 12657 if (count == tp->tty_incount) return; /* no reason to reprint */
- 12658
- 12659 /* Show REPRINT (^R) and move to a new line. */
- 12660 (void) echo(tp, tp->tty_termios.c_cc[VREPRINT] | IN_ESC);
- 12661 rawecho(tp, 'r');
- 12662 rawecho(tp, 'n');
- 12663
- 12664 /* Reprint from the last break onwards. */
- 12665 do {
- 12666 if (head == bufend(tp->tty_inbuf)) head = tp->tty_inbuf;
- 12667 *head = echo(tp, *head);
- 12668 head++;
- 12669 count++;
- 12670 } while (count < tp->tty_incount);
- 12671 }
- 12674 /*==========================================================================*
- 12675 * out_process *
- 12676 *==========================================================================*/
- 12677 PUBLIC void out_process(tp, bstart, bpos, bend, icount, ocount)
- 12678 tty_t *tp;
- 12679 char *bstart, *bpos, *bend; /* start/pos/end of circular buffer */
- 12680 int *icount; /* # input chars / input chars used */
- 12681 int *ocount; /* max output chars / output chars used */
- 12682 {
- 12683 /* Perform output processing on a circular buffer. *icount is the number of
- 12684 * bytes to process, and the number of bytes actually processed on return.
- 12685 * *ocount is the space available on input and the space used on output.
- 12686 * (Naturally *icount < *ocount.) The column position is updated modulo
- 12687 * the TAB size, because we really only need it for tabs.
- 12688 */
- 12689
- 12690 int tablen;
- 12691 int ict = *icount;
- 12692 int oct = *ocount;
- 12693 int pos = tp->tty_position;
- 12694
- 12695 while (ict > 0) {
- 12696 switch (*bpos) {
- 12697 case '7':
- 12698 break;
- 12699 case 'b':
- 12700 pos--;
- 12701 break;
- 12702 case 'r':
- 12703 pos = 0;
- 12704 break;
- 12705 case 'n':
- 12706 if ((tp->tty_termios.c_oflag & (OPOST|ONLCR))
- 12707 == (OPOST|ONLCR)) {
- 12708 /* Map LF to CR+LF if there is space. Note that the
- 12709 * next character in the buffer is overwritten, so
- 12710 * we stop at this point.
- 12711 */
- 12712 if (oct >= 2) {
- 12713 *bpos = 'r';
- 12714 if (++bpos == bend) bpos = bstart;
- 12715 *bpos = 'n';
- 12716 pos = 0;
- 12717 ict--;
- 12718 oct -= 2;
- 12719 }
- 12720 goto out_done; /* no space or buffer got changed */
- 12721 }
- 12722 break;
- 12723 case 't':
- 12724 /* Best guess for the tab length. */
- 12725 tablen = TAB_SIZE - (pos & TAB_MASK);
- 12726
- 12727 if ((tp->tty_termios.c_oflag & (OPOST|XTABS))
- 12728 == (OPOST|XTABS)) {
- 12729 /* Tabs must be expanded. */
- 12730 if (oct >= tablen) {
- 12731 pos += tablen;
- 12732 ict--;
- 12733 oct -= tablen;
- 12734 do {
- 12735 *bpos = ' ';
- 12736 if (++bpos == bend) bpos = bstart;
- 12737 } while (--tablen != 0);
- 12738 }
- 12739 goto out_done;
- 12740 }
- 12741 /* Tabs are output directly. */
- 12742 pos += tablen;
- 12743 break;
- 12744 default:
- 12745 /* Assume any other character prints as one character. */
- 12746 pos++;
- 12747 }
- 12748 if (++bpos == bend) bpos = bstart;
- 12749 ict--;
- 12750 oct--;
- 12751 }
- 12752 out_done:
- 12753 tp->tty_position = pos & TAB_MASK;
- 12754
- 12755 *icount -= ict; /* [io]ct are the number of chars not used */
- 12756 *ocount -= oct; /* *[io]count are the number of chars that are used */
- 12757 }
- 12760 /*===========================================================================*
- 12761 * dev_ioctl *
- 12762 *===========================================================================*/
- 12763 PRIVATE void dev_ioctl(tp)
- 12764 tty_t *tp;
- 12765 {
- 12766 /* The ioctl's TCSETSW, TCSETSF and TCDRAIN wait for output to finish to make
- 12767 * sure that an attribute change doesn't affect the processing of current
- 12768 * output. Once output finishes the ioctl is executed as in do_ioctl().
- 12769 */
- 12770 phys_bytes user_phys;
- 12771
- 12772 if (tp->tty_outleft > 0) return; /* output not finished */
- 12773
- 12774 if (tp->tty_ioreq != TCDRAIN) {
- 12775 if (tp->tty_ioreq == TCSETSF) tty_icancel(tp);
- 12776 user_phys = proc_vir2phys(proc_addr(tp->tty_ioproc), tp->tty_iovir);
- 12777 phys_copy(user_phys, vir2phys(&tp->tty_termios),
- 12778 (phys_bytes) sizeof(tp->tty_termios));
- 12779 setattr(tp);
- 12780 }
- 12781 tp->tty_ioreq = 0;
- 12782 tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, OK);
- 12783 }
- 12786 /*===========================================================================*
- 12787 * setattr *
- 12788 *===========================================================================*/
- 12789 PRIVATE void setattr(tp)
- 12790 tty_t *tp;
- 12791 {
- 12792 /* Apply the new line attributes (raw/canonical, line speed, etc.) */
- 12793 u16_t *inp;
- 12794 int count;
- 12795
- 12796 if (!(tp->tty_termios.c_lflag & ICANON)) {
- 12797 /* Raw mode; put a "line break" on all characters in the input queue.
- 12798 * It is undefined what happens to the input queue when ICANON is
- 12799 * switched off, a process should use TCSAFLUSH to flush the queue.
- 12800 * Keeping the queue to preserve typeahead is the Right Thing, however
- 12801 * when a process does use TCSANOW to switch to raw mode.
- 12802 */
- 12803 count = tp->tty_eotct = tp->tty_incount;
- 12804 inp = tp->tty_intail;
- 12805 while (count > 0) {
- 12806 *inp |= IN_EOT;
- 12807 if (++inp == bufend(tp->tty_inbuf)) inp = tp->tty_inbuf;
- 12808 --count;
- 12809 }
- 12810 }
- 12811
- 12812 /* Inspect MIN and TIME. */
- 12813 lock();
- 12814 settimer(tp, FALSE);
- 12815 unlock();
- 12816 if (tp->tty_termios.c_lflag & ICANON) {
- 12817 /* No MIN & TIME in canonical mode. */
- 12818 tp->tty_min = 1;
- 12819 } else {
- 12820 /* In raw mode MIN is the number of chars wanted, and TIME how long
- 12821 * to wait for them. With interesting exceptions if either is zero.
- 12822 */
- 12823 tp->tty_min = tp->tty_termios.c_cc[VMIN];
- 12824 if (tp->tty_min == 0 && tp->tty_termios.c_cc[VTIME] > 0)
- 12825 tp->tty_min = 1;
- 12826 }
- 12827
- 12828 if (!(tp->tty_termios.c_iflag & IXON)) {
- 12829 /* No start/stop output control, so don't leave output inhibited. */
- 12830 tp->tty_inhibited = RUNNING;
- 12831 tp->tty_events = 1;
- 12832 }
- 12833
- 12834 /* Setting the output speed to zero hangs up the phone. */
- 12835 if (tp->tty_termios.c_ospeed == B0) sigchar(tp, SIGHUP);
- 12836
- 12837 /* Set new line speed, character size, etc at the device level. */
- 12838 (*tp->tty_ioctl)(tp);
- 12839 }
- 12842 /*===========================================================================*
- 12843 * tty_reply *
- 12844 *===========================================================================*/
- 12845 PUBLIC void tty_reply(code, replyee, proc_nr, status)
- 12846 int code; /* TASK_REPLY or REVIVE */
- 12847 int replyee; /* destination address for the reply */
- 12848 int proc_nr; /* to whom should the reply go? */
- 12849 int status; /* reply code */
- 12850 {
- 12851 /* Send a reply to a process that wanted to read or write data. */
- 12852
- 12853 message tty_mess;
- 12854
- 12855 tty_mess.m_type = code;
- 12856 tty_mess.REP_PROC_NR = proc_nr;
- 12857 tty_mess.REP_STATUS = status;
- 12858 if ((status = send(replyee, &tty_mess)) != OK)
- 12859 panic("tty_reply failed, statusn", status);
- 12860 }
- 12863 /*===========================================================================*
- 12864 * sigchar *
- 12865 *===========================================================================*/
- 12866 PUBLIC void sigchar(tp, sig)
- 12867 register tty_t *tp;
- 12868 int sig; /* SIGINT, SIGQUIT, SIGKILL or SIGHUP */
- 12869 {
- 12870 /* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard or SIGHUP from
- 12871 * a tty close, "stty 0", or a real RS-232 hangup. MM will send the signal to
- 12872 * the process group (INT, QUIT), all processes (KILL), or the session leader
- 12873 * (HUP).
- 12874 */
- 12875
- 12876 if (tp->tty_pgrp != 0) cause_sig(tp->tty_pgrp, sig);
- 12877
- 12878 if (!(tp->tty_termios.c_lflag & NOFLSH)) {
- 12879 tp->tty_incount = tp->tty_eotct = 0; /* kill earlier input */
- 12880 tp->tty_intail = tp->tty_inhead;
- 12881 (*tp->tty_ocancel)(tp); /* kill all output */
- 12882 tp->tty_inhibited = RUNNING;
- 12883 tp->tty_events = 1;
- 12884 }
- 12885 }
- 12888 /*==========================================================================*
- 12889 * tty_icancel *
- 12890 *==========================================================================*/
- 12891 PRIVATE void tty_icancel(tp)
- 12892 register tty_t *tp;
- 12893 {
- 12894 /* Discard all pending input, tty buffer or device. */
- 12895
- 12896 tp->tty_incount = tp->tty_eotct = 0;
- 12897 tp->tty_intail = tp->tty_inhead;
- 12898 (*tp->tty_icancel)(tp);
- 12899 }
- 12902 /*==========================================================================*
- 12903 * tty_init *
- 12904 *==========================================================================*/
- 12905 PRIVATE void tty_init(tp)
- 12906 tty_t *tp; /* TTY line to initialize. */
- 12907 {
- 12908 /* Initialize tty structure and call device initialization routines. */
- 12909
- 12910 tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
- 12911 tp->tty_min = 1;
- 12912 tp->tty_termios = termios_defaults;
- 12913 tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
- 12914 tty_devnop;
- 12915 if (tp < tty_addr(NR_CONS)) {
- 12916 scr_init(tp);
- 12917 } else
- 12918 if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
- 12919 rs_init(tp);
- 12920 } else {
- 12921 pty_init(tp);
- 12922 }
- 12923 }
- 12926 /*==========================================================================*
- 12927 * tty_wakeup *
- 12928 *==========================================================================*/
- 12929 PUBLIC void tty_wakeup(now)
- 12930 clock_t now; /* current time */
- 12931 {
- 12932 /* Wake up TTY when something interesting is happening on one of the terminal
- 12933 * lines, like a character arriving on an RS232 line, a key being typed, or
- 12934 * a timer on a line expiring by TIME.
- 12935 */
- 12936 tty_t *tp;
- 12937
- 12938 /* Scan the timerlist for expired timers and compute the next timeout time. */
- 12939 tty_timeout = TIME_NEVER;
- 12940 while ((tp = tty_timelist) != NULL) {
- 12941 if (tp->tty_time > now) {
- 12942 tty_timeout = tp->tty_time; /* this timer is next */
- 12943 break;
- 12944 }
- 12945 tp->tty_min = 0; /* force read to succeed */
- 12946 tp->tty_events = 1;
- 12947 tty_timelist = tp->tty_timenext;
- 12948 }
- 12949
- 12950 /* Let TTY know there is something afoot. */
- 12951 interrupt(TTY);
- 12952 }
- 12955 /*===========================================================================*
- 12956 * settimer *
- 12957 *===========================================================================*/
- 12958 PRIVATE void settimer(tp, on)
- 12959 tty_t *tp; /* line to set or unset a timer on */
- 12960 int on; /* set timer if true, otherwise unset */
- 12961 {
- 12962 /* Set or unset a TIME inspired timer. This function is interrupt sensitive
- 12963 * due to tty_wakeup(), so it must be called from within lock()/unlock().
- 12964 */
- 12965 tty_t **ptp;
- 12966
- 12967 /* Take tp out of the timerlist if present. */
- 12968 for (ptp = &tty_timelist; *ptp != NULL; ptp = &(*ptp)->tty_timenext) {
- 12969 if (tp == *ptp) {
- 12970 *ptp = tp->tty_timenext; /* take tp out of the list */
- 12971 break;
- 12972 }
- 12973 }
- 12974 if (!on) return; /* unsetting it is enough */
- 12975
- 12976 /* Timeout occurs TIME deciseconds from now. */
- 12977 tp->tty_time = get_uptime() + tp->tty_termios.c_cc[VTIME] * (HZ/10);
- 12978
- 12979 /* Find a new place in the list. */
- 12980 for (ptp = &tty_timelist; *ptp != NULL; ptp = &(*ptp)->tty_timenext) {
- 12981 if (tp->tty_time <= (*ptp)->tty_time) break;
- 12982 }
- 12983 tp->tty_timenext = *ptp;
- 12984 *ptp = tp;
- 12985 if (tp->tty_time < tty_timeout) tty_timeout = tp->tty_time;
- 12986 }
- 12989 /*==========================================================================*
- 12990 * tty_devnop *
- 12991 *==========================================================================*/
- 12992 PUBLIC void tty_devnop(tp)
- 12993 tty_t *tp;
- 12994 {
- 12995 /* Some functions need not be implemented at the device level. */
- 12996 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/keyboard.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 13000 /* Keyboard driver for PC's and AT's.
- 13001 *
- 13002 * Changed by Marcus Hampel (04/02/1994)
- 13003 * - Loadable keymaps
- 13004 */
- 13005
- 13006 #include "kernel.h"
- 13007 #include <termios.h>
- 13008 #include <signal.h>
- 13009 #include <unistd.h>
- 13010 #include <minix/callnr.h>
- 13011 #include <minix/com.h>
- 13012 #include <minix/keymap.h>
- 13013 #include "tty.h"
- 13014 #include "keymaps/us-std.src"
- 13015
- 13016 /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
- 13017 #define KEYBD 0x60 /* I/O port for keyboard data */
- 13018
- 13019 /* AT keyboard. */
- 13020 #define KB_COMMAND 0x64 /* I/O port for commands on AT */
- 13021 #define KB_GATE_A20 0x02 /* bit in output port to enable A20 line */
- 13022 #define KB_PULSE_OUTPUT 0xF0 /* base for commands to pulse output port */
- 13023 #define KB_RESET 0x01 /* bit in output port to reset CPU */
- 13024 #define KB_STATUS 0x64 /* I/O port for status on AT */
- 13025 #define KB_ACK 0xFA /* keyboard ack response */
- 13026 #define KB_BUSY 0x02 /* status bit set when KEYBD port ready */
- 13027 #define LED_CODE 0xED /* command to keyboard to set LEDs */
- 13028 #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
- 13029 #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
- 13030 #define KBIT 0x80 /* bit used to ack characters to keyboard */
- 13031
- 13032 /* Miscellaneous. */
- 13033 #define ESC_SCAN 1 /* Reboot key when panicking */
- 13034 #define SLASH_SCAN 53 /* to recognize numeric slash */
- 13035 #define HOME_SCAN 71 /* first key on the numeric keypad */
- 13036 #define DEL_SCAN 83 /* DEL for use in CTRL-ALT-DEL reboot */
- 13037 #define CONSOLE 0 /* line number for console */
- 13038 #define MEMCHECK_ADR 0x472 /* address to stop memory check after reboot */
- 13039 #define MEMCHECK_MAG 0x1234 /* magic number to stop memory check */
- 13040
- 13041 #define kb_addr() (&kb_lines[0]) /* there is only one keyboard */
- 13042 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
- 13043
- 13044 PRIVATE int alt1; /* left alt key state */
- 13045 PRIVATE int alt2; /* right alt key state */
- 13046 PRIVATE int capslock; /* caps lock key state */
- 13047 PRIVATE int esc; /* escape scan code detected? */
- 13048 PRIVATE int control; /* control key state */
- 13049 PRIVATE int caps_off; /* 1 = normal position, 0 = depressed */
- 13050 PRIVATE int numlock; /* number lock key state */
- 13051 PRIVATE int num_off; /* 1 = normal position, 0 = depressed */
- 13052 PRIVATE int slock; /* scroll lock key state */
- 13053 PRIVATE int slock_off; /* 1 = normal position, 0 = depressed */
- 13054 PRIVATE int shift; /* shift key state */
- 13055
- 13056 PRIVATE char numpad_map[] =
- 13057 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
- 13058
- 13059 /* Keyboard structure, 1 per console. */
- 13060 struct kb_s {
- 13061 char *ihead; /* next free spot in input buffer */
- 13062 char *itail; /* scan code to return to TTY */
- 13063 int icount; /* # codes in buffer */
- 13064 char ibuf[KB_IN_BYTES]; /* input buffer */
- 13065 };
- 13066
- 13067 PRIVATE struct kb_s kb_lines[NR_CONS];
- 13068
- 13069 FORWARD _PROTOTYPE( int kb_ack, (void) );
- 13070 FORWARD _PROTOTYPE( int kb_wait, (void) );
- 13071 FORWARD _PROTOTYPE( int func_key, (int scode) );
- 13072 FORWARD _PROTOTYPE( int scan_keyboard, (void) );
- 13073 FORWARD _PROTOTYPE( unsigned make_break, (int scode) );
- 13074 FORWARD _PROTOTYPE( void set_leds, (void) );
- 13075 FORWARD _PROTOTYPE( int kbd_hw_int, (int irq) );
- 13076 FORWARD _PROTOTYPE( void kb_read, (struct tty *tp) );
- 13077 FORWARD _PROTOTYPE( unsigned map_key, (int scode) );
- 13078
- 13079
- 13080 /*===========================================================================*
- 13081 * map_key0 *
- 13082 *===========================================================================*/
- 13083 /* Map a scan code to an ASCII code ignoring modifiers. */
- 13084 #define map_key0(scode)
- 13085 ((unsigned) keymap[(scode) * MAP_COLS])
- 13086
- 13087
- 13088 /*===========================================================================*
- 13089 * map_key *
- 13090 *===========================================================================*/
- 13091 PRIVATE unsigned map_key(scode)
- 13092 int scode;
- 13093 {
- 13094 /* Map a scan code to an ASCII code. */
- 13095
- 13096 int caps, column;
- 13097 u16_t *keyrow;
- 13098
- 13099 if (scode == SLASH_SCAN && esc) return '/'; /* don't map numeric slash */
- 13100
- 13101 keyrow = &keymap[scode * MAP_COLS];
- 13102
- 13103 caps = shift;
- 13104 if (numlock && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
- 13105 if (capslock && (keyrow[0] & HASCAPS)) caps = !caps;
- 13106
- 13107 if (alt1 || alt2) {
- 13108 column = 2;
- 13109 if (control || alt2) column = 3; /* Ctrl + Alt1 == Alt2 */
- 13110 if (caps) column = 4;
- 13111 } else {
- 13112 column = 0;
- 13113 if (caps) column = 1;
- 13114 if (control) column = 5;
- 13115 }
- 13116 return keyrow[column] & ~HASCAPS;
- 13117 }
- 13120 /*===========================================================================*
- 13121 * kbd_hw_int *
- 13122 *===========================================================================*/
- 13123 PRIVATE int kbd_hw_int(irq)
- 13124 int irq;
- 13125 {
- 13126 /* A keyboard interrupt has occurred. Process it. */
- 13127
- 13128 int code;
- 13129 unsigned km;
- 13130 register struct kb_s *kb;
- 13131
- 13132 /* Fetch the character from the keyboard hardware and acknowledge it. */
- 13133 code = scan_keyboard();
- 13134
- 13135 /* The IBM keyboard interrupts twice per key, once when depressed, once when
- 13136 * released. Filter out the latter, ignoring all but the shift-type keys.
- 13137 * The shift-type keys 29, 42, 54, 56, 58, and 69 must be processed normally.
- 13138 */
- 13139
- 13140 if (code & 0200) {
- 13141 /* A key has been released (high bit is set). */
- 13142 km = map_key0(code & 0177);
- 13143 if (km != CTRL && km != SHIFT && km != ALT && km != CALOCK
- 13144 && km != NLOCK && km != SLOCK && km != EXTKEY)
- 13145 return 1;
- 13146 }
- 13147
- 13148 /* Store the character in memory so the task can get at it later. */
- 13149 kb = kb_addr();
- 13150 if (kb->icount < KB_IN_BYTES) {
- 13151 *kb->ihead++ = code;
- 13152 if (kb->ihead == kb->ibuf + KB_IN_BYTES) kb->ihead = kb->ibuf;
- 13153 kb->icount++;
- 13154 tty_table[current].tty_events = 1;
- 13155 force_timeout();
- 13156 }
- 13157 /* Else it doesn't fit - discard it. */
- 13158 return 1; /* Reenable keyboard interrupt */
- 13159 }
- 13162 /*==========================================================================*
- 13163 * kb_read *
- 13164 *==========================================================================*/
- 13165 PRIVATE void kb_read(tp)
- 13166 tty_t *tp;
- 13167 {
- 13168 /* Process characters from the circular keyboard buffer. */
- 13169
- 13170 struct kb_s *kb;
- 13171 char buf[3];
- 13172 int scode;
- 13173 unsigned ch;
- 13174
- 13175 kb = kb_addr();
- 13176 tp = &tty_table[current]; /* always use the current console */
- 13177
- 13178 while (kb->icount > 0) {
- 13179 scode = *kb->itail++; /* take one key scan code */
- 13180 if (kb->itail == kb->ibuf + KB_IN_BYTES) kb->itail = kb->ibuf;
- 13181 lock();
- 13182 kb->icount--;
- 13183 unlock();
- 13184
- 13185 /* Function keys are being used for debug dumps. */
- 13186 if (func_key(scode)) continue;
- 13187
- 13188 /* Perform make/break processing. */
- 13189 ch = make_break(scode);
- 13190
- 13191 if (ch <= 0xFF) {
- 13192 /* A normal character. */
- 13193 buf[0] = ch;
- 13194 (void) in_process(tp, buf, 1);
- 13195 } else
- 13196 if (HOME <= ch && ch <= INSRT) {
- 13197 /* An ASCII escape sequence generated by the numeric pad. */
- 13198 buf[0] = ESC;
- 13199 buf[1] = '[';
- 13200 buf[2] = numpad_map[ch - HOME];
- 13201 (void) in_process(tp, buf, 3);
- 13202 } else
- 13203 if (ch == ALEFT) {
- 13204 /* Choose lower numbered console as current console. */
- 13205 select_console(current - 1);
- 13206 } else
- 13207 if (ch == ARIGHT) {
- 13208 /* Choose higher numbered console as current console. */
- 13209 select_console(current + 1);
- 13210 } else
- 13211 if (AF1 <= ch && ch <= AF12) {
- 13212 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
- 13213 select_console(ch - AF1);
- 13214 }
- 13215 }
- 13216 }
- 13219 /*===========================================================================*
- 13220 * make_break *
- 13221 *===========================================================================*/
- 13222 PRIVATE unsigned make_break(scode)
- 13223 int scode; /* scan code of key just struck or released */
- 13224 {
- 13225 /* This routine can handle keyboards that interrupt only on key depression,
- 13226 * as well as keyboards that interrupt on key depression and key release.
- 13227 * For efficiency, the interrupt routine filters out most key releases.
- 13228 */
- 13229 int ch, make;
- 13230 static int CAD_count = 0;
- 13231
- 13232 /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
- 13233 * be better done in keyboard() in case TTY is hung, except control and
- 13234 * alt are set in the high level code.
- 13235 */
- 13236 if (control && (alt1 || alt2) && scode == DEL_SCAN)
- 13237 {
- 13238 if (++CAD_count == 3) wreboot(RBT_HALT);
- 13239 cause_sig(INIT_PROC_NR, SIGABRT);
- 13240 return -1;
- 13241 }
- 13242
- 13243 /* High-order bit set on key release. */
- 13244 make = (scode & 0200 ? 0 : 1); /* 0 = release, 1 = press */
- 13245
- 13246 ch = map_key(scode & 0177); /* map to ASCII */
- 13247
- 13248 switch (ch) {
- 13249 case CTRL:
- 13250 control = make;
- 13251 ch = -1;
- 13252 break;
- 13253 case SHIFT:
- 13254 shift = make;
- 13255 ch = -1;
- 13256 break;
- 13257 case ALT:
- 13258 if (make) {
- 13259 if (esc) alt2 = 1; else alt1 = 1;
- 13260 } else {
- 13261 alt1 = alt2 = 0;
- 13262 }
- 13263 ch = -1;
- 13264 break;
- 13265 case CALOCK:
- 13266 if (make && caps_off) {
- 13267 capslock = 1 - capslock;
- 13268 set_leds();
- 13269 }
- 13270 caps_off = 1 - make;
- 13271 ch = -1;
- 13272 break;
- 13273 case NLOCK:
- 13274 if (make && num_off) {
- 13275 numlock = 1 - numlock;
- 13276 set_leds();
- 13277 }
- 13278 num_off = 1 - make;
- 13279 ch = -1;
- 13280 break;
- 13281 case SLOCK:
- 13282 if (make & slock_off) {
- 13283 slock = 1 - slock;
- 13284 set_leds();
- 13285 }
- 13286 slock_off = 1 - make;
- 13287 ch = -1;
- 13288 break;
- 13289 case EXTKEY:
- 13290 esc = 1;
- 13291 return(-1);
- 13292 default:
- 13293 if (!make) ch = -1;
- 13294 }
- 13295 esc = 0;
- 13296 return(ch);
- 13297 }
- 13300 /*===========================================================================*
- 13301 * set_leds *
- 13302 *===========================================================================*/
- 13303 PRIVATE void set_leds()
- 13304 {
- 13305 /* Set the LEDs on the caps lock and num lock keys */
- 13306
- 13307 unsigned leds;
- 13308
- 13309 if (!pc_at) return; /* PC/XT doesn't have LEDs */
- 13310
- 13311 /* encode LED bits */
- 13312 leds = (slock << 0) | (numlock << 1) | (capslock << 2);
- 13313
- 13314 kb_wait(); /* wait for buffer empty */
- 13315 out_byte(KEYBD, LED_CODE); /* prepare keyboard to accept LED values */
- 13316 kb_ack(); /* wait for ack response */
- 13317
- 13318 kb_wait(); /* wait for buffer empty */
- 13319 out_byte(KEYBD, leds); /* give keyboard LED values */
- 13320 kb_ack(); /* wait for ack response */
- 13321 }
- 13324 /*==========================================================================*
- 13325 * kb_wait *
- 13326 *==========================================================================*/
- 13327 PRIVATE int kb_wait()
- 13328 {
- 13329 /* Wait until the controller is ready; return zero if this times out. */
- 13330
- 13331 int retries;
- 13332
- 13333 retries = MAX_KB_BUSY_RETRIES + 1;
- 13334 while (--retries != 0 && in_byte(KB_STATUS) & KB_BUSY)
- 13335 ; /* wait until not busy */
- 13336 return(retries); /* nonzero if ready */
- 13337 }
- 13340 /*==========================================================================*
- 13341 * kb_ack *
- 13342 *==========================================================================*/
- 13343 PRIVATE int kb_ack()
- 13344 {
- 13345 /* Wait until kbd acknowledges last command; return zero if this times out. */
- 13346
- 13347 int retries;
- 13348
- 13349 retries = MAX_KB_ACK_RETRIES + 1;
- 13350 while (--retries != 0 && in_byte(KEYBD) != KB_ACK)
- 13351 ; /* wait for ack */
- 13352 return(retries); /* nonzero if ack received */
- 13353 }
- 13356 /*===========================================================================*
- 13357 * kb_init *
- 13358 *===========================================================================*/
- 13359 PUBLIC void kb_init(tp)
- 13360 tty_t *tp;
- 13361 {
- 13362 /* Initialize the keyboard driver. */
- 13363
- 13364 register struct kb_s *kb;
- 13365
- 13366 /* Input function. */
- 13367 tp->tty_devread = kb_read;
- 13368
- 13369 kb = kb_addr();
- 13370
- 13371 /* Set up input queue. */
- 13372 kb->ihead = kb->itail = kb->ibuf;
- 13373
- 13374 /* Set initial values. */
- 13375 caps_off = 1;
- 13376 num_off = 1;
- 13377 slock_off = 1;
- 13378 esc = 0;
- 13379
- 13380 set_leds(); /* turn off numlock led */
- 13381
- 13382 scan_keyboard(); /* stop lockup from leftover keystroke */
- 13383
- 13384 put_irq_handler(KEYBOARD_IRQ, kbd_hw_int); /* set the interrupt handler */
- 13385 enable_irq(KEYBOARD_IRQ); /* safe now everything initialised! */
- 13386 }
- 13389 /*===========================================================================*
- 13390 * kbd_loadmap *
- 13391 *===========================================================================*/
- 13392 PUBLIC int kbd_loadmap(user_phys)
- 13393 phys_bytes user_phys;
- 13394 {
- 13395 /* Load a new keymap. */
- 13396
- 13397 phys_copy(user_phys, vir2phys(keymap), (phys_bytes) sizeof(keymap));
- 13398 return(OK);
- 13399 }
- 13402 /*===========================================================================*
- 13403 * func_key *
- 13404 *===========================================================================*/
- 13405 PRIVATE int func_key(scode)
- 13406 int scode; /* scan code for a function key */
- 13407 {
- 13408 /* This procedure traps function keys for debugging and control purposes. */
- 13409
- 13410 unsigned code;
- 13411
- 13412 code = map_key0(scode); /* first ignore modifiers */
- 13413 if (code < F1 || code > F12) return(FALSE); /* not our job */
- 13414
- 13415 switch (map_key(scode)) { /* include modifiers */
- 13416
- 13417 case F1: p_dmp(); break; /* print process table */
- 13418 case F2: map_dmp(); break; /* print memory map */
- 13419 case F3: toggle_scroll(); break; /* hardware vs. software scrolling */
- 13420 case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT); break;
- 13421 case CF8: sigchar(&tty_table[CONSOLE], SIGINT); break;
- 13422 case CF9: sigchar(&tty_table[CONSOLE], SIGKILL); break;
- 13423 default: return(FALSE);
- 13424 }
- 13425 return(TRUE);
- 13426 }
- 13429 /*==========================================================================*
- 13430 * scan_keyboard *
- 13431 *==========================================================================*/
- 13432 PRIVATE int scan_keyboard()
- 13433 {
- 13434 /* Fetch the character from the keyboard hardware and acknowledge it. */
- 13435
- 13436 int code;
- 13437 int val;
- 13438
- 13439 code = in_byte(KEYBD); /* get the scan code for the key struck */
- 13440 val = in_byte(PORT_B); /* strobe the keyboard to ack the char */
- 13441 out_byte(PORT_B, val | KBIT); /* strobe the bit high */
- 13442 out_byte(PORT_B, val); /* now strobe it low */
- 13443 return code;
- 13444 }
- 13447 /*==========================================================================*
- 13448 * wreboot *
- 13449 *==========================================================================*/
- 13450 PUBLIC void wreboot(how)
- 13451 int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */
- 13452 {
- 13453 /* Wait for keystrokes for printing debugging info and reboot. */
- 13454
- 13455 int quiet, code;
- 13456 static u16_t magic = MEMCHECK_MAG;
- 13457 struct tasktab *ttp;
- 13458
- 13459 /* Mask all interrupts. */
- 13460 out_byte(INT_CTLMASK, ~0);
- 13461
- 13462 /* Tell several tasks to stop. */
- 13463 cons_stop();
- 13464 floppy_stop();
- 13465 clock_stop();
- 13466
- 13467 if (how == RBT_HALT) {
- 13468 printf("System Haltedn");
- 13469 if (!mon_return) how = RBT_PANIC;
- 13470 }
- 13471
- 13472 if (how == RBT_PANIC) {
- 13473 /* A panic! */
- 13474 printf("Hit ESC to reboot, F-keys for debug dumpsn");
- 13475
- 13476 (void) scan_keyboard(); /* ack any old input */
- 13477 quiet = scan_keyboard();/* quiescent value (0 on PC, last code on AT)*/
- 13478 for (;;) {
- 13479 milli_delay(100); /* pause for a decisecond */
- 13480 code = scan_keyboard();
- 13481 if (code != quiet) {
- 13482 /* A key has been pressed. */
- 13483 if (code == ESC_SCAN) break; /* reboot if ESC typed */
- 13484 (void) func_key(code); /* process function key */
- 13485 quiet = scan_keyboard();
- 13486 }
- 13487 }
- 13488 how = RBT_REBOOT;
- 13489 }
- 13490
- 13491 if (how == RBT_REBOOT) printf("Rebootingn");
- 13492
- 13493 if (mon_return && how != RBT_RESET) {
- 13494 /* Reinitialize the interrupt controllers to the BIOS defaults. */
- 13495 intr_init(0);
- 13496 out_byte(INT_CTLMASK, 0);
- 13497 out_byte(INT2_CTLMASK, 0);
- 13498
- 13499 /* Return to the boot monitor. */
- 13500 if (how == RBT_HALT) {
- 13501 reboot_code = vir2phys("");
- 13502 } else
- 13503 if (how == RBT_REBOOT) {
- 13504 reboot_code = vir2phys("delay;boot");
- 13505 }
- 13506 level0(monitor);
- 13507 }
- 13508
- 13509 /* Stop BIOS memory test. */
- 13510 phys_copy(vir2phys(&magic), (phys_bytes) MEMCHECK_ADR,
- 13511 (phys_bytes) sizeof(magic));
- 13512
- 13513 if (protected_mode) {
- 13514 /* Use the AT keyboard controller to reset the processor.
- 13515 * The A20 line is kept enabled in case this code is ever
- 13516 * run from extended memory, and because some machines
- 13517 * appear to drive the fake A20 high instead of low just
- 13518 * after reset, leading to an illegal opode trap. This bug
- 13519 * is more of a problem if the fake A20 is in use, as it
- 13520 * would be if the keyboard reset were used for real mode.
- 13521 */
- 13522 kb_wait();
- 13523 out_byte(KB_COMMAND,
- 13524 KB_PULSE_OUTPUT | (0x0F & ~(KB_GATE_A20 | KB_RESET)));
- 13525 milli_delay(10);
- 13526
- 13527 /* If the nice method fails then do a reset. In protected
- 13528 * mode this means a processor shutdown.
- 13529 */
- 13530 printf("Hard reset...n");
- 13531 milli_delay(250);
- 13532 }
- 13533 /* In real mode, jumping to the reset address is good enough. */
- 13534 level0(reset);
- 13535 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/console.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 13600 /* Code and data for the IBM console driver.
- 13601 *
- 13602 * The 6845 video controller used by the IBM PC shares its video memory with
- 13603 * the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory
- 13604 * consists of 16-bit words. Each word has a character code in the low byte
- 13605 * and a so-called attribute byte in the high byte. The CPU directly modifies
- 13606 * video memory to display characters, and sets two registers on the 6845 that
- 13607 * specify the video origin and the cursor position. The video origin is the
- 13608 * place in video memory where the first character (upper left corner) can
- 13609 * be found. Moving the origin is a fast way to scroll the screen. Some
- 13610 * video adapters wrap around the top of video memory, so the origin can
- 13611 * move without bounds. For other adapters screen memory must sometimes be
- 13612 * moved to reset the origin. All computations on video memory use character
- 13613 * (word) addresses for simplicity and assume there is no wrapping. The
- 13614 * assembly support functions translate the word addresses to byte addresses
- 13615 * and the scrolling function worries about wrapping.
- 13616 */
- 13617
- 13618 #include "kernel.h"
- 13619 #include <termios.h>
- 13620 #include <minix/callnr.h>
- 13621 #include <minix/com.h>
- 13622 #include "protect.h"
- 13623 #include "tty.h"
- 13624 #include "proc.h"
- 13625
- 13626 /* Definitions used by the console driver. */
- 13627 #define MONO_BASE 0xB0000L /* base of mono video memory */
- 13628 #define COLOR_BASE 0xB8000L /* base of color video memory */
- 13629 #define MONO_SIZE 0x1000 /* 4K mono video memory */
- 13630 #define COLOR_SIZE 0x4000 /* 16K color video memory */
- 13631 #define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */
- 13632 #define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */
- 13633 #define SCROLL_UP 0 /* scroll forward */
- 13634 #define SCROLL_DOWN 1 /* scroll backward */
- 13635 #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
- 13636 #define CONS_RAM_WORDS 80 /* video ram buffer size */
- 13637 #define MAX_ESC_PARMS 2 /* number of escape sequence params allowed */
- 13638
- 13639 /* Constants relating to the controller chips. */
- 13640 #define M_6845 0x3B4 /* port for 6845 mono */
- 13641 #define C_6845 0x3D4 /* port for 6845 color */
- 13642 #define EGA 0x3C4 /* port for EGA or VGA card */
- 13643 #define INDEX 0 /* 6845's index register */
- 13644 #define DATA 1 /* 6845's data register */
- 13645 #define VID_ORG 12 /* 6845's origin register */
- 13646 #define CURSOR 14 /* 6845's cursor register */
- 13647
- 13648 /* Beeper. */
- 13649 #define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */
- 13650 #define B_TIME 3 /* length of CTRL-G beep is ticks */
- 13651
- 13652 /* definitions used for font management */
- 13653 #define GA_SEQUENCER_INDEX 0x3C4
- 13654 #define GA_SEQUENCER_DATA 0x3C5
- 13655 #define GA_GRAPHICS_INDEX 0x3CE
- 13656 #define GA_GRAPHICS_DATA 0x3CF
- 13657 #define GA_VIDEO_ADDRESS 0xA0000L
- 13658 #define GA_FONT_SIZE 8192
- 13659
- 13660 /* Global variables used by the console driver. */
- 13661 PUBLIC unsigned vid_seg; /* video ram selector (0xB0000 or 0xB8000) */
- 13662 PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */
- 13663 PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
- 13664 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
- 13665
- 13666 /* Private variables used by the console driver. */
- 13667 PRIVATE int vid_port; /* I/O port for accessing 6845 */
- 13668 PRIVATE int wrap; /* hardware can wrap? */
- 13669 PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
- 13670 PRIVATE unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */
- 13671 PRIVATE int beeping; /* speaker is beeping? */
- 13672 #define scr_width 80 /* # characters on a line */
- 13673 #define scr_lines 25 /* # lines on the screen */
- 13674 #define scr_size (80*25) /* # characters on the screen */
- 13675
- 13676 /* Per console data. */
- 13677 typedef struct console {
- 13678 tty_t *c_tty; /* associated TTY struct */
- 13679 int c_column; /* current column number (0-origin) */
- 13680 int c_row; /* current row (0 at top of screen) */
- 13681 int c_rwords; /* number of WORDS (not bytes) in outqueue */
- 13682 unsigned c_start; /* start of video memory of this console */
- 13683 unsigned c_limit; /* limit of this console's video memory */
- 13684 unsigned c_org; /* location in RAM where 6845 base points */
- 13685 unsigned c_cur; /* current position of cursor in video RAM */
- 13686 unsigned c_attr; /* character attribute */
- 13687 unsigned c_blank; /* blank attribute */
- 13688 char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */
- 13689 char c_esc_intro; /* Distinguishing character following ESC */
- 13690 int *c_esc_parmp; /* pointer to current escape parameter */
- 13691 int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */
- 13692 u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */
- 13693 } console_t;
- 13694
- 13695 PRIVATE int nr_cons= 1; /* actual number of consoles */
- 13696 PRIVATE console_t cons_table[NR_CONS];
- 13697 PRIVATE console_t *curcons; /* currently visible */
- 13698
- 13699 /* Color if using a color controller. */
- 13700 #define color (vid_port == C_6845)
- 13701
- 13702 /* Map from ANSI colors to the attributes used by the PC */
- 13703 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
- 13704
- 13705 /* Structure used for font management */
- 13706 struct sequence {
- 13707 unsigned short index;
- 13708 unsigned char port;
- 13709 unsigned char value;
- 13710 };
- 13711
- 13712 FORWARD _PROTOTYPE( void cons_write, (struct tty *tp) );
- 13713 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );
- 13714 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );
- 13715 FORWARD _PROTOTYPE( void beep, (void) );
- 13716 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );
- 13717 FORWARD _PROTOTYPE( void flush, (console_t *cons) );
- 13718 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );
- 13719 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );
- 13720 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );
- 13721 FORWARD _PROTOTYPE( void stop_beep, (void) );
- 13722 FORWARD _PROTOTYPE( void cons_org0, (void) );
- 13723 FORWARD _PROTOTYPE( void ga_program, (struct sequence *seq) );
- 13724
- 13725
- 13726 /*===========================================================================*
- 13727 * cons_write *
- 13728 *===========================================================================*/
- 13729 PRIVATE void cons_write(tp)
- 13730 register struct tty *tp; /* tells which terminal is to be used */
- 13731 {
- 13732 /* Copy as much data as possible to the output queue, then start I/O. On
- 13733 * memory-mapped terminals, such as the IBM console, the I/O will also be
- 13734 * finished, and the counts updated. Keep repeating until all I/O done.
- 13735 */
- 13736
- 13737 int count;
- 13738 register char *tbuf;
- 13739 char buf[64];
- 13740 phys_bytes user_phys;
- 13741 console_t *cons = tp->tty_priv;
- 13742
- 13743 /* Check quickly for nothing to do, so this can be called often without
- 13744 * unmodular tests elsewhere.
- 13745 */
- 13746 if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
- 13747
- 13748 /* Copy the user bytes to buf[] for decent addressing. Loop over the
- 13749 * copies, since the user buffer may be much larger than buf[].
- 13750 */
- 13751 do {
- 13752 if (count > sizeof(buf)) count = sizeof(buf);
- 13753 user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir);
- 13754 phys_copy(user_phys, vir2phys(buf), (phys_bytes) count);
- 13755 tbuf = buf;
- 13756
- 13757 /* Update terminal data structure. */
- 13758 tp->tty_out_vir += count;
- 13759 tp->tty_outcum += count;
- 13760 tp->tty_outleft -= count;
- 13761
- 13762 /* Output each byte of the copy to the screen. Avoid calling
- 13763 * out_char() for the "easy" characters, put them into the buffer
- 13764 * directly.
- 13765 */
- 13766 do {
- 13767 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
- 13768 || cons->c_column >= scr_width
- 13769 || cons->c_rwords >= buflen(cons->c_ramqueue))
- 13770 {
- 13771 out_char(cons, *tbuf++);
- 13772 } else {
- 13773 cons->c_ramqueue[cons->c_rwords++] =
- 13774 cons->c_attr | (*tbuf++ & BYTE);
- 13775 cons->c_column++;
- 13776 }
- 13777 } while (--count != 0);
- 13778 } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
- 13779
- 13780 flush(cons); /* transfer anything buffered to the screen */
- 13781
- 13782 /* Reply to the writer if all output is finished. */
- 13783 if (tp->tty_outleft == 0) {
- 13784 tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
- 13785 tp->tty_outcum);
- 13786 tp->tty_outcum = 0;
- 13787 }
- 13788 }
- 13791 /*===========================================================================*
- 13792 * cons_echo *
- 13793 *===========================================================================*/
- 13794 PRIVATE void cons_echo(tp, c)
- 13795 register tty_t *tp; /* pointer to tty struct */
- 13796 int c; /* character to be echoed */
- 13797 {
- 13798 /* Echo keyboard input (print & flush). */
- 13799 console_t *cons = tp->tty_priv;
- 13800
- 13801 out_char(cons, c);
- 13802 flush(cons);
- 13803 }
- 13806 /*===========================================================================*
- 13807 * out_char *
- 13808 *===========================================================================*/
- 13809 PRIVATE void out_char(cons, c)
- 13810 register console_t *cons; /* pointer to console struct */
- 13811 int c; /* character to be output */
- 13812 {
- 13813 /* Output a character on the console. Check for escape sequences first. */
- 13814 if (cons->c_esc_state > 0) {
- 13815 parse_escape(cons, c);
- 13816 return;
- 13817 }
- 13818
- 13819 switch(c) {
- 13820 case 000: /* null is typically used for padding */
- 13821 return; /* better not do anything */
- 13822
- 13823 case 007: /* ring the bell */
- 13824 flush(cons); /* print any chars queued for output */
- 13825 beep();
- 13826 return;
- 13827
- 13828 case 'b': /* backspace */
- 13829 if (--cons->c_column < 0) {
- 13830 if (--cons->c_row >= 0) cons->c_column += scr_width;
- 13831 }
- 13832 flush(cons);
- 13833 return;
- 13834
- 13835 case 'n': /* line feed */
- 13836 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
- 13837 == (OPOST|ONLCR)) {
- 13838 cons->c_column = 0;
- 13839 }
- 13840 /*FALL THROUGH*/
- 13841 case 013: /* CTRL-K */
- 13842 case 014: /* CTRL-L */
- 13843 if (cons->c_row == scr_lines-1) {
- 13844 scroll_screen(cons, SCROLL_UP);
- 13845 } else {
- 13846 cons->c_row++;
- 13847 }
- 13848 flush(cons);
- 13849 return;
- 13850
- 13851 case 'r': /* carriage return */
- 13852 cons->c_column = 0;
- 13853 flush(cons);
- 13854 return;
- 13855
- 13856 case 't': /* tab */
- 13857 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
- 13858 if (cons->c_column > scr_width) {
- 13859 cons->c_column -= scr_width;
- 13860 if (cons->c_row == scr_lines-1) {
- 13861 scroll_screen(cons, SCROLL_UP);
- 13862 } else {
- 13863 cons->c_row++;
- 13864 }
- 13865 }
- 13866 flush(cons);
- 13867 return;
- 13868
- 13869 case 033: /* ESC - start of an escape sequence */
- 13870 flush(cons); /* print any chars queued for output */
- 13871 cons->c_esc_state = 1; /* mark ESC as seen */
- 13872 return;
- 13873
- 13874 default: /* printable chars are stored in ramqueue */
- 13875 if (cons->c_column >= scr_width) {
- 13876 if (!LINEWRAP) return;
- 13877 if (cons->c_row == scr_lines-1) {
- 13878 scroll_screen(cons, SCROLL_UP);
- 13879 } else {
- 13880 cons->c_row++;
- 13881 }
- 13882 cons->c_column = 0;
- 13883 flush(cons);
- 13884 }
- 13885 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
- 13886 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
- 13887 cons->c_column++; /* next column */
- 13888 return;
- 13889 }
- 13890 }
- 13893 /*===========================================================================*
- 13894 * scroll_screen *
- 13895 *===========================================================================*/
- 13896 PRIVATE void scroll_screen(cons, dir)
- 13897 register console_t *cons; /* pointer to console struct */
- 13898 int dir; /* SCROLL_UP or SCROLL_DOWN */
- 13899 {
- 13900 unsigned new_line, new_org, chars;
- 13901
- 13902 flush(cons);
- 13903 chars = scr_size - scr_width; /* one screen minus one line */
- 13904
- 13905 /* Scrolling the screen is a real nuisance due to the various incompatible
- 13906 * video cards. This driver supports software scrolling (Hercules?),
- 13907 * hardware scrolling (mono and CGA cards) and hardware scrolling without
- 13908 * wrapping (EGA and VGA cards). In the latter case we must make sure that
- 13909 * c_start <= c_org && c_org + scr_size <= c_limit
- 13910 * holds, because EGA and VGA don't wrap around the end of video memory.
- 13911 */
- 13912 if (dir == SCROLL_UP) {
- 13913 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
- 13914 if (softscroll) {