home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / kernel / time.c < prev   
Encoding:
C/C++ Source or Header  |  1995-02-01  |  13.5 KB  |  485 lines

  1. /*
  2.  *  linux/kernel/time.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  *  This file contains the interface functions for the various
  7.  *  time related system calls: time, stime, gettimeofday, settimeofday,
  8.  *                   adjtime
  9.  */
  10. /*
  11.  * Modification history kernel/time.c
  12.  * 
  13.  * 02 Sep 93    Philip Gladstone
  14.  *      Created file with time related functions from sched.c and adjtimex() 
  15.  * 08 Oct 93    Torsten Duwe
  16.  *      adjtime interface update and CMOS clock write code
  17.  * 02 Jul 94    Alan Modra
  18.  *    fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
  19.  */
  20.  
  21. #include <linux/errno.h>
  22. #include <linux/sched.h>
  23. #include <linux/kernel.h>
  24. #include <linux/param.h>
  25. #include <linux/string.h>
  26. #include <linux/mm.h>
  27.  
  28. #include <asm/segment.h>
  29. #include <asm/io.h>
  30.  
  31. #include <linux/mc146818rtc.h>
  32. #include <linux/timex.h>
  33.  
  34. /* converts date to days since 1/1/1970
  35.  * assumes year,mon,day in normal date format
  36.  * ie. 1/1/1970 => year=1970, mon=1, day=1
  37.  *
  38.  * For the Julian calendar (which was used in Russia before 1917,
  39.  * Britain & colonies before 1752, anywhere else before 1582,
  40.  * and is still in use by some communities) leave out the
  41.  * -year/100+year/400 terms, and add 10.
  42.  *
  43.  * This algorithm was first published by Gauss (I think).
  44.  */
  45. static inline unsigned long mktime(unsigned int year, unsigned int mon,
  46.     unsigned int day, unsigned int hour,
  47.     unsigned int min, unsigned int sec)
  48. {
  49.     if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
  50.         mon += 12;    /* Puts Feb last since it has leap day */
  51.         year -= 1;
  52.     }
  53.     return (((
  54.         (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
  55.           year*365 - 719499
  56.         )*24 + hour /* now have hours */
  57.        )*60 + min /* now have minutes */
  58.       )*60 + sec; /* finally seconds */
  59. }
  60.  
  61. void time_init(void)
  62. {
  63.     unsigned int year, mon, day, hour, min, sec;
  64.     int i;
  65.  
  66.     /* checking for Update-In-Progress could be done more elegantly
  67.      * (using the "update finished"-interrupt for example), but that
  68.      * would require excessive testing. promise I'll do that when I find
  69.      * the time.            - Torsten
  70.      */
  71.     /* read RTC exactly on falling edge of update flag */
  72.     for (i = 0 ; i < 1000000 ; i++)    /* may take up to 1 second... */
  73.         if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
  74.             break;
  75.     for (i = 0 ; i < 1000000 ; i++)    /* must try at least 2.228 ms*/
  76.         if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
  77.             break;
  78.     do { /* Isn't this overkill ? UIP above should guarantee consistency */
  79.         sec = CMOS_READ(RTC_SECONDS);
  80.         min = CMOS_READ(RTC_MINUTES);
  81.         hour = CMOS_READ(RTC_HOURS);
  82.         day = CMOS_READ(RTC_DAY_OF_MONTH);
  83.         mon = CMOS_READ(RTC_MONTH);
  84.         year = CMOS_READ(RTC_YEAR);
  85.     } while (sec != CMOS_READ(RTC_SECONDS));
  86.     if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  87.       {
  88.         BCD_TO_BIN(sec);
  89.         BCD_TO_BIN(min);
  90.         BCD_TO_BIN(hour);
  91.         BCD_TO_BIN(day);
  92.         BCD_TO_BIN(mon);
  93.         BCD_TO_BIN(year);
  94.       }
  95.     if ((year += 1900) < 1970)
  96.         year += 100;
  97.     xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
  98.     xtime.tv_usec = 0;
  99. }
  100. /* 
  101.  * The timezone where the local system is located.  Used as a default by some
  102.  * programs who obtain this value by using gettimeofday.
  103.  */
  104. struct timezone sys_tz = { 0, 0};
  105.  
  106. asmlinkage int sys_time(long * tloc)
  107. {
  108.     int i, error;
  109.  
  110.     i = CURRENT_TIME;
  111.     if (tloc) {
  112.         error = verify_area(VERIFY_WRITE, tloc, 4);
  113.         if (error)
  114.             return error;
  115.         put_fs_long(i,(unsigned long *)tloc);
  116.     }
  117.     return i;
  118. }
  119.  
  120. asmlinkage int sys_stime(unsigned long * tptr)
  121. {
  122.     int error;
  123.     unsigned long value;
  124.  
  125.     if (!suser())
  126.         return -EPERM;
  127.     error = verify_area(VERIFY_READ, tptr, sizeof(*tptr));
  128.     if (error)
  129.         return error;
  130.     value = get_fs_long(tptr);
  131.     cli();
  132.     xtime.tv_sec = value;
  133.     xtime.tv_usec = 0;
  134.     time_status = TIME_BAD;
  135.     time_maxerror = 0x70000000;
  136.     time_esterror = 0x70000000;
  137.     sti();
  138.     return 0;
  139. }
  140.  
  141. /* This function must be called with interrupts disabled 
  142.  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
  143.  * 
  144.  * However, the pc-audio speaker driver changes the divisor so that
  145.  * it gets interrupted rather more often - it loads 64 into the
  146.  * counter rather than 11932! This has an adverse impact on
  147.  * do_gettimeoffset() -- it stops working! What is also not
  148.  * good is that the interval that our timer function gets called
  149.  * is no longer 10.0002 msecs, but 9.9767 msec. To get around this
  150.  * would require using a different timing source. Maybe someone
  151.  * could use the RTC - I know that this can interrupt at frequencies
  152.  * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
  153.  * it so that at startup, the timer code in sched.c would select
  154.  * using either the RTC or the 8253 timer. The decision would be
  155.  * based on whether there was any other device around that needed
  156.  * to trample on the 8253. I'd set up the RTC to interrupt at 1024Hz,
  157.  * and then do some jiggery to have a version of do_timer that 
  158.  * advanced the clock by 1/1024 sec. Every time that reached over 1/100
  159.  * of a second, then do all the old code. If the time was kept correct
  160.  * then do_gettimeoffset could just return 0 - there is no low order
  161.  * divider that can be accessed.
  162.  *
  163.  * Ideally, you would be able to use the RTC for the speaker driver,
  164.  * but it appears that the speaker driver really needs interrupt more
  165.  * often than every 120us or so.
  166.  *
  167.  * Anyway, this needs more thought....        pjsg (28 Aug 93)
  168.  * 
  169.  * If you are really that interested, you should be reading
  170.  * comp.protocols.time.ntp!
  171.  */
  172.  
  173. #define TICK_SIZE tick
  174.  
  175. static inline unsigned long do_gettimeoffset(void)
  176. {
  177.     int count;
  178.     unsigned long offset = 0;
  179.  
  180.     /* timer count may underflow right here */
  181.     outb_p(0x00, 0x43);    /* latch the count ASAP */
  182.     count = inb_p(0x40);    /* read the latched count */
  183.     count |= inb(0x40) << 8;
  184.     /* we know probability of underflow is always MUCH less than 1% */
  185.     if (count > (LATCH - LATCH/100)) {
  186.         /* check for pending timer interrupt */
  187.         outb_p(0x0a, 0x20);
  188.         if (inb(0x20) & 1)
  189.             offset = TICK_SIZE;
  190.     }
  191.     count = ((LATCH-1) - count) * TICK_SIZE;
  192.     count = (count + LATCH/2) / LATCH;
  193.     return offset + count;
  194. }
  195.  
  196. /*
  197.  * This version of gettimeofday has near microsecond resolution.
  198.  */
  199. void do_gettimeofday(struct timeval *tv)
  200. {
  201.     unsigned long flags;
  202.  
  203.     save_flags(flags);
  204.     cli();
  205.     *tv = xtime;
  206. #if defined (__i386__) || defined (__mips__)
  207.     tv->tv_usec += do_gettimeoffset();
  208.     if (tv->tv_usec >= 1000000) {
  209.         tv->tv_usec -= 1000000;
  210.         tv->tv_sec++;
  211.     }
  212. #endif /* !defined (__i386__) && !defined (__mips__) */
  213.     restore_flags(flags);
  214. }
  215.  
  216. asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
  217. {
  218.     int error;
  219.  
  220.     if (tv) {
  221.         struct timeval ktv;
  222.         error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
  223.         if (error)
  224.             return error;
  225.         do_gettimeofday(&ktv);
  226.         put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
  227.         put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
  228.     }
  229.     if (tz) {
  230.         error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
  231.         if (error)
  232.             return error;
  233.         put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
  234.         put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
  235.     }
  236.     return 0;
  237. }
  238.  
  239. /*
  240.  * Adjust the time obtained from the CMOS to be GMT time instead of
  241.  * local time.
  242.  * 
  243.  * This is ugly, but preferable to the alternatives.  Otherwise we
  244.  * would either need to write a program to do it in /etc/rc (and risk
  245.  * confusion if the program gets run more than once; it would also be 
  246.  * hard to make the program warp the clock precisely n hours)  or
  247.  * compile in the timezone information into the kernel.  Bad, bad....
  248.  *
  249.  * XXX Currently does not adjust for daylight savings time.  May not
  250.  * need to do anything, depending on how smart (dumb?) the BIOS
  251.  * is.  Blast it all.... the best thing to do not depend on the CMOS
  252.  * clock at all, but get the time via NTP or timed if you're on a 
  253.  * network....                - TYT, 1/1/92
  254.  */
  255. inline static void warp_clock(void)
  256. {
  257.     cli();
  258.     xtime.tv_sec += sys_tz.tz_minuteswest * 60;
  259.     sti();
  260. }
  261.  
  262. /*
  263.  * The first time we set the timezone, we will warp the clock so that
  264.  * it is ticking GMT time instead of local time.  Presumably, 
  265.  * if someone is setting the timezone then we are running in an
  266.  * environment where the programs understand about timezones.
  267.  * This should be done at boot time in the /etc/rc script, as
  268.  * soon as possible, so that the clock can be set right.  Otherwise,
  269.  * various programs will get confused when the clock gets warped.
  270.  */
  271. asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
  272. {
  273.     static int    firsttime = 1;
  274.     struct timeval    new_tv;
  275.     struct timezone new_tz;
  276.  
  277.     if (!suser())
  278.         return -EPERM;
  279.     if (tv) {
  280.         int error = verify_area(VERIFY_READ, tv, sizeof(*tv));
  281.         if (error)
  282.             return error;
  283.         memcpy_fromfs(&new_tv, tv, sizeof(*tv));
  284.     }
  285.     if (tz) {
  286.         int error = verify_area(VERIFY_READ, tz, sizeof(*tz));
  287.         if (error)
  288.             return error;
  289.         memcpy_fromfs(&new_tz, tz, sizeof(*tz));
  290.     }
  291.     if (tz) {
  292.         sys_tz = new_tz;
  293.         if (firsttime) {
  294.             firsttime = 0;
  295.             if (!tv)
  296.                 warp_clock();
  297.         }
  298.     }
  299.     if (tv) {
  300.         cli();
  301.         /* This is revolting. We need to set the xtime.tv_usec
  302.          * correctly. However, the value in this location is
  303.          * is value at the last tick.
  304.          * Discover what correction gettimeofday
  305.          * would have done, and then undo it!
  306.          */
  307.         new_tv.tv_usec -= do_gettimeoffset();
  308.  
  309.         if (new_tv.tv_usec < 0) {
  310.             new_tv.tv_usec += 1000000;
  311.             new_tv.tv_sec--;
  312.         }
  313.  
  314.         xtime = new_tv;
  315.         time_status = TIME_BAD;
  316.         time_maxerror = 0x70000000;
  317.         time_esterror = 0x70000000;
  318.         sti();
  319.     }
  320.     return 0;
  321. }
  322.  
  323. /* adjtimex mainly allows reading (and writing, if superuser) of
  324.  * kernel time-keeping variables. used by xntpd.
  325.  */
  326. asmlinkage int sys_adjtimex(struct timex *txc_p)
  327. {
  328.         long ltemp, mtemp, save_adjust;
  329.     int error;
  330.  
  331.     /* Local copy of parameter */
  332.     struct timex txc;
  333.  
  334.     error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
  335.     if (error)
  336.       return error;
  337.  
  338.     /* Copy the user data space into the kernel copy
  339.      * structure. But bear in mind that the structures
  340.      * may change
  341.      */
  342.     memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
  343.  
  344.     /* In order to modify anything, you gotta be super-user! */
  345.     if (txc.mode && !suser())
  346.         return -EPERM;
  347.  
  348.     /* Now we validate the data before disabling interrupts
  349.      */
  350.  
  351.     if (txc.mode != ADJ_OFFSET_SINGLESHOT && (txc.mode & ADJ_OFFSET))
  352.       /* Microsec field limited to -131000 .. 131000 usecs */
  353.       if (txc.offset <= -(1 << (31 - SHIFT_UPDATE))
  354.           || txc.offset >= (1 << (31 - SHIFT_UPDATE)))
  355.         return -EINVAL;
  356.  
  357.     /* time_status must be in a fairly small range */
  358.     if (txc.mode & ADJ_STATUS)
  359.       if (txc.status < TIME_OK || txc.status > TIME_BAD)
  360.         return -EINVAL;
  361.  
  362.     /* if the quartz is off by more than 10% something is VERY wrong ! */
  363.     if (txc.mode & ADJ_TICK)
  364.       if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
  365.         return -EINVAL;
  366.  
  367.     cli();
  368.  
  369.     /* Save for later - semantics of adjtime is to return old value */
  370.     save_adjust = time_adjust;
  371.  
  372.     /* If there are input parameters, then process them */
  373.     if (txc.mode)
  374.     {
  375.         if (time_status == TIME_BAD)
  376.         time_status = TIME_OK;
  377.  
  378.         if (txc.mode & ADJ_STATUS)
  379.         time_status = txc.status;
  380.  
  381.         if (txc.mode & ADJ_FREQUENCY)
  382.         time_freq = txc.frequency << (SHIFT_KF - 16);
  383.  
  384.         if (txc.mode & ADJ_MAXERROR)
  385.         time_maxerror = txc.maxerror;
  386.  
  387.         if (txc.mode & ADJ_ESTERROR)
  388.         time_esterror = txc.esterror;
  389.  
  390.         if (txc.mode & ADJ_TIMECONST)
  391.         time_constant = txc.time_constant;
  392.  
  393.         if (txc.mode & ADJ_OFFSET)
  394.           if (txc.mode == ADJ_OFFSET_SINGLESHOT)
  395.         {
  396.           time_adjust = txc.offset;
  397.         }
  398.           else /* XXX should give an error if other bits set */
  399.         {
  400.           time_offset = txc.offset << SHIFT_UPDATE;
  401.           mtemp = xtime.tv_sec - time_reftime;
  402.           time_reftime = xtime.tv_sec;
  403.           if (mtemp > (MAXSEC+2) || mtemp < 0)
  404.             mtemp = 0;
  405.  
  406.           if (txc.offset < 0)
  407.             time_freq -= (-txc.offset * mtemp) >>
  408.               (time_constant + time_constant);
  409.           else
  410.             time_freq += (txc.offset * mtemp) >>
  411.               (time_constant + time_constant);
  412.  
  413.           ltemp = time_tolerance << SHIFT_KF;
  414.  
  415.           if (time_freq > ltemp)
  416.             time_freq = ltemp;
  417.           else if (time_freq < -ltemp)
  418.             time_freq = -ltemp;
  419.         }
  420.         if (txc.mode & ADJ_TICK)
  421.           tick = txc.tick;
  422.  
  423.     }
  424.     txc.offset       = save_adjust;
  425.     txc.frequency       = ((time_freq+1) >> (SHIFT_KF - 16));
  426.     txc.maxerror       = time_maxerror;
  427.     txc.esterror       = time_esterror;
  428.     txc.status       = time_status;
  429.     txc.time_constant  = time_constant;
  430.     txc.precision       = time_precision;
  431.     txc.tolerance       = time_tolerance;
  432.     txc.time       = xtime;
  433.     txc.tick       = tick;
  434.  
  435.     sti();
  436.  
  437.     memcpy_tofs(txc_p, &txc, sizeof(struct timex));
  438.     return time_status;
  439. }
  440.  
  441. int set_rtc_mmss(unsigned long nowtime)
  442. {
  443.   int retval = 0;
  444.   int real_seconds, real_minutes, cmos_minutes;
  445.   unsigned char save_control, save_freq_select;
  446.  
  447.   save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
  448.   CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
  449.  
  450.   save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
  451.   CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
  452.  
  453.   cmos_minutes = CMOS_READ(RTC_MINUTES);
  454.   if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  455.     BCD_TO_BIN(cmos_minutes);
  456.  
  457.   /* since we're only adjusting minutes and seconds,
  458.    * don't interfere with hour overflow. This avoids
  459.    * messing with unknown time zones but requires your
  460.    * RTC not to be off by more than 15 minutes
  461.    */
  462.   real_seconds = nowtime % 60;
  463.   real_minutes = nowtime / 60;
  464.   if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
  465.     real_minutes += 30;        /* correct for half hour time zone */
  466.   real_minutes %= 60;
  467.  
  468.   if (abs(real_minutes - cmos_minutes) < 30)
  469.     {
  470.       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  471.     {
  472.       BIN_TO_BCD(real_seconds);
  473.       BIN_TO_BCD(real_minutes);
  474.     }
  475.       CMOS_WRITE(real_seconds,RTC_SECONDS);
  476.       CMOS_WRITE(real_minutes,RTC_MINUTES);
  477.     }
  478.   else
  479.     retval = -1;
  480.  
  481.   CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
  482.   CMOS_WRITE(save_control, RTC_CONTROL);
  483.   return retval;
  484. }
  485.