Package: util-linux Version: 2.12p-4 Tags: patch Here's a patch that takes the code distributed in util-linux source as hwclock/clock-ppc.c and modifies it to work with the clock_ops structure. It allows PPC machines running kernels without /dev/rtc support to fall back to modifying the hardware click via ADB.
It's lower precision than the /dev/rtc method, but as far as I can tell, all the functionality has survived from Paul's code. The patch applies to 2.12p and 2.12q. I got no response when I submitted this to [EMAIL PROTECTED] (the address mentioned in the INSTALL file)
diff -urN util-linux-2.12q/hwclock/adb.c util-linux-2.12q-new/hwclock/adb.c --- util-linux-2.12q/hwclock/adb.c 1969-12-31 19:00:00.000000000 -0500 +++ util-linux-2.12q-new/hwclock/adb.c 2005-04-28 18:45:57.000000000 -0400 @@ -0,0 +1,143 @@ +#include <unistd.h> /* for write(), read() */ +#include <fcntl.h> /* for O_RDWR */ +#include <errno.h> + +#include <linux/adb.h> +#include <linux/cuda.h> + +#include "nls.h" + +#include "clock.h" + +/* Apparently the RTC on PowerMacs stores seconds since 1 Jan 1904 */ +#define RTC_OFFSET 2082844800 + +static int adb_fd; + +static unsigned char get_packet[2] = { (unsigned char) CUDA_PACKET, + (unsigned char) CUDA_GET_TIME }; +static unsigned char set_packet[6] = { (unsigned char) CUDA_PACKET, + (unsigned char) CUDA_SET_TIME }; + +static int +synchronize_to_clock_tick_adb(void) { + /* I don't know how to do this via adb */ + return 0; +} + +static int +read_hardware_clock_adb(struct tm *tm) { + int ii; + time_t clock_time; + unsigned char reply[16]; + + if (write(adb_fd, get_packet, sizeof(get_packet)) < 0) { + perror("write adb"); + exit(EXIT_FAILURE); + } + ii = (int) read(adb_fd, reply, sizeof(reply)); + if (ii < 0) { + perror("read adb"); + exit(EXIT_FAILURE); + } + if (ii != 7) + (void) fprintf(stderr, + "Warning: bad reply length from CUDA (%d)\n", ii); + clock_time = (time_t) ((reply[3] << 24) + (reply[4] << 16) + + (reply[5] << 8)) + (time_t) reply[6]; + clock_time -= RTC_OFFSET; + + gmtime_r(&clock_time, tm); /* Should this be localtime()? */ + if (debug) + (void) printf("time in rtc is %s", asctime(tm)); + tm->tm_isdst = -1; + return 0; +} + +static int +set_hardware_clock_adb(const struct tm *new_broken_time) { + int i; + time_t clock_time; + char * zone; + unsigned char reply[16]; + + zone = (char *) getenv ("TZ"); /* save original time zone */ + (void) putenv ("TZ="); + tzset (); + clock_time = mktime (new_broken_time); + /* now put back the original zone */ + if (zone) { + char *zonebuf; + zonebuf = malloc (strlen (zone) + 4); + strcpy (zonebuf, "TZ="); + strcpy (zonebuf+3, zone); + putenv (zonebuf); + free (zonebuf); + } + else { /* wasn't one, so clear it */ + putenv ("TZ"); + } + tzset (); + + clock_time += RTC_OFFSET; + set_packet[2] = clock_time >> 24; + set_packet[3] = clock_time >> 16; + set_packet[4] = clock_time >> 8; + set_packet[5] = (unsigned char) clock_time; + + if (write(adb_fd, set_packet, sizeof(set_packet)) < 0) { + perror("write adb (set)"); + exit(EXIT_FAILURE); + } + i = (int) read(adb_fd, reply, sizeof(reply)); + if (debug) { + int j; + (void) printf("set reply %d bytes:", i); + for (j = 0; j < i; ++j) + (void) printf(" %.2x", (unsigned int) reply[j]); + (void) printf("\n"); + } + if (i != 3 || reply[1] != (unsigned char) 0) + (void) fprintf(stderr, "Warning: error %d setting RTC\n", + (int) reply[1]); + + if (debug) { + clock_time -= RTC_OFFSET; + (void) printf("set RTC to %s", asctime(gmtime(&clock_time))); + } + return 0; +} + +static int +get_permissions_adb(void) { + if ((adb_fd = open ("/dev/adb", O_RDWR)) < 0) { + int errsv = errno; + fprintf(stderr, _("Cannot open /dev/port: %s"), strerror(errsv)); + fprintf(stderr, _("Probably you need root priveledges.\n")); + return 1; + } + return 0; +} + +static struct clock_ops adb = { + "adb interface to powerpc clock", + get_permissions_adb, + read_hardware_clock_adb, + set_hardware_clock_adb, + synchronize_to_clock_tick_adb, +}; + + +/* return &adb if adb clock present, NULL otherwise */ +/* choose this construction to avoid gcc messages about unused variables */ + +struct clock_ops * +probe_for_adb_clock(void){ + int have_adb = +#if defined(__powerpc__) + TRUE; +#else + FALSE; +#endif + return have_adb ? &adb : NULL; +} diff -urN util-linux-2.12q/hwclock/clock.h util-linux-2.12q-new/hwclock/clock.h --- util-linux-2.12q/hwclock/clock.h 2000-12-07 11:39:53.000000000 -0500 +++ util-linux-2.12q-new/hwclock/clock.h 2005-04-28 13:06:20.000000000 -0400 @@ -15,6 +15,7 @@ extern struct clock_ops *probe_for_cmos_clock(void); extern struct clock_ops *probe_for_rtc_clock(void); extern struct clock_ops *probe_for_kd_clock(void); +extern struct clock_ops *probe_for_adb_clock(void); typedef int bool; #define TRUE 1 diff -urN util-linux-2.12q/hwclock/hwclock.c util-linux-2.12q-new/hwclock/hwclo ck.c --- util-linux-2.12q/hwclock/hwclock.c 2004-12-15 14:13:48.000000000 -0500 +++ util-linux-2.12q-new/hwclock/hwclock.c 2005-04-28 12:36:19.000000000 -0400 @@ -1010,6 +1010,9 @@ if (!ur && !user_requests_ISA) ur = probe_for_cmos_clock(); + if (!ur) + ur = probe_for_adb_clock(); + if (debug) { if (ur) printf(_("Using %s.\n"), ur->interface_name); diff -urN util-linux-2.12q/hwclock/Makefile util-linux-2.12q-new/hwclock/Makefi le --- util-linux-2.12q/hwclock/Makefile 2004-12-15 14:11:59.000000000 -0500 +++ util-linux-2.12q-new/hwclock/Makefile 2005-04-28 12:35:04.000000000 -0400 @@ -19,7 +19,7 @@ hwclock.o: hwclock.c hwclock.o cmos.o kd.o: ../defines.h hwclock.o cmos.o rtc.o kd.o: clock.h -hwclock: hwclock.o cmos.o rtc.o kd.o +hwclock: hwclock.o cmos.o rtc.o kd.o adb.o CWFLAGS := $(subst -Wmissing-prototypes,,$(CFLAGS))