On Wed, Aug 6, 2008 at 7:35 PM, Robert Millan <[EMAIL PROTECTED]> wrote:
> Can we make this portable by accessing 0x70 / 0x71 I/O ports instead?

Hi,

Good point. The new patch uses cmos to get datetime setting, it should
be generic among i386 platforms.

2008-08-06  Bean  <[EMAIL PROTECTED]>

        * conf/i386-pc.rmk (pkglib_MODULES): Add chktime.mod.
        (chktime_mod_SOURCES): New macro.
        (chktime_mod_CFLAGS): Likewise.
        (chktime_mod_LDFLAGS): Likewise.

        * commands/checktime.c: New file.

        * include/grub/datetime.h: Likewise.

        * include/grub/i386/cmos.h: Likewise.

        * kern/i386/datetime.c: Likewise.

-- 
Bean
diff --git a/commands/checktime.c b/commands/checktime.c
new file mode 100644
index 0000000..6e3d0d9
--- /dev/null
+++ b/commands/checktime.c
@@ -0,0 +1,147 @@
+/* checktime.c - command to test current date/time.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/arg.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/i386/cmos.h>
+#include <grub/datetime.h>
+
+static grub_err_t
+grub_cmd_checktime (struct grub_arg_list *state __attribute__ ((unused)),
+                    int argc, char **args)
+{
+  int day, month, year, sec, min, hour, dow, i;
+  int limit[5][2] = {{0, 59}, {0, 23}, {1, 31}, {1, 12}, {0, 7}};
+  int field[5];
+
+  auto int get_day_of_week (void);
+  int get_day_of_week (void)
+    {
+      int a, y, m;
+
+      a = (14 - month) / 12;
+      y = year - a;
+      m = month + 12 * a - 2;
+      return (day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
+    }
+
+  if ((grub_get_date (&year, &month, &day)) ||
+      (grub_get_time (&hour, &min, &sec)))
+    return grub_errno;
+
+  dow = get_day_of_week ();
+
+  field[0] = min;
+  field[1] = hour;
+  field[2] = day;
+  field[3] = month;
+  field[4] = dow;
+
+  if (argc == 0)
+    {
+      grub_printf ("%d-%02d-%02d %02d:%02d:%02d %d\n",
+                   year, month, day, hour, min, sec, dow);
+
+      return 0;
+    }
+
+  for (i = 0; i < 5; i++)
+    {
+      char *p;
+      int ok = 0;
+
+      if (i >= argc)
+        return 0;
+
+      p = args[i];
+      while (1)
+        {
+          int m1, m2, m3, j;
+
+          if (*p == '*')
+            {
+              m1 = limit[i][0];
+              m2 = limit[i][1];
+              p++;
+            }
+          else
+            {
+              m1 = grub_strtoul (p, &p, 0);
+
+              if (*p == '-')
+                {
+                  p++;
+                  m2 = grub_strtoul (p, &p, 0);
+                }
+              else
+                m2 = m1;
+            }
+
+          if ((m1 < limit[i][0]) || (m2 > limit[i][1]) || (m1 > m2))
+            break;
+
+          if (*p == '/')
+            {
+              p++;
+              m3 = grub_strtoul (p, &p, 0);
+            }
+          else
+            m3 = 1;
+
+          for (j = m1; j <= m2; j+= m3)
+            {
+              if (j == field[i])
+                {
+                  ok = 1;
+                  break;
+                }
+            }
+
+          if (ok)
+            break;
+
+          if (*p == ',')
+            p++;
+          else
+            break;
+        }
+
+      if (! ok)
+        break;
+    }
+
+  return (i == 5) ? 0 : grub_error (GRUB_ERR_TEST_FAILURE, "false");
+}
+
+GRUB_MOD_INIT(checktime)
+{
+  (void) mod;			/* To stop warning. */
+  grub_register_command ("checktime", grub_cmd_checktime,
+                         GRUB_COMMAND_FLAG_BOTH,
+			 "checktime min hour day_of_month month day_of_week",
+                         "Command to test current date/time.", 0);
+}
+
+GRUB_MOD_FINI(checktime)
+{
+  grub_unregister_command ("checktime");
+}
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index c1e4ac4..f383160 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -163,7 +163,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \
 	vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
 	videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod	\
 	ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \
-	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod
+	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod chktime.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -340,4 +340,9 @@ pxecmd_mod_SOURCES = commands/i386/pc/pxecmd.c
 pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For chktime.mod
+chktime_mod_SOURCES = commands/checktime.c kern/i386/datetime.c
+chktime_mod_CFLAGS = $(COMMON_CFLAGS)
+chktime_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
diff --git a/include/grub/datetime.h b/include/grub/datetime.h
new file mode 100755
index 0000000..b8f62b1
--- /dev/null
+++ b/include/grub/datetime.h
@@ -0,0 +1,28 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_DATETIME_HEADER
+#define KERNEL_DATETIME_HEADER	1
+
+#include <grub/types.h>
+
+/* Return date and time.  */
+grub_err_t grub_get_date (int *year, int *month, int *day);
+grub_err_t grub_get_time (int *hour, int *minute, int *second);
+
+#endif /* ! KERNEL_DATETIME_HEADER */
diff --git a/include/grub/i386/cmos.h b/include/grub/i386/cmos.h
new file mode 100755
index 0000000..4e3304c
--- /dev/null
+++ b/include/grub/i386/cmos.h
@@ -0,0 +1,61 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef	GRUB_CPU_CMOS_H
+#define	GRUB_CPU_CMOS_H	1
+
+#include <grub/types.h>
+#include <grub/i386/io.h>
+
+#define GRUB_CMOS_ADDR_REG	0x70
+#define GRUB_CMOS_DATA_REG	0x71
+
+#define GRUB_CMOS_INDEX_SECONDS		0
+#define GRUB_CMOS_INDEX_SECOND_ALARM	1
+#define GRUB_CMOS_INDEX_MINUTES		2
+#define GRUB_CMOS_INDEX_MINUTE_ALARM	3
+#define GRUB_CMOS_INDEX_HOURS		4
+#define GRUB_CMOS_INDEX_HOUR_ALARM	5
+#define GRUB_CMOS_INDEX_DAY_OF_WEEK	6
+#define GRUB_CMOS_INDEX_DAY_OF_MONTH	7
+#define GRUB_CMOS_INDEX_MONTH		8
+#define GRUB_CMOS_INDEX_YEAR		9
+
+#define GRUB_CMOS_INDEX_STATUS_A	0xA
+#define GRUB_CMOS_INDEX_STATUS_B	0xB
+#define GRUB_CMOS_INDEX_STATUS_C	0xC
+#define GRUB_CMOS_INDEX_STATUS_D	0xD
+
+#define GRUB_CMOS_STATUS_B_DAYLIGHT	1
+#define GRUB_CMOS_STATUS_B_24HOUR	2
+#define GRUB_CMOS_STATUS_B_BINARY	4
+
+static inline grub_uint8_t
+grub_bcd_to_num (grub_uint8_t a)
+{
+  return ((a >> 4) * 10 + (a & 0xF));
+}
+
+static inline grub_uint8_t
+grub_cmos_read (grub_uint8_t index)
+{
+  grub_outb (index, GRUB_CMOS_ADDR_REG);
+  return grub_inb (GRUB_CMOS_DATA_REG);
+}
+
+#endif /* GRUB_CPU_PCI_H */
diff --git a/kern/i386/datetime.c b/kern/i386/datetime.c
new file mode 100755
index 0000000..4170cab
--- /dev/null
+++ b/kern/i386/datetime.c
@@ -0,0 +1,118 @@
+/* kern/i386/datetime.c - x86 CMOS datetime access function.
+ *
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/datetime.h>
+#include <grub/i386/cmos.h>
+
+grub_err_t
+grub_get_date (int *year, int *month, int *day)
+{
+  int is_bcd;
+  grub_uint8_t value;
+
+  is_bcd = ! (grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B) &
+              GRUB_CMOS_STATUS_B_BINARY);
+
+  if (year)
+    {
+      value = grub_cmos_read (GRUB_CMOS_INDEX_YEAR);
+      if (is_bcd)
+        value = grub_bcd_to_num (value);
+
+      *year = value;
+      *year += (value < 80) ? 2000 : 1900;
+    }
+
+  if (month)
+    {
+      value = grub_cmos_read (GRUB_CMOS_INDEX_MONTH);
+      if (is_bcd)
+        value = grub_bcd_to_num (value);
+
+      *month = value;
+    }
+
+  if (day)
+    {
+      value = grub_cmos_read (GRUB_CMOS_INDEX_DAY_OF_MONTH);
+      if (is_bcd)
+        value = grub_bcd_to_num (value);
+
+      *day = value;
+    }
+
+  return 0;
+}
+
+grub_err_t
+grub_get_time (int *hour, int *minute, int *second)
+{
+  int is_bcd;
+  grub_uint8_t value;
+
+  is_bcd = ! (grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B) &
+              GRUB_CMOS_STATUS_B_BINARY);
+
+
+  if (hour)
+    {
+      int is_12hour;
+
+      is_12hour = ! (grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B) &
+                     GRUB_CMOS_STATUS_B_24HOUR);
+
+      value = grub_cmos_read (GRUB_CMOS_INDEX_HOURS);
+      if (is_12hour)
+        {
+          is_12hour = (value & 0x80);
+          value &= 0x7F;
+        }
+
+      if (is_bcd)
+        value = grub_bcd_to_num (value);
+
+      if (is_12hour)
+        value += 12;
+
+      *hour = value;
+    }
+
+  if (minute)
+    {
+      value = grub_cmos_read (GRUB_CMOS_INDEX_MINUTES);
+      if (is_bcd)
+        value = grub_bcd_to_num (value);
+
+      *minute = value;
+    }
+
+  if (second)
+    {
+      value = grub_cmos_read (GRUB_CMOS_INDEX_SECONDS);
+      if (is_bcd)
+        value = grub_bcd_to_num (value);
+
+      *second = value;
+    }
+
+  return 0;
+}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to