1: /* This file contains the code and data for the clock task.  The clock task
   2:  * accepts six message types:
   3:  *
   4:  *   HARD_INT:    a clock interrupt has occurred
   5:  *   GET_UPTIME:  get the time since boot in ticks
   6:  *   GET_TIME:    a process wants the real time in seconds
   7:  *   SET_TIME:    a process wants to set the real time in seconds
   8:  *   SET_ALARM:   a process wants to be alerted after a specified interval
   9:  *   SET_SYNC_AL: set the sync alarm
  10:  *
  11:  *
  12:  * The input message is format m6.  The parameters are as follows:
  13:  *
  14:  *     m_type    CLOCK_PROC   FUNC    NEW_TIME
  15:  * ---------------------------------------------
  16:  * | HARD_INT   |          |         |         |
  17:  * |------------+----------+---------+---------|
  18:  * | GET_UPTIME |          |         |         |
  19:  * |------------+----------+---------+---------|
  20:  * | GET_TIME   |          |         |         |
  21:  * |------------+----------+---------+---------|
  22:  * | SET_TIME   |          |         | newtime |
  23:  * |------------+----------+---------+---------|
  24:  * | SET_ALARM  | proc_nr  |         |  delta  |
  25:  * |------------+----------+---------+---------|
  26:  * | SET_SYNC_AL| proc_nr  |         |  delta  |
  27:  * ---------------------------------------------
  28:  * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
  29:  * the message, depending upon the message type.
  30:  *
  31:  * Reply messages are of type OK, except in the case of a HARD_INT, to
  32:  * which no reply is generated. For the GET_* messages the time is returned
  33:  * in the NEW_TIME field, and for the SET_ALARM and SET_SYNC_AL the time
  34:  * in seconds remaining until the alarm is returned is returned in the same
  35:  * field.
  36:  *
  37:  * When an alarm goes off, if the caller is a user process, a SIGALRM signal
  38:  * is sent to it.  If it is a task, a function specified by the caller will
  39:  * be invoked.  This function may, for example, send a message, but only if
  40:  * it is certain that the task will be blocked when the timer goes off. A
  41:  * synchronous alarm sends a message to the synchronous alarm task, which
  42:  * in turn can dispatch a message to another server. This is the only way
  43:  * to send an alarm to a server, since servers cannot use the function-call
  44:  * mechanism available to tasks and servers cannot receive signals.
  45:  */
  46: 
  47: #include "kernel.h"
  48: #include <stddef.h>
  49: #include <signal.h>
  50: #include <minix/callnr.h>
  51: #include <minix/com.h>
  52: #include "proc.h"
  53: 
  54: /* Constant definitions. */
  55: #define MILLISEC         100    /* how often to call the scheduler (msec) */
  56: #define SCHED_RATE (MILLISEC*HZ/1000)   /* number of ticks per schedule */
  57: 
  58: /* Clock parameters. */
  59: #if (CHIP == INTEL)
  60: #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using square wave */
  61: #define LATCH_COUNT     0x00    /* cc00xxxx, c = channel, x = any */
  62: #define SQUARE_WAVE     0x36    /* ccaammmb, a = access, m = mode, b = BCD */
  63:                                 /*   11x11, 11 = LSB then MSB, x11 = sq wave */
  64: #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
  65: #define TIMER_FREQ  1193182L    /* clock frequency for timer in PC and AT */
  66: 
  67: #define CLOCK_ACK_BIT   0x80    /* PS/2 clock interrupt acknowledge bit */
  68: #endif
  69: 
  70: #if (CHIP == M68000)
  71: #define TIMER_FREQ  2457600L    /* timer 3 input clock frequency */
  72: #endif
  73: 
  74: /* Clock task variables. */
  75: PRIVATE clock_t realtime;       /* real time clock */
  76: PRIVATE time_t boot_time;       /* time in seconds of system boot */
  77: PRIVATE timer_t *timers;        /* list of active timers */
  78: PRIVATE clock_t next_timer;     /* when the first timer expires */
  79: PRIVATE timer_t tmr_alarm[NR_PROCS];    /* timers for alarm(2) */
  80: 
  81: /* Variables changed by interrupt handler */
  82: PRIVATE clock_t pending_ticks;  /* ticks seen by low level only */
  83: PRIVATE int sched_ticks = SCHED_RATE;   /* counter: when 0, call scheduler */
  84: PRIVATE struct proc *prev_ptr;  /* last user process run by clock task */
  85: 
  86: FORWARD _PROTOTYPE( void do_clocktick, (void) );
  87: FORWARD _PROTOTYPE( void do_get_time, (message *m_ptr) );
  88: FORWARD _PROTOTYPE( void do_getuptime, (message *m_ptr) );
  89: FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
  90: FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr, int handler,
  91:                                                 tmr_func_t function) );
  92: FORWARD _PROTOTYPE( void init_clock, (void) );
  93: FORWARD _PROTOTYPE( void cause_alarm, (timer_t *tp) );
  94: FORWARD _PROTOTYPE( void cause_synalarm, (timer_t *tp) );
  95: FORWARD _PROTOTYPE( int clock_handler, (irq_hook_t *hook) );
  96: 
  97: /*===========================================================================*
  98:  *                              clock_task                                   *
  99:  *===========================================================================*/
 100: PUBLIC void clock_task()
 101: {
 102: /* Main program of clock task.  It corrects realtime by adding pending
 103:  * ticks seen only by the interrupt service, then it determines which
 104:  * of the 6 possible calls this is by looking at 'mc.m_type'.  Then
 105:  * it dispatches.
 106:  */
 107:   message mc;                   /* message buffer for both input and output */
 108:   int opcode;
 109: 
 110:   init_clock();                 /* initialize clock task */
 111: 
 112:   /* Main loop of the clock task.  Get work, process it, sometimes reply. */
 113:   while (TRUE) {
 114:      receive(ANY, &mc);          /* go get a message */
 115:      opcode = mc.m_type;        /* extract the function code */
 116: 
 117:      lock();
 118:      realtime += pending_ticks; /* transfer ticks from low level handler */
 119:      pending_ticks = 0;         /* so we don't have to worry about them */
 120:      unlock();
 121: 
 122:      switch (opcode) {
 123:         case HARD_INT:   do_clocktick();        break;
 124:         case GET_UPTIME: do_getuptime(&mc);      break;
 125:         case GET_TIME:   do_get_time(&mc);       break;
 126:         case SET_TIME:   do_set_time(&mc);       break;
 127:         case SET_ALARM:  do_setalarm(&mc, CLOCK, cause_alarm);   break;
 128:         case SET_SYNC_AL:do_setalarm(&mc, SYN_ALRM_TASK, cause_synalarm); break;
 129:         default: panic("clock task got bad message", mc.m_type);
 130:      }
 131: 
 132:     /* Send reply, except for clock tick. */
 133:     mc.m_type = OK;
 134:     if (opcode != HARD_INT) send(mc.m_source, &mc);
 135:   }
 136: }
 137: 
 138: /*===========================================================================*
 139:  *                              do_clocktick                                 *
 140:  *===========================================================================*/
 141: PRIVATE void do_clocktick()
 142: {
 143: /* Despite its name, this routine is not called on every clock tick. It
 144:  * is called on those clock ticks when a lot of work needs to be done.
 145:  */
 146: 
 147:   register struct proc *rp;
 148:   register int proc_nr;
 149:   timer_t *tp;
 150:   struct proc *p;
 151: 
 152:   if (next_timer <= realtime) {
 153:         /* One or more timers may have expired.  If so move the expired timers
 154:          * to the per-task expired timers list and alert the task.
 155:          */
 156:         while ((tp = timers) != NULL && tp->tmr_exp_time <= realtime) {
 157:                 timers = tp->tmr_next;
 158:                 p= proc_addr(tp->tmr_task);
 159:                 if (p->p_exptimers == NULL && p != proc_ptr) {
 160:                         interrupt(tp->tmr_task);
 161:                 }
 162:                 tp->tmr_next = p->p_exptimers;
 163:                 p->p_exptimers = tp;
 164:         }
 165: 
 166:         /* When does the next timer expire? */
 167:         next_timer = timers == NULL ? TMR_NEVER : timers->tmr_exp_time;
 168: 
 169:         /* It's possible that one of the clock's own timers expired. */
 170:         tmr_exptimers();
 171:   }
 172: 
 173:   /* If a user process has been running too long, pick another one. */
 174:   if (--sched_ticks == 0) {
 175:         if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
 176:         sched_ticks = SCHED_RATE;               /* reset quantum */
 177:         prev_ptr = bill_ptr;                    /* new previous process */
 178:   }
 179: }
 180: 
 181: /*===========================================================================*
 182:  *                              tmr_settimer                                 *
 183:  *===========================================================================*/
 184: PUBLIC void tmr_settimer(tp, task, exp_time, fp)
 185: timer_t *tp;
 186: int task;
 187: clock_t exp_time;
 188: tmr_func_t fp;
 189: {
 190:   /* Activate a timer to run function 'fp' at time 'exp_time'.  The timer
 191:    * is to be owned by the given task.  (Usually the clock task, the calling
 192:    * task itself or the synchronous alarm task.)
 193:    */
 194:   timer_t **atp;
 195: 
 196:   if (tp->tmr_exp_time != TMR_NEVER) tmr_clrtimer(tp);
 197:   tp->tmr_task = task;
 198:   tp->tmr_exp_time = exp_time;
 199:   tp->tmr_func = fp;
 200: 
 201:   /* Put the timer in the list of active timers with the first to expire in
 202:    * front.
 203:    */
 204:   for (atp = &timers; *atp != NULL; atp = &(*atp)->tmr_next) {
 205:         if (exp_time < (*atp)->tmr_exp_time) break;
 206:   }
 207:   tp->tmr_next = *atp;
 208:   *atp = tp;
 209:   
 210:   /* The new timer may be the first. */
 211:   next_timer = timers->tmr_exp_time;
 212: }
 213: 
 214: /*===========================================================================*
 215:  *                              tmr_clrtimer                                 *
 216:  *===========================================================================*/
 217: PUBLIC void tmr_clrtimer(tp)
 218: timer_t *tp;
 219: {
 220:   /* Deactivate a timer by removing it from the active and expired lists. */
 221:   timer_t **atp;
 222:   struct proc *p;
 223: 
 224:   tp->tmr_exp_time = TMR_NEVER;
 225: 
 226:   for (atp = &timers; *atp != NULL; atp = &(*atp)->tmr_next) {
 227:         if (*atp == tp) {
 228:                 *atp = tp->tmr_next;
 229:                 return;
 230:         }
 231:   }
 232: 
 233:   p = proc_addr(tp->tmr_task);
 234:   for (atp = &p->p_exptimers; *atp != NULL; atp = &(*atp)->tmr_next) {
 235:         if (*atp == tp) {
 236:                 *atp = tp->tmr_next;
 237:                 return;
 238:         }
 239:   }
 240: }
 241: 
 242: /*===========================================================================*
 243:  *                              tmr_exptimers                                *
 244:  *===========================================================================*/
 245: PUBLIC void tmr_exptimers()
 246: {
 247:   /* One or more timers of the caller may have expired.  Run the functions
 248:    * they reference and deactivate the timers.  This function must be called
 249:    * by the clock task if its main timer expires, or by a task in its main
 250:    * loop if p_exptimers is non-NULL.
 251:    */
 252:   timer_t *tp;
 253:   struct proc *p;
 254: 
 255:   p = proc_ptr;
 256: 
 257:   while ((tp = p->p_exptimers) != NULL) {
 258:         p->p_exptimers = tp->tmr_next;
 259:         tp->tmr_exp_time = TMR_NEVER;
 260:         (*tp->tmr_func)(tp);
 261:   }
 262: }
 263: 
 264: /*===========================================================================*
 265:  *                              do_getuptime                                 *
 266:  *===========================================================================*/
 267: PRIVATE void do_getuptime(m_ptr)
 268: message *m_ptr;                 /* pointer to request message */
 269: {
 270: /* Get and return the current clock uptime in ticks. */
 271: 
 272:   m_ptr->NEW_TIME = realtime;    /* current uptime */
 273: }
 274: 
 275: /*===========================================================================*
 276:  *                              get_uptime                                   *
 277:  *===========================================================================*/
 278: PUBLIC clock_t get_uptime()
 279: {
 280: /* Get and return the current clock uptime in ticks.  This function is
 281:  * designed to be called from other tasks, so they can get uptime without
 282:  * the overhead of messages. It has to be careful about pending_ticks.
 283:  */
 284: 
 285:   clock_t uptime;
 286: 
 287:   lock();
 288:   uptime = realtime + pending_ticks;
 289:   unlock();
 290:   return(uptime);
 291: }
 292: 
 293: /*===========================================================================*
 294:  *                              do_get_time                                  *
 295:  *===========================================================================*/
 296: PRIVATE void do_get_time(m_ptr)
 297: message *m_ptr;                 /* pointer to request message */
 298: {
 299: /* Get and return the current clock time in seconds. */
 300: 
 301:   m_ptr->NEW_TIME = boot_time + realtime/HZ;     /* current real time */
 302: }
 303: 
 304: /*===========================================================================*
 305:  *                              do_set_time                                  *
 306:  *===========================================================================*/
 307: PRIVATE void do_set_time(m_ptr)
 308: message *m_ptr;                 /* pointer to request message */
 309: {
 310: /* Set the real time clock.  Only the superuser can use this call. */
 311: 
 312:   boot_time = m_ptr->NEW_TIME - realtime/HZ;
 313: }
 314: 
 315: /*===========================================================================*
 316:  *                              do_setalarm                                  *
 317:  *===========================================================================*/
 318: PRIVATE void do_setalarm(m_ptr, handler, function)
 319: message *m_ptr;                 /* pointer to request message */
 320: int handler;                    /* CLOCK or SYN_ALRM_TASK */
 321: tmr_func_t function;            /* cause_alarm or cause_synalarm */
 322: {
 323: /* A process requests an alarm signal or a synchronous alarm. */
 324: 
 325:   register struct proc *rp;
 326:   int proc_nr;                  /* which process wants the alarm */
 327:   long delta_ticks;             /* in how many clock ticks does he want it? */
 328:   timer_t *tp;
 329: 
 330:   /* Extract the parameters from the message. */
 331:   proc_nr = m_ptr->CLOCK_PROC_NR;        /* process to interrupt later */
 332:   delta_ticks = m_ptr->DELTA_TICKS;      /* how many ticks to wait */
 333: 
 334:   rp = proc_addr(proc_nr);
 335:   tp = &tmr_alarm[proc_nr];
 336: 
 337:   /* Return the number of seconds left on the old timer. */
 338:   if (tp->tmr_exp_time <= realtime || tp->tmr_exp_time == TMR_NEVER) {
 339:         m_ptr->SECONDS_LEFT = 0;
 340:   } else {
 341:         m_ptr->SECONDS_LEFT = (tp->tmr_exp_time - realtime + (HZ-1)) / HZ;
 342:   }
 343: 
 344:   /* Clear or set the new timer. */
 345:   if (delta_ticks == 0) {
 346:         tmr_clrtimer(tp);
 347:   } else {
 348:         tmr_arg(tp)->ta_int = proc_nr;
 349:         tmr_settimer(tp, handler, get_uptime() + delta_ticks, function);
 350:   }
 351: }
 352: 
 353: /*===========================================================================*
 354:  *                              cause_alarm                                  *
 355:  *===========================================================================*/
 356: PRIVATE void cause_alarm(tp)
 357: timer_t *tp;
 358: {
 359: /* Routine called if a timer goes off for a process that requested an SIGALRM
 360:  * signal using the alarm(2) system call.  The timer argument contains the
 361:  * process number of the process to signal.
 362:  */
 363: 
 364:   cause_sig(tmr_arg(tp)->ta_int, SIGALRM);
 365: }
 366: 
 367: /*===========================================================================*
 368:  *                              cause_synalarm                               *
 369:  *===========================================================================*/
 370: PRIVATE void cause_synalarm(tp)
 371: timer_t *tp;
 372: {
 373: /* Routine called if a timer goes off and the process requested a synchronous
 374:  * alarm.  Send that process a CLOCK_INT message.
 375:  */
 376:   message mess;
 377: 
 378:   mess.m_type= CLOCK_INT;
 379:   send(tmr_arg(tp)->ta_int, &mess);
 380: }
 381: 
 382: /*===========================================================================*
 383:  *                              syn_alrm_task                                *
 384:  *===========================================================================*/
 385: PUBLIC void syn_alrm_task()
 386: {
 387: /* Main program of the synchronous alarm task.
 388:  * All this task ever does is expire timers that call the cause_synalarm
 389:  * function that sends processes a CLOCK_INT message.  These alarm messages
 390:  * are called synchronous alarms because, unlike a signals or the timers
 391:  * run by the CLOCK task, a synchronous alarm is received by a process
 392:  * when it is in a known part of its code, that is, when it has issued
 393:  * a call to receive a message.
 394:  */
 395:   message mess;
 396: 
 397:   while (TRUE) {
 398:         tmr_exptimers();                /* send synchronous alarms */
 399: 
 400:         receive(HARDWARE, &mess);        /* wait for an interrupt */
 401:   }
 402: }
 403: 
 404: /*===========================================================================*
 405:  *                              cancel_alarm                                 *
 406:  *===========================================================================*/
 407: PUBLIC void cancel_alarm(proc_nr)
 408: int proc_nr;                    /* process to cancel alarm for */
 409: {
 410: /* Cancel the alarm timer of a process, probably because it has exited. */
 411: 
 412:   tmr_clrtimer(&tmr_alarm[proc_nr]);
 413: }
 414: 
 415: /*===========================================================================*
 416:  *                              clock_handler                                *
 417:  *===========================================================================*/
 418: PRIVATE int clock_handler(hook)
 419: irq_hook_t *hook;
 420: {
 421: /* This executes on every clock tick (i.e., every time the timer chip
 422:  * generates an interrupt). It does a little bit of work so the clock
 423:  * task does not have to be called on every tick.
 424:  *
 425:  * Switch context to do_clocktick if an alarm has gone off.
 426:  * Also switch there to reschedule if the reschedule will do something.
 427:  * This happens when
 428:  *      (1) quantum has expired
 429:  *      (2) current process received full quantum (as clock sampled it!)
 430:  *      (3) something else is ready to run.
 431:  * Also call TTY and PRINTER and let them do whatever is necessary.
 432:  *
 433:  * Many global global and static variables are accessed here.  The safety
 434:  * of this must be justified.  Most of them are not changed here:
 435:  *      k_reenter:
 436:  *              This safely tells if the clock interrupt is nested.
 437:  *      proc_ptr, bill_ptr:
 438:  *              These are used for accounting.  It does not matter if proc.c
 439:  *              is changing them, provided they are always valid pointers,
 440:  *              since at worst the previous process would be billed.
 441:  *      next_timer, realtime, sched_ticks, bill_ptr, prev_ptr,
 442:  *      rdy_head[USER_Q]:
 443:  *              These are tested to decide whether to call interrupt().  It
 444:  *              does not matter if the test is sometimes (rarely) backwards
 445:  *              due to a race, since this will only delay the high-level
 446:  *              processing by one tick, or call the high level unnecessarily.
 447:  * The variables which are changed require more care:
 448:  *      rp->user_time, rp->sys_time:
 449:  *              These are protected by explicit locks in system.c.  They are
 450:  *              not properly protected in dmp.c (the increment here is not
 451:  *              atomic) but that hardly matters.
 452:  *      pending_ticks:
 453:  *              This is protected by explicit locks in clock.c.  Don't
 454:  *              update realtime directly, since there are too many
 455:  *              references to it to guard conveniently.
 456:  *      lost_ticks:
 457:  *              Clock ticks counted outside the clock task.
 458:  *      sched_ticks, prev_ptr:
 459:  *              Updating these competes with similar code in do_clocktick().
 460:  *              No lock is necessary, because if bad things happen here
 461:  *              (like sched_ticks going negative), the code in do_clocktick()
 462:  *              will restore the variables to reasonable values, and an
 463:  *              occasional missed or extra sched() is harmless.
 464:  *
 465:  * Are these complications worth the trouble?  Well, they make the system 15%
 466:  * faster on a 5MHz 8088, and make task debugging much easier since there are
 467:  * no task switches on an inactive system.
 468:  */
 469: 
 470:   register struct proc *rp;
 471:   register unsigned ticks;
 472:   clock_t now;
 473: 
 474:   if (ps_mca) {
 475:         /* Acknowledge the PS/2 clock interrupt. */
 476:         outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT);
 477:   }
 478: 
 479:   /* Update user and system accounting times.
 480:    * First charge the current process for user time.
 481:    * If the current process is not the billable process (usually because it
 482:    * is a task), charge the billable process for system time as well.
 483:    * Thus the unbillable tasks' user time is the billable users' system time.
 484:    */
 485:   if (k_reenter != 0)
 486:         rp = proc_addr(HARDWARE);
 487:   else
 488:         rp = proc_ptr;
 489:   ticks = lost_ticks + 1;
 490:   lost_ticks = 0;
 491:   rp->user_time += ticks;
 492:   if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;
 493: 
 494:   pending_ticks += ticks;
 495:   now = realtime + pending_ticks;
 496:   if (tty_timeout <= now) tty_wakeup(now);       /* possibly wake up TTY */
 497: #if (CHIP == INTEL) && ENABLE_PRINTER
 498:   pr_restart();                                 /* possibly restart printer */
 499: #endif
 500: #if (CHIP == M68000)
 501:   kb_timer();                                   /* keyboard repeat */
 502:   if (sched_ticks == 1) fd_timer();             /* floppy deselect */
 503: #endif
 504: 
 505:   if (next_timer <= now
 506:         || (sched_ticks == 1 && bill_ptr == prev_ptr
 507:                 && rdy_head[USER_Q] != NIL_PROC)
 508:   ) {
 509:         interrupt(CLOCK);
 510:         return 1;       /* Reenable interrupts */
 511:   }
 512: 
 513:   if (--sched_ticks == 0) {
 514:         /* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
 515:         sched_ticks = SCHED_RATE;       /* reset quantum */
 516:         prev_ptr = bill_ptr;            /* new previous process */
 517:   }
 518:   return 1;     /* Reenable clock interrupt */
 519: }
 520: 
 521: #if (CHIP == INTEL)
 522: 
 523: /*===========================================================================*
 524:  *                              init_clock                                   *
 525:  *===========================================================================*/
 526: PRIVATE void init_clock()
 527: {
 528: /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
 529:   static irq_hook_t clock_hook;
 530: 
 531:   outb(TIMER_MODE, SQUARE_WAVE);        /* set timer to run continuously */
 532:   outb(TIMER0, TIMER_COUNT);            /* load timer low byte */
 533:   outb(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
 534:   put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* register handler */
 535:   enable_irq(&clock_hook);               /* ready for clock interrupts */
 536: }
 537: 
 538: /*===========================================================================*
 539:  *                              clock_stop                                   *
 540:  *===========================================================================*/
 541: PUBLIC void clock_stop()
 542: {
 543: /* Reset the clock to the BIOS rate. (For rebooting) */
 544: 
 545:   outb(TIMER_MODE, 0x36);
 546:   outb(TIMER0, 0);
 547:   outb(TIMER0, 0);
 548: }
 549: 
 550: /*==========================================================================*
 551:  *                              micro_delay                                 *
 552:  *==========================================================================*/
 553: PUBLIC void micro_delay(micros)
 554: unsigned long micros;
 555: {
 556: /* Delay some microseconds. */
 557:   struct micro_state ms;
 558: 
 559:   micro_start(&ms);
 560:   while (micro_elapsed(&ms) < micros) {}
 561: }
 562: 
 563: /*==========================================================================*
 564:  *                              micro_start                                 *
 565:  *==========================================================================*/
 566: PUBLIC void micro_start(msp)
 567: struct micro_state *msp;
 568: {
 569:   /* Prepare for calls to micro_elapsed(). */
 570:   msp->prev_count = 0;
 571:   msp->accum_count = 0;
 572: }
 573: 
 574: /*==========================================================================*
 575:  *                              micro_elapsed                               *
 576:  *==========================================================================*/
 577: PUBLIC unsigned long micro_elapsed(msp)
 578: struct micro_state *msp;
 579: {
 580:   /* Return the number of microseconds since the call to micro_start().  Must
 581:    * be polled rapidly.
 582:    *
 583:    * Micro_elapsed() is used by micro_delay() to busy wait until some
 584:    * number of microseconds have elapsed.  Micro_elapsed() can also be
 585:    * used to poll a device for some time.
 586:    */
 587:   unsigned count;
 588: 
 589:   /* Read the counter of channel 0 of the 8253A timer.  This counter counts
 590:    * down at a rate of TIMER_FREQ and restarts at TIMER_COUNT-1 when it
 591:    * reaches zero.  We count each tick here, unlike the main task that cares
 592:    * more about the HZ per second restarts.
 593:    */
 594:   lock();
 595:   outb(TIMER_MODE, LATCH_COUNT);
 596:   count = inb(TIMER0);
 597:   count |= (inb(TIMER0) << 8);
 598:   unlock();
 599: 
 600:   /* Add difference between previous and new count unless the counter has
 601:    * increased (restarted its cycle).  In that case add 1, which should be
 602:    * correct when polling rapidly.
 603:    */
 604:   msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
 605:   msp->prev_count = count;
 606: 
 607:   /* Return the number of microseconds counted, avoiding overflow. */
 608:   if (msp->accum_count < ULONG_MAX / 1000000) {
 609:         /* Precise for about 3600 us. */
 610:         return msp->accum_count * 1000000 / TIMER_FREQ;
 611:   } else {
 612:         /* Longer periods need not be so precise. */
 613:         return msp->accum_count / TIMER_FREQ * 1000000;
 614:   }
 615: }
 616: #endif /* (CHIP == INTEL) */
 617: 
 618: 
 619: #if (CHIP == M68000)
 620: #include "staddr.h"
 621: #include "stmfp.h"
 622: 
 623: /*===========================================================================*
 624:  *                              init_clock                                   *
 625:  *===========================================================================*/
 626: PRIVATE void init_clock()
 627: {
 628: /* Initialize the timer C in the MFP 68901.
 629:  * Reducing to HZ is not possible by hardware.  The resulting interrupt
 630:  * rate is further reduced by software with a factor of 4.
 631:  * Note that the expression below works for both HZ=50 and HZ=60.
 632:  */
 633:   do {
 634:         MFP->mf_tcdr = TIMER_FREQ/(64*4*HZ);
 635:   } while ((MFP->mf_tcdr & 0xFF) != TIMER_FREQ/(64*4*HZ));
 636:   MFP->mf_tcdcr |= (T_Q064<<4);
 637: }
 638: #endif /* (CHIP == M68000) */