]> git.pld-linux.org Git - packages/util-linux.git/blob - util-linux-ppc-hwclock.patch
- init var
[packages/util-linux.git] / util-linux-ppc-hwclock.patch
1 diff -urN util-linux-2.11n.org/clock-ppc.c util-linux-2.11n/clock-ppc.c
2 --- util-linux-2.11n.org/clock-ppc.c    Thu Jan  1 01:00:00 1970
3 +++ util-linux-2.11n/clock-ppc.c        Thu Mar  7 21:15:39 2002
4 @@ -0,0 +1,472 @@
5 +#include <stdio.h>
6 +#include <stdlib.h>
7 +#include <string.h>
8 +#include <errno.h>
9 +#include <unistd.h>
10 +
11 +#include <time.h>
12 +#include <fcntl.h>
13 +#include <getopt.h>
14 +#include <sys/time.h>
15 +
16 +#include <linux/version.h>
17 +
18 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0)
19 +#include <asm/cuda.h>
20 +#else
21 +#include <linux/cuda.h>
22 +#endif
23 +
24 +/*
25 + * Adapted for Power Macintosh by Paul Mackerras.
26 + */
27 +
28 +/* V1.0
29 + * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992
30 + * 
31 + * clock [-u] -r  - read cmos clock
32 + * clock [-u] -w  - write cmos clock from system time
33 + * clock [-u] -s  - set system time from cmos clock
34 + * clock [-u] -a  - set system time from cmos clock, adjust the time to
35 + *                  correct for systematic error, and put it back to the cmos.
36 + *  -u indicates cmos clock is kept in universal time
37 + *
38 + * The program is designed to run setuid, since we need to be able to
39 + * write to the CUDA.
40 + *
41 + *********************
42 + * V1.1
43 + * Modified for clock adjustments - Rob Hooft, hooft@chem.ruu.nl, Nov 1992
44 + * Also moved error messages to stderr. The program now uses getopt.
45 + * Changed some exit codes. Made 'gcc 2.3 -Wall' happy.
46 + *
47 + * I think a small explanation of the adjustment routine should be given
48 + * here. The problem with my machine is that its CMOS clock is 10 seconds 
49 + * per day slow. With this version of clock.c, and my '/etc/rc.local' 
50 + * reading '/etc/clock -au' instead of '/etc/clock -u -s', this error 
51 + * is automatically corrected at every boot. 
52 + *
53 + * To do this job, the program reads and writes the file '/etc/adjtime' 
54 + * to determine the correction, and to save its data. In this file are 
55 + * three numbers: 
56 + *
57 + * 1) the correction in seconds per day (So if your clock runs 5 
58 + *    seconds per day fast, the first number should read -5.0)
59 + * 2) the number of seconds since 1/1/1970 the last time the program was
60 + *    used.
61 + * 3) the remaining part of a second which was leftover after the last 
62 + *    adjustment
63 + *
64 + * Installation and use of this program:
65 + *
66 + * a) create a file '/etc/adjtime' containing as the first and only line:
67 + *    '0.0 0 0.0'
68 + * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in
69 + *    universal or local time. This updates the second number.
70 + * c) set your system time using the 'date' command.
71 + * d) update your cmos time using 'clock -wu' or 'clock -w'
72 + * e) replace the first number in /etc/adjtime by your correction.
73 + * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local'
74 + *
75 + * If the adjustment doesn't work for you, try contacting me by E-mail.
76 + *
77 + ******
78 + * V1.2
79 + *
80 + * Applied patches by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de)
81 + * Patched and indented by Rob Hooft (hooft@EMBL-Heidelberg.DE)
82 + * 
83 + * A free quote from a MAIL-message (with spelling corrections):
84 + *
85 + * "I found the explanation and solution for the CMOS reading 0xff problem
86 + *  in the 0.99pl13c (ALPHA) kernel: the RTC goes offline for a small amount
87 + *  of time for updating. Solution is included in the kernel source 
88 + *  (linux/kernel/time.c)."
89 + *
90 + * "I modified clock.c to fix this problem and added an option (now default,
91 + *  look for USE_INLINE_ASM_IO) that I/O instructions are used as inline
92 + *  code and not via /dev/port (still possible via #undef ...)."
93 + *
94 + * With the new code, which is partially taken from the kernel sources, 
95 + * the CMOS clock handling looks much more "official".
96 + * Thanks Harald (and Torsten for the kernel code)!
97 + *
98 + ******
99 + * V1.3
100 + * Canges from alan@spri.levels.unisa.edu.au (Alan Modra):
101 + * a) Fix a few typos in comments and remove reference to making
102 + *    clock -u a cron job.  The kernel adjusts cmos time every 11
103 + *    minutes - see kernel/sched.c and kernel/time.c set_rtc_mmss().
104 + *    This means we should really have a cron job updating
105 + *    /etc/adjtime every 11 mins (set last_time to the current time
106 + *    and not_adjusted to ???).
107 + * b) Swapped arguments of outb() to agree with asm/io.h macro of the
108 + *    same name.  Use outb() from asm/io.h as it's slightly better.
109 + * c) Changed CMOS_READ and CMOS_WRITE to inline functions.  Inserted
110 + *    cli()..sti() pairs in appropriate places to prevent possible
111 + *    errors, and changed ioperm() call to iopl() to allow cli.
112 + * d) Moved some variables around to localise them a bit.
113 + * e) Fixed bug with clock -ua or clock -us that cleared environment
114 + *    variable TZ.  This fix also cured the annoying display of bogus
115 + *    day of week on a number of machines. (Use mktime(), ctime()
116 + *    rather than asctime() )
117 + * f) Use settimeofday() rather than stime().  This one is important
118 + *    as it sets the kernel's timezone offset, which is returned by
119 + *    gettimeofday(), and used for display of MSDOS and OS2 file
120 + *    times.
121 + * g) faith@cs.unc.edu added -D flag for debugging
122 + *
123 + * V1.4: alan@SPRI.Levels.UniSA.Edu.Au (Alan Modra)
124 + *       Wed Feb  8 12:29:08 1995, fix for years > 2000.
125 + *       faith@cs.unc.edu added -v option to print version.
126 + *
127 + * August 1996 Tom Dyas (tdyas@eden.rutgers.edu)
128 + *       Converted to be compatible with the SPARC /dev/rtc driver.
129 + *
130 + */
131 +
132 +#define VERSION "1.4"
133 +#define ADB_PACKET      0
134 +#define CUDA_PACKET     1
135 +#define ERROR_PACKET    2
136 +#define TIMER_PACKET    3
137 +#define POWER_PACKET    4
138 +#define MACIIC_PACKET   5
139 +#define PMU_PACKET      6
140 +
141 +/* Here the information for time adjustments is kept. */
142 +#define ADJPATH "/etc/adjtime"
143 +
144 +/* Apparently the RTC on PowerMacs stores seconds since 1 Jan 1904 */
145 +#define RTC_OFFSET     2082844800
146 +
147 +/* used for debugging the code. */
148 +/*#define KEEP_OFF */
149 +
150 +/* Globals */
151 +int readit = 0;
152 +int adjustit = 0;
153 +int writeit = 0;
154 +int setit = 0;
155 +int universal = 0;
156 +int debug = 0;
157 +
158 +time_t mkgmtime(struct tm *);
159 +
160 +volatile void 
161 +usage ( void )
162 +{
163 +  (void) fprintf (stderr, 
164 +    "clock [-u] -r|w|s|a|v\n"
165 +    "  r: read and print CMOS clock\n"
166 +    "  w: write CMOS clock from system time\n"
167 +    "  s, --hctosys: set system time from CMOS clock\n"
168 +    "  a, --systohc: get system time and adjust CMOS clock\n"
169 +    "  u, --utc: CMOS clock is in universal time\n"
170 +    "  v: print version (" VERSION ") and exit\n"
171 +  );
172 +  exit(EXIT_FAILURE);
173 +}
174 +
175 +int adb_fd;
176 +
177 +void
178 +adb_init ( void )
179 +{
180 +  adb_fd = open ("/dev/adb", 2);
181 +  if (adb_fd < 0)
182 +    {
183 +      perror ("unable to open /dev/adb read/write : ");
184 +      exit(EXIT_FAILURE);
185 +    }
186 +}
187 +
188 +unsigned char get_packet[2] = { (unsigned char) CUDA_PACKET, 
189 +                               (unsigned char) CUDA_GET_TIME };
190 +unsigned char set_packet[6] = { (unsigned char) CUDA_PACKET, 
191 +                               (unsigned char) CUDA_SET_TIME };
192 +
193 +int 
194 +main (int argc, char **argv )
195 +{
196 +  struct tm tm, *tmp;
197 +  time_t systime;
198 +  time_t last_time;
199 +  time_t clock_time;
200 +  int i, arg;
201 +  double factor;
202 +  double not_adjusted;
203 +  int adjustment = 0;
204 +  /*   unsigned char save_control, save_freq_select; */
205 +  unsigned char reply[16];
206 +
207 +  /*  get clock-ppc to accept systohc, hctosys options like hwclock */
208 +  /* this will avoid having to customize initscripts for Mandrake PPC */
209 +  /*  May 15 2001 - S. Benedict <sbenedict@mandrakesoft.com>        */
210 +  extern char *optarg; 
211 +
212 +  while ((arg = getopt (argc, argv, "rwsuaDv-:")) != -1)
213 +    {
214 +      switch (arg)
215 +       {
216 +       case 'r':
217 +         readit = 1;
218 +         break;
219 +       case 'w':
220 +         writeit = 1;
221 +         break;
222 +       case 's':
223 +         setit = 1;
224 +         break;
225 +       case 'u':
226 +         universal = 1;
227 +         break;
228 +       case 'a':
229 +         adjustit = 1;
230 +         break;
231 +        case 'D':
232 +         debug = 1;
233 +         break;
234 +       case 'v':
235 +         (void) fprintf( stderr, "clock " VERSION "\n" );
236 +         exit(EXIT_SUCCESS);
237 +       case '-':
238 +          if (!strncmp(optarg, "systohc", 7)) {
239 +            adjustit = 1;
240 +            break;
241 +          } 
242 +          if (!strncmp(optarg, "hctosys", 7)) {
243 +            setit = 1;
244 +            break;
245 +          } 
246 +          if (!strncmp(optarg, "localtime", 9)) {
247 +            universal = 0;
248 +            break;
249 +          } 
250 +          if (!strncmp(optarg, "utc", 3)) {
251 +            universal = 1;
252 +            break;
253 +          } 
254 +       default:
255 +         usage ();
256 +       }
257 +    }
258 +
259 +    /* If we are in MkLinux do not even bother trying to set the clock */
260 +    if(!access("/proc/osfmach3/version", R_OK))
261 +    {           // We're running MkLinux
262 +     if ( readit | writeit | setit | adjustit )
263 +       printf("You must change the clock setting in MacOS.\n");
264 +     exit(0);
265 +    }
266 +
267 +  if (readit + writeit + setit + adjustit > 1)
268 +    usage ();                  /* only allow one of these */
269 +
270 +  if (!(readit | writeit | setit | adjustit))  /* default to read */
271 +    readit = 1;
272 +
273 +  adb_init ();
274 +
275 +  if (adjustit)
276 +    {                          /* Read adjustment parameters first */
277 +      FILE *adj;
278 +      if ((adj = fopen (ADJPATH, "r")) == NULL)
279 +       {
280 +         perror (ADJPATH);
281 +         exit(EXIT_FAILURE);
282 +       }
283 +      if (fscanf (adj, "%lf %d %lf", &factor, (int *) (&last_time), 
284 +                 &not_adjusted) < 0)
285 +       {
286 +         perror (ADJPATH);
287 +         exit(EXIT_FAILURE);
288 +       }
289 +      (void) fclose (adj);
290 +      if (debug) (void) printf(
291 +                       "Last adjustment done at %d seconds after 1/1/1970\n",
292 +                       (int) last_time);
293 +    }
294 +
295 +  if (readit || setit || adjustit)
296 +    {
297 +      int ii;
298 +
299 +      if (write(adb_fd, get_packet, sizeof(get_packet)) < 0) {
300 +       perror("write adb");
301 +       exit(EXIT_FAILURE);
302 +      }
303 +      ii = (int) read(adb_fd, reply, sizeof(reply));
304 +      if (ii < 0) {
305 +       perror("read adb");
306 +       exit(EXIT_FAILURE);
307 +      }
308 +      if (ii != 7)
309 +       (void) fprintf(stderr, 
310 +                      "Warning: bad reply length from CUDA (%d)\n", ii);
311 +      clock_time = (time_t) ((reply[3] << 24) + (reply[4] << 16)
312 +                            + (reply[5] << 8)) + (time_t) reply[6];
313 +      clock_time -= RTC_OFFSET;
314 +
315 +      if (universal) {
316 +       systime = clock_time;
317 +      } else {
318 +       tm = *gmtime(&clock_time);
319 +       (void) printf("time in rtc is %s", asctime(&tm));
320 +       tm.tm_isdst = -1;               /* don't know whether it's DST */
321 +       systime = mktime(&tm);
322 +      }
323 +    }
324 +
325 +  if (readit)
326 +    {
327 +      (void) printf ("%s", ctime (&systime ));
328 +    }
329 +
330 +  if (setit || adjustit)
331 +    {
332 +      struct timeval tv;
333 +      struct timezone tz;
334 +
335 +/* program is designed to run setuid, be secure! */
336 +
337 +      if (getuid () != 0)
338 +       {                       
339 +         (void) fprintf (stderr, 
340 +                         "Sorry, must be root to set or adjust time\n");
341 +         exit(EXIT_FAILURE);
342 +       }
343 +
344 +      if (adjustit)
345 +       {                       /* the actual adjustment */
346 +         double exact_adjustment;
347 +
348 +         exact_adjustment = ((double) (systime - last_time))
349 +           * factor / (24 * 60 * 60)
350 +           + not_adjusted;
351 +         if (exact_adjustment > 0.)
352 +           adjustment = (int) (exact_adjustment + 0.5);
353 +         else
354 +           adjustment = (int) (exact_adjustment - 0.5);
355 +         not_adjusted = exact_adjustment - (double) adjustment;
356 +         systime += adjustment;
357 +         if (debug) {
358 +            (void) printf ("Time since last adjustment is %d seconds\n",
359 +                    (int) (systime - last_time));
360 +            (void) printf ("Adjusting time by %d seconds\n",
361 +                    adjustment);
362 +            (void) printf ("remaining adjustment is %.3f seconds\n",
363 +                    not_adjusted);
364 +         }
365 +       }
366 +#ifndef KEEP_OFF
367 +      tv.tv_sec = systime;
368 +      tv.tv_usec = 0;
369 +      tz.tz_minuteswest = timezone / 60;
370 +      tz.tz_dsttime = daylight;
371 +
372 +      if (settimeofday (&tv, &tz) != 0)
373 +        {
374 +         (void) fprintf (stderr,
375 +                  "Unable to set time -- probably you are not root\n");
376 +         exit(EXIT_FAILURE);
377 +       }
378 +      
379 +      if (debug) {
380 +        (void) printf( "Called settimeofday:\n" );
381 +        (void) printf( "\ttv.tv_sec = %ld, tv.tv_usec = %ld\n",
382 +                tv.tv_sec, tv.tv_usec );
383 +        (void) printf( "\ttz.tz_minuteswest = %d, tz.tz_dsttime = %d\n",
384 +                tz.tz_minuteswest, tz.tz_dsttime );
385 +      }
386 +#endif
387 +    }
388 +  
389 +  if (writeit || (adjustit && adjustment != 0))
390 +    {
391 +      systime = time (NULL);
392 +
393 +      if (universal) {
394 +       clock_time = systime;
395 +
396 +      } else {
397 +       tmp = localtime(&systime);
398 +       clock_time = mkgmtime(tmp);
399 +      }
400 +
401 +      clock_time += RTC_OFFSET;
402 +      set_packet[2] = clock_time >> 24;
403 +      set_packet[3] = clock_time >> 16;
404 +      set_packet[4] = clock_time >> 8;
405 +      set_packet[5] = (unsigned char) clock_time;
406 +
407 +      if (write(adb_fd, set_packet, sizeof(set_packet)) < 0) {
408 +       perror("write adb (set)");
409 +       exit(EXIT_FAILURE);
410 +      }
411 +      i = (int) read(adb_fd, reply, sizeof(reply));
412 +      if (debug) {
413 +       int j;
414 +       (void) printf("set reply %d bytes:", i);
415 +       for (j = 0; j < i; ++j) 
416 +           (void) printf(" %.2x", (unsigned int) reply[j]);
417 +       (void) printf("\n");
418 +      }
419 +      if (i != 3 || reply[1] != (unsigned char) 0)
420 +       (void) fprintf(stderr, "Warning: error %d setting RTC\n", 
421 +                      (int) reply[1]);
422 +
423 +      if (debug) {
424 +       clock_time -= RTC_OFFSET;
425 +       (void) printf("set RTC to %s", asctime(gmtime(&clock_time)));
426 +      }
427 +    }
428 +  else
429 +    if (debug) (void) printf ("CMOS clock unchanged.\n");
430 +  /* Save data for next 'adjustit' call */
431 +  if (adjustit)
432 +    {
433 +      FILE *adj;
434 +      if ((adj = fopen (ADJPATH, "w")) == NULL)
435 +       {
436 +         perror (ADJPATH);
437 +         exit(EXIT_FAILURE);
438 +       }
439 +      (void) fprintf (adj, "%f %d %f\n", factor, (int) systime, not_adjusted);
440 +      (void) fclose (adj);
441 +    }
442 +  exit(EXIT_SUCCESS);
443 +}
444 +
445 +/* Stolen from linux/arch/i386/kernel/time.c. */
446 +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
447 + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
448 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
449 + *
450 + * [For the Julian calendar (which was used in Russia before 1917,
451 + * Britain & colonies before 1752, anywhere else before 1582,
452 + * and is still in use by some communities) leave out the
453 + * -year/100+year/400 terms, and add 10.]
454 + *
455 + * This algorithm was first published by Gauss (I think).
456 + *
457 + * WARNING: this function will overflow on 2106-02-07 06:28:16 on
458 + * machines were long is 32-bit! (However, as time_t is signed, we
459 + * will already get problems at other places on 2038-01-19 03:14:08)
460 + */
461 +time_t mkgmtime(struct tm *tm)
462 +{
463 +  int mon = tm->tm_mon + 1;
464 +  int year = tm->tm_year + 1900;
465 +
466 +  if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
467 +    mon += 12; /* Puts Feb last since it has leap day */
468 +    year -= 1;
469 +  }
470 +  return (((
471 +           (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12) +
472 +             tm->tm_mday + year*365 - 719499
473 +           )*24 + tm->tm_hour /* now have hours */
474 +          )*60 + tm->tm_min /* now have minutes */
475 +         )*60 + tm->tm_sec; /* finally seconds */
476 +}
This page took 0.095435 seconds and 3 git commands to generate.