summaryrefslogtreecommitdiff
path: root/arch/x86/machine/pit.c
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2012-10-03 01:23:21 +0200
committerRichard Braun <rbraun@sceen.net>2012-10-03 01:26:08 +0200
commita4485f033c4ffa07955a45cad30424aedb89dff4 (patch)
tree136381bd711a9e6bd54b0c31fb347b35028911d1 /arch/x86/machine/pit.c
parent69504fc63720b4bf2677d6074285b82256bc9b83 (diff)
x86: new architecture
Merge 32-bit IA-32 (i386) and 64-bit AMD64 (amd64) code into one common architecture. The amd64 variant isn't functional yet.
Diffstat (limited to 'arch/x86/machine/pit.c')
-rw-r--r--arch/x86/machine/pit.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/arch/x86/machine/pit.c b/arch/x86/machine/pit.c
new file mode 100644
index 0000000..e5113ce
--- /dev/null
+++ b/arch/x86/machine/pit.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2012 Richard Braun.
+ *
+ * This program 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.
+ *
+ * This program 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <kern/init.h>
+#include <lib/assert.h>
+#include <machine/io.h>
+#include <machine/pit.h>
+
+/*
+ * I/O ports.
+ */
+#define PIT_PORT_COUNTER0 0x40
+#define PIT_PORT_MODE 0x43
+
+/*
+ * Mode control register bits.
+ */
+#define PIT_MODE_LATCH 0x00
+#define PIT_MODE_RATE_GEN 0x04
+#define PIT_MODE_RW_LSB 0x10
+#define PIT_MODE_RW_MSB 0x20
+
+/*
+ * Native timer frequency.
+ */
+#define PIT_FREQ 1193182
+
+/*
+ * Maximum value of a counter.
+ */
+#define PIT_MAX_COUNT 0xffff
+
+void __init
+pit_setup(void)
+{
+ io_write_byte(PIT_PORT_MODE, PIT_MODE_RATE_GEN | PIT_MODE_RW_LSB
+ | PIT_MODE_RW_MSB);
+ io_write_byte(PIT_PORT_COUNTER0, PIT_MAX_COUNT & 0xff);
+ io_write_byte(PIT_PORT_COUNTER0, PIT_MAX_COUNT >> 8);
+}
+
+static unsigned int
+pit_read(void)
+{
+ unsigned int low, high;
+
+ io_write_byte(PIT_PORT_MODE, PIT_MODE_LATCH);
+ low = io_read_byte(PIT_PORT_COUNTER0);
+ high = io_read_byte(PIT_PORT_COUNTER0);
+ return (high << 8) | low;
+}
+
+void
+pit_delay(unsigned long usecs)
+{
+ long total, prev, count, diff;
+
+ assert(usecs != 0);
+
+ /* TODO Avoid 64-bits conversion if result is known not to overflow */
+ total = (long)(((long long)usecs * PIT_FREQ + 999999) / 1000000);
+ prev = pit_read();
+
+ do {
+ count = pit_read();
+ diff = prev - count;
+ prev = count;
+
+ if (diff < 0)
+ diff += PIT_MAX_COUNT;
+
+ total -= diff;
+ } while (total > 0);
+}