summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/amd64/isa/i8042.c76
-rw-r--r--sys/arch/amd64/isa/mc1468.c68
-rw-r--r--sys/kern/init_main.c1
3 files changed, 125 insertions, 20 deletions
diff --git a/sys/arch/amd64/isa/i8042.c b/sys/arch/amd64/isa/i8042.c
index b32ff5b..eb8960c 100644
--- a/sys/arch/amd64/isa/i8042.c
+++ b/sys/arch/amd64/isa/i8042.c
@@ -39,6 +39,7 @@
#include <dev/acpi/acpi.h>
#include <dev/timer.h>
#include <dev/cons/cons.h>
+#include <dev/dmi/dmi.h>
#include <machine/cpu.h>
#include <machine/pio.h>
#include <machine/isa/i8042var.h>
@@ -157,6 +158,45 @@ i8042_write(uint16_t port, uint8_t val)
}
/*
+ * Read from an i8042 register.
+ *
+ * @port: I/O port
+ */
+static uint8_t
+i8042_read(uint16_t port)
+{
+ i8042_obuf_wait();
+ return inb(port);
+}
+
+/*
+ * Read the i8042 controller configuration
+ * byte.
+ */
+static uint8_t
+i8042_read_conf(void)
+{
+ uint8_t conf;
+
+ i8042_write(I8042_CMD, I8042_GET_CONFB);
+ i8042_obuf_wait();
+ conf = i8042_read(I8042_DATA);
+ return conf;
+}
+
+/*
+ * Write a new value to the i8042 controller
+ * configuration byte.
+ */
+static void
+i8042_write_conf(uint8_t conf)
+{
+ i8042_write(I8042_CMD, I8042_SET_CONFB);
+ i8042_ibuf_wait();
+ i8042_write(I8042_DATA, conf);
+}
+
+/*
* Send a data to a device
*
* @aux: If true, send to aux device (mouse)
@@ -204,25 +244,22 @@ static void
i8042_en_intr(void)
{
struct intr_hand ih;
+ uint8_t conf;
ih.func = i8042_kb_event;
ih.priority = IPL_BIO;
ih.irq = KB_IRQ;
intr_register("i8042-kb", &ih);
-}
-
-static void
-esckey_reboot(void)
-{
- syslock();
- kprintf(OMIT_TIMESTAMP "** Machine going down for a reboot\f");
-
- for (size_t i = 0; i < 3; ++i) {
- kprintf(OMIT_TIMESTAMP ".\f");
- tmr.msleep(1000);
- }
- cpu_reboot(0);
+ /*
+ * Enable the clock of PS/2 port 0 and tell
+ * the controller that we are accepting
+ * interrupts.
+ */
+ conf = i8042_read_conf();
+ conf &= ~I8042_PORT0_CLK;
+ conf |= I8042_PORT0_INTR;
+ i8042_write_conf(conf);
}
/*
@@ -239,10 +276,6 @@ i8042_kb_getc(uint8_t sc, char *chr)
bool release = ISSET(sc, BIT(7));
switch (sc) {
- /* Left alt [press] */
- case 0x38:
- esckey_reboot();
- break;
/* Caps lock [press] */
case 0x3A:
/*
@@ -350,6 +383,8 @@ i8042_sync_loop(void)
static int
i8042_init(void)
{
+ const char *prodver = NULL;
+
/* Try to request a general purpose timer */
if (req_timer(TIMER_GP, &tmr) != TMRR_SUCCESS) {
pr_error("failed to fetch general purpose timer\n");
@@ -378,9 +413,12 @@ i8042_init(void)
* etc... As of now, treat the i8042 like a fucking bomb
* if this bit is set.
*/
- if (strcmp(acpi_oemid(), "LENOVO") == 0) {
+ if ((prodver = dmi_prodver()) == NULL) {
+ prodver = "None";
+ }
+ if (strcmp(prodver, "ThinkPad T420s") == 0) {
quirks |= I8042_HOSTILE;
- pr_trace("lenovo device, assuming hostile\n");
+ pr_trace("ThinkPad T420s detected, assuming hostile\n");
pr_trace("disabling irq 1, polling as fallback\n");
spawn(&polltd, i8042_sync_loop, NULL, 0, NULL);
}
diff --git a/sys/arch/amd64/isa/mc1468.c b/sys/arch/amd64/isa/mc1468.c
index 531751b..bbaa3d1 100644
--- a/sys/arch/amd64/isa/mc1468.c
+++ b/sys/arch/amd64/isa/mc1468.c
@@ -50,6 +50,29 @@
static struct cdevsw mc1468_cdevsw;
+static uint8_t
+bin_dabble(uint8_t bin)
+{
+ uint8_t retval = 0;
+ uint8_t nibble;
+
+ for (int i = 7; i >= 0; --i) {
+ retval <<= 1;
+ if (bin & (1 << i)) {
+ retval |= 1;
+ }
+
+ for (int j = 0; j < 2; ++j) {
+ nibble = retval & (retval >> (4 * nibble)) & 0x0F;
+ if (nibble >= 5) {
+ retval += 0x03 << (4 * nibble);
+ }
+ }
+ }
+
+ return retval;
+}
+
/*
* Read a byte from an MC1468XX register.
*/
@@ -61,6 +84,16 @@ mc1468_read(uint8_t reg)
}
/*
+ * Write a byte to the MC1468XX register.
+ */
+static void
+mc1468_write(uint8_t reg, uint8_t val)
+{
+ outb(MC1468_REGSEL, reg);
+ outb(MC1468_DATA, val);
+}
+
+/*
* Returns true if the MC1468XX is updating
* its time registers.
*/
@@ -134,6 +167,23 @@ __mc1468_get_time(struct date *dp)
dp->hour = mc1468_read(0x04);
}
+/*
+ * Write a new time/date to the chip.
+ */
+static void
+mc1468_set_date(const struct date *dp)
+{
+ while (mc1468_updating()) {
+ md_pause();
+ }
+
+ mc1468_write(0x08, bin_dabble(dp->month));
+ mc1468_write(0x07, bin_dabble(dp->day));
+ mc1468_write(0x04, bin_dabble(dp->hour));
+ mc1468_write(0x02, bin_dabble(dp->min));
+ mc1468_write(0x00, bin_dabble(dp->sec));
+}
+
static int
mc1468_get_date(struct date *dp)
{
@@ -174,6 +224,7 @@ mc1468_get_date(struct date *dp)
date_cur.hour = ((date_cur.hour & 0x7F) + 12) % 24;
}
+ date_cur.year += 2000;
*dp = date_cur;
return 0;
}
@@ -194,6 +245,21 @@ mc1468_dev_read(dev_t dev, struct sio_txn *sio, int flags)
}
static int
+mc1468_dev_write(dev_t dev, struct sio_txn *sio, int flags)
+{
+ struct date d;
+ size_t len = sizeof(d);
+
+ if (sio->len > len) {
+ sio->len = len;
+ }
+
+ memcpy(&d, sio->buf, sio->len);
+ mc1468_set_date(&d);
+ return sio->len;
+}
+
+static int
mc1468_init(void)
{
char devname[] = "rtc";
@@ -209,7 +275,7 @@ mc1468_init(void)
static struct cdevsw mc1468_cdevsw = {
.read = mc1468_dev_read,
- .write = nowrite
+ .write = mc1468_dev_write,
};
DRIVER_EXPORT(mc1468_init);
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 81ddcb5..797319f 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -67,6 +67,7 @@ start_init(void)
char *argv[] = { _START_PATH, NULL, NULL };
char *envp[] = { NULL };
+ kprintf("starting init...\n");
execve_args.pathname = argv[0];
execve_args.argv = argv;
execve_args.envp = envp;