diff options
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r-- | sys/arch/amd64/isa/i8042.c | 76 | ||||
-rw-r--r-- | sys/arch/amd64/isa/mc1468.c | 68 |
2 files changed, 124 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); |