]> git.pld-linux.org Git - packages/util-linux.git/blame - util-linux-ppc-hwclock.patch
- init var
[packages/util-linux.git] / util-linux-ppc-hwclock.patch
CommitLineData
f9d1edda
AM
1diff -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
f097cc42 4@@ -0,0 +1,472 @@
f9d1edda
AM
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+
9f957f60 16+#include <linux/version.h>
17+
18+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0)
19+#include <asm/cuda.h>
20+#else
f9d1edda 21+#include <linux/cuda.h>
9f957f60 22+#endif
f9d1edda
AM
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.071574 seconds and 4 git commands to generate.