[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH Hurd] Add rtc translator and RTC CMOS driver
From: |
Zhaoming Luo |
Subject: |
[PATCH Hurd] Add rtc translator and RTC CMOS driver |
Date: |
Mon, 2 Dec 2024 10:34:15 +0800 |
A translator will be created as /hurd/rtc-cmos, users can create a
/dev/rtc device using the following command:
```
sudo settrans -c /dev/rtc /hurd/rtc-cmos
```
* Makefile: add rtc-cmos server into the compile chain
* hurd/pioctl.defs: new file. Interfaces for rtc ioctl operations
* hurd/rtc.h: new file. Interfaces for rtc device
* rtc/Makefile: new file. Makefile for rtc server
* rtc/main.c: new file. Initialisation for rtc translator
* rtc/mig-mutate.h: new file. Type translation for rtc server
* rtc/rtc-cmos_pioctl-ops.c: new file. The rtc-cmos server side implementation
---
Makefile | 3 +-
hurd/pioctl.defs | 51 ++++++++
hurd/rtc.h | 45 +++++++
rtc/Makefile | 39 ++++++
rtc/main.c | 104 +++++++++++++++
rtc/mig-mutate.h | 24 ++++
rtc/rtc-cmos_pioctl-ops.c | 262 ++++++++++++++++++++++++++++++++++++++
7 files changed, 527 insertions(+), 1 deletion(-)
create mode 100644 hurd/pioctl.defs
create mode 100644 hurd/rtc.h
create mode 100644 rtc/Makefile
create mode 100644 rtc/main.c
create mode 100644 rtc/mig-mutate.h
create mode 100644 rtc/rtc-cmos_pioctl-ops.c
diff --git a/Makefile b/Makefile
index 4d848221..9d9e33c3 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,8 @@ prog-subdirs = auth proc exec term \
init \
devnode \
eth-multiplexer \
- shutdown
+ shutdown \
+ rtc
ifeq ($(HAVE_LIBRUMP),yes)
prog-subdirs += rumpdisk
diff --git a/hurd/pioctl.defs b/hurd/pioctl.defs
new file mode 100644
index 00000000..f6b7b3a6
--- /dev/null
+++ b/hurd/pioctl.defs
@@ -0,0 +1,51 @@
+/* Definitions for /dev/rtc ioctls
+
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Ioctl group 'p'; the subsystem is derived from calculations in
+ hurd/ioctls.defs. */
+subsystem pioctl 140000;
+
+#include <hurd/ioctl_types.defs>
+
+import <hurd/rtc.h>;
+
+#ifdef PIOCTL_IMPORTS
+PIOCTL_IMPORTS
+#endif
+
+INTR_INTERFACE
+
+/* This is the arg for a struct rtc_time as specified by the
+ definition of _IOT_rtc_time in $(hurd)/hurd/rtc.h. */
+type rtc_time_t = struct[9] of int;
+
+skip; skip; skip; skip; /* 0 1 2 3 */
+skip; skip; skip; skip; /* 4 5 6 7 */
+skip; /* 8 */
+
+/* 9 RTC_RD_TIME */
+routine pioctl_rtc_rd_time (
+ reqport: io_t;
+ out tm: rtc_time_t);
+
+/* 10 RTC_SET_TIME */
+routine pioctl_rtc_set_time (
+ reqport: io_t;
+ tm: rtc_time_t);
diff --git a/hurd/rtc.h b/hurd/rtc.h
new file mode 100644
index 00000000..12ca7531
--- /dev/null
+++ b/hurd/rtc.h
@@ -0,0 +1,45 @@
+/* GNU Hurd RTC interface
+
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _RTC_H
+#define _RTC_H 1
+
+#include <hurd/ioctl.h>
+
+struct rtc_time
+{
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+typedef struct rtc_time rtc_time_t;
+
+#define _IOT_rtc_time _IOT(_IOTS(int),9,0,0,0,0)
+
+#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time. */
+#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time. */
+
+#endif /* rtc.h */
diff --git a/rtc/Makefile b/rtc/Makefile
new file mode 100644
index 00000000..ce32de4c
--- /dev/null
+++ b/rtc/Makefile
@@ -0,0 +1,39 @@
+# Makefile for rtc server
+#
+# Copyright (C) 2024 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd 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 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+dir := rtc
+makemode := server
+
+SRCS = main.c rtc-cmos_pioctl-ops.c
+MIGSRCS = pioctlServer.c
+
+OBJS = main.o pioctlServer.o rtc-cmos_pioctl-ops.o
+
+HURDLIBS = trivfs shouldbeinlibc ports
+
+target = rtc
+
+include ../Makeconf
+
+MIGCOMSFLAGS += -prefix rtc_
+mig-sheader-prefix = rtc_
+pioctl-MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+
+rtc_pioctl_S.h pioctlServer.c: mig-mutate.h
diff --git a/rtc/main.c b/rtc/main.c
new file mode 100644
index 00000000..19bf73b9
--- /dev/null
+++ b/rtc/main.c
@@ -0,0 +1,104 @@
+/* A translator for accessing rtc
+
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <version.h>
+
+#include <error.h>
+#include <stdbool.h>
+#include <argp.h>
+#include <hurd/trivfs.h>
+#include <hurd/ports.h>
+#include <hurd/rtc.h>
+#include <sys/io.h>
+
+#include "rtc_pioctl_S.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rtc);
+
+static struct trivfs_control *rtccntl;
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = O_READ | O_WRITE;
+
+static const struct argp rtc_argp =
+{ NULL, NULL, NULL, "Real-Time Clock device" };
+
+static int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ mig_routine_t routine;
+ if ((routine = rtc_pioctl_server_routine (inp)) ||
+ (routine = NULL, trivfs_demuxer (inp, outp)))
+ {
+ if (routine)
+ (*routine) (inp, outp);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+
+ argp_parse (&rtc_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Request for permission to do i/o on port numbers 0x70 and 0x71 for
+ accessing RTC registers. Do this before replying to our parent, so
+ we don't end up saying "I'm ready!" and then immediately exit with
+ an error. */
+ err = ioperm (0x70, 2, true);
+ if (err)
+ error (1, err, "Request IO permission failed");
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, O_NORW, NULL, NULL, NULL, NULL, &rtccntl);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (1, err, "trivfs_startup failed");
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (rtccntl->pi.bucket, demuxer,
+ 2 * 60 * 1000);
+
+ return 0;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ exit (EXIT_SUCCESS);
+}
diff --git a/rtc/mig-mutate.h b/rtc/mig-mutate.h
new file mode 100644
index 00000000..ddead5be
--- /dev/null
+++ b/rtc/mig-mutate.h
@@ -0,0 +1,24 @@
+/* Type translation for rtc operations
+
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#define IO_INTRAN trivfs_protid_t trivfs_begin_using_protid (io_t)
+#define IO_INTRAN_PAYLOAD trivfs_protid_t trivfs_begin_using_protid_payload
+#define IO_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
+#define PIOCTL_IMPORTS import "../libtrivfs/mig-decls.h";
diff --git a/rtc/rtc-cmos_pioctl-ops.c b/rtc/rtc-cmos_pioctl-ops.c
new file mode 100644
index 00000000..e8058d11
--- /dev/null
+++ b/rtc/rtc-cmos_pioctl-ops.c
@@ -0,0 +1,262 @@
+/* Server side implementation for rtc-cmos
+
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* This implementation is largely based on sys-utils/hwclock-cmos.c from
+ util-linux. */
+
+/* A struct tm has int fields (it is defined in POSIX)
+ tm_sec 0-59, 60 or 61 only for leap seconds
+ tm_min 0-59
+ tm_hour 0-23
+ tm_mday 1-31
+ tm_mon 0-11
+ tm_year number of years since 1900
+ tm_wday 0-6, 0=Sunday
+ tm_yday 0-365
+ tm_isdst >0: yes, 0: no, <0: unknown */
+
+#include "rtc_pioctl_S.h"
+#include <hurd/rtc.h>
+#include <hurd/hurd_types.h>
+#include <sys/io.h>
+#include <stdbool.h>
+
+/* Conversions to and from RTC internal format. */
+#define BCD_TO_BIN(val) ((val)=((val)&15) + (((val)>>4)&15)*10 + \
+ ((val)>>8)*100)
+#define BIN_TO_BCD(val) ((val)=(((val)/100)<<8) + \
+ ((((val)/10)%10)<<4) + (val)%10)
+
+/* POSIX uses 1900 as epoch for a struct tm, and 1970 for a time_t. */
+#define TM_EPOCH 1900
+
+#define CLOCK_CTL_ADDR 0x70
+#define CLOCK_DATA_ADDR 0x71
+
+#define is_leap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+static const int mon_yday[2][13] =
+{
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+
+static inline unsigned char
+cmos_read (unsigned char reg)
+{
+ outb_p (reg, CLOCK_CTL_ADDR);
+ return inb_p (CLOCK_DATA_ADDR);
+}
+
+static inline void
+cmos_write (unsigned char reg, unsigned char val)
+{
+ outb_p (reg, CLOCK_CTL_ADDR);
+ outb_p (val, CLOCK_DATA_ADDR);
+}
+
+static inline int
+cmos_clock_busy (void)
+{
+ /* Poll bit 7 (UIP) of Control Register A. */
+ return (cmos_read (10) & 0x80);
+}
+
+/* Calculate day of year based on month, day of month, and year. The value
+ it returns is in binary format. */
+static int
+calculate_yday (const struct rtc_time *tm)
+{
+ return mon_yday[is_leap (tm->tm_year)][tm->tm_mon] + tm->tm_mday - 1;
+}
+
+/* 9 RTC_RD_TIME -- Read RTC time. */
+kern_return_t
+rtc_S_pioctl_rtc_rd_time (struct trivfs_protid *cred, struct rtc_time *tm)
+{
+ unsigned char status = 0;
+ unsigned char pmbit = 0;
+ int time_passed_in_milliseconds = 0;
+ bool read_rtc_successfully = false;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & O_READ))
+ return EBADF;
+
+ /* When we wait for 100 ms (it takes too long), we exit with error. */
+ while (time_passed_in_milliseconds < 100)
+ {
+ if (!cmos_clock_busy ())
+ {
+ tm->tm_sec = cmos_read (0);
+ tm->tm_min = cmos_read (2);
+ tm->tm_hour = cmos_read (4);
+ tm->tm_wday = cmos_read (6);
+ tm->tm_mday = cmos_read (7);
+ tm->tm_mon = cmos_read (8);
+ tm->tm_year = cmos_read (9);
+ status = cmos_read (11);
+ /* Unless the clock changed while we were reading, consider this
+ a good clock read. */
+ if (tm->tm_sec == cmos_read (0))
+ {
+ read_rtc_successfully = true;
+ break;
+ }
+ }
+ usleep (1000);
+ time_passed_in_milliseconds++;
+ }
+
+ if (!read_rtc_successfully)
+ return EBUSY;
+
+ /* If the data we just read is in BCD format, convert it to binary
+ format. */
+ if (!(status & 0x04))
+ {
+ BCD_TO_BIN (tm->tm_sec);
+ BCD_TO_BIN (tm->tm_min);
+ pmbit = (tm->tm_hour & 0x80);
+ tm->tm_hour &= 0x7f;
+ BCD_TO_BIN (tm->tm_hour);
+ BCD_TO_BIN (tm->tm_wday);
+ BCD_TO_BIN (tm->tm_mday);
+ BCD_TO_BIN (tm->tm_mon);
+ BCD_TO_BIN (tm->tm_year);
+ }
+
+ /* We don't use the century byte of the Hardware Clock since we
+ don't know its address (usually 50 or 55). Here, we follow the
+ advice of the X/Open Base Working Group: "if century is not
+ specified, then values in the range [69-99] refer to years in the
+ twentieth century (1969 to 1999 inclusive), and values in the
+ range [00-68] refer to years in the twenty-first century (2000 to
+ 2068 inclusive)". */
+ tm->tm_wday -= 1;
+ tm->tm_mon -= 1;
+ if (tm->tm_year < 69)
+ tm->tm_year += 100;
+
+ /* Calculate day of year. */
+ tm->tm_yday = calculate_yday (tm);
+
+ if (pmbit)
+ {
+ tm->tm_hour += 12;
+ if (tm->tm_hour == 24)
+ tm->tm_hour = 0;
+ }
+
+ /* We don't know whether it's daylight. */
+ tm->tm_isdst = -1;
+
+ return KERN_SUCCESS;
+}
+
+/* 10 RTC_SET_TIME -- Set RTC time. */
+kern_return_t
+rtc_S_pioctl_rtc_set_time (struct trivfs_protid *cred, struct rtc_time tm)
+{
+ unsigned char save_control, save_freq_select, pmbit = 0;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & O_WRITE))
+ return EBADF;
+
+ /* CMOS byte 10 (clock status register A) has 3 bitfields:
+ bit 7: 1 if data invalid, update in progress (read-only bit)
+ (this is raised 224 us before the actual update starts)
+ 6-4 select base frequency
+ 010: 32768 Hz time base (default)
+ 111: reset
+ all other combinations are manufacturer-dependent
+ (e.g.: DS1287: 010 = start oscillator, anything else = stop)
+ 3-0 rate selection bits for interrupt
+ 0000 none (may stop RTC)
+ 0001, 0010 give same frequency as 1000, 1001
+ 0011 122 microseconds (minimum, 8192 Hz)
+ .... each increase by 1 halves the frequency, doubles the period
+ 1111 500 milliseconds (maximum, 2 Hz)
+ 0110 976.562 microseconds (default 1024 Hz). */
+
+ /* Tell the clock it's being set. */
+ save_control = cmos_read (11);
+ cmos_write (11, (save_control | 0x80));
+ /* Stop and reset prescaler. */
+ save_freq_select = cmos_read (10);
+ cmos_write (10, (save_freq_select | 0x70));
+
+ tm.tm_year %= 100;
+ tm.tm_mon += 1;
+ tm.tm_wday += 1;
+
+ /* 12hr mode; the default is 24hr mode. */
+ if (!(save_control & 0x02))
+ {
+ if (tm.tm_hour == 0)
+ tm.tm_hour = 24;
+ if (tm.tm_hour > 12)
+ {
+ tm.tm_hour -= 12;
+ pmbit = 0x80;
+ }
+ }
+
+ /* BCD mode - the default. */
+ if (!(save_control & 0x04))
+ {
+ BIN_TO_BCD (tm.tm_sec);
+ BIN_TO_BCD (tm.tm_min);
+ BIN_TO_BCD (tm.tm_hour);
+ BIN_TO_BCD (tm.tm_wday);
+ BIN_TO_BCD (tm.tm_mday);
+ BIN_TO_BCD (tm.tm_mon);
+ BIN_TO_BCD (tm.tm_year);
+ }
+
+ cmos_write (0, tm.tm_sec);
+ cmos_write (2, tm.tm_min);
+ cmos_write (4, tm.tm_hour | pmbit);
+ cmos_write (6, tm.tm_wday);
+ cmos_write (7, tm.tm_mday);
+ cmos_write (8, tm.tm_mon);
+ cmos_write (9, tm.tm_year);
+
+ /* The kernel sources, linux/arch/i386/kernel/time.c, have the
+ following comment:
+
+ The following flags have to be released exactly in this order,
+ otherwise the DS12887 (popular MC146818A clone with integrated
+ battery and quartz) will not reset the oscillator and will not
+ update precisely 500 ms later. You won't find this mentioned in
+ the Dallas Semiconductor data sheets, but who believes data
+ sheets anyway ... -- Markus Kuhn. */
+ cmos_write (11, save_control);
+ cmos_write (10, save_freq_select);
+
+ return KERN_SUCCESS;
+}
--
2.45.2
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH Hurd] Add rtc translator and RTC CMOS driver,
Zhaoming Luo <=