#include <stdlib.h> #include <wchar.h> #include <stdio.h> #include <ctype.h> #include <kernel/kernel.h> #include <kernel/sys.h> #include <kernel/thread.h> #include <kernel/handle.h> #include <errno.h> #include <kernel/debug.h> #include <kernel/driver.h> #include "keyboard.h" #include "british.h" /*! * \ingroup drivers * \defgroup keyboard AT/PS2 keyboard * @{ */ typedef struct Keyboard Keyboard; struct Keyboard { device_t dev; dword keys; wchar_t compose; dword *write, *read; dword buffer[128]; bool isps2; word port, ctrl; }; #define SET(var, bit, val) \ { \ if (val) \ var |= bit; \ else \ var &= ~bit; \ } void kbdHwWrite(Keyboard* ctx, word port, byte data) { dword timeout; byte stat; for (timeout = 500000L; timeout != 0; timeout--) { stat = in(ctx->ctrl); if ((stat & 0x02) == 0) break; } if (timeout != 0) out(port, data); } byte kbdHwRead(Keyboard* ctx) { unsigned long Timeout; byte Stat, Data; for (Timeout = 50000L; Timeout != 0; Timeout--) { Stat = in(ctx->ctrl); /* loop until 8042 output buffer full */ if ((Stat & 0x01) != 0) { Data = in(ctx->port); /* loop if parity error or receive timeout */ if((Stat & 0xC0) == 0) return Data; } } return -1; } byte kbdHwWriteRead(Keyboard* ctx, word port, byte data, const char* expect) { int RetVal; kbdHwWrite(ctx, port, data); for (; *expect; expect++) { RetVal = kbdHwRead(ctx); if ((byte) *expect != RetVal) { TRACE2("[keyboard] error: expected 0x%x, got 0x%x\n", (byte) *expect, RetVal); return RetVal; } } return 0; } dword kbdScancodeToKey(Keyboard* ctx, byte scancode) { static int keypad[RAW_NUM0 - RAW_NUM7 + 1] = { 7, 8, 9, -1, 4, 5, 6, -1, 1, 2, 3, 0 }; bool down = (scancode & 0x80) == 0; byte code = scancode & ~0x80; dword key = 0; byte temp; switch (code) { case RAW_LEFT_CTRL: case RAW_RIGHT_CTRL: SET(ctx->keys, KBD_BUCKY_CTRL, down); break; case RAW_LEFT_ALT: //case RAW_RIGHT_ALT: if (down && (ctx->keys & KBD_BUCKY_ALT) == 0) ctx->compose = 0; else if (!down && (ctx->keys & KBD_BUCKY_ALT)) key = ctx->compose; SET(ctx->keys, KBD_BUCKY_ALT, down); break; case RAW_LEFT_SHIFT: case RAW_RIGHT_SHIFT: SET(ctx->keys, KBD_BUCKY_SHIFT, down); break; case RAW_NUM_LOCK: if (!down) { ctx->keys ^= KBD_BUCKY_NUM; goto leds; } break; case RAW_CAPS_LOCK: if (!down) { ctx->keys ^= KBD_BUCKY_CAPS; goto leds; } break; case RAW_SCROLL_LOCK: if (!down) { ctx->keys ^= KBD_BUCKY_SCRL; goto leds; } break; leds: kbdHwWrite(ctx, ctx->port, KEYB_SET_LEDS); temp = 0; if (ctx->keys & KBD_BUCKY_SCRL) temp |= 1; if (ctx->keys & KBD_BUCKY_NUM) temp |= 2; if (ctx->keys & KBD_BUCKY_CAPS) temp |= 4; kbdHwWrite(ctx, ctx->port, temp); break; default: if (down) { if (code >= RAW_NUM7 && code <= RAW_NUM0 && code != 0x4a && code != 0x4e) { if (ctx->keys & KBD_BUCKY_ALT && keypad[code - RAW_NUM7] != -1) { ctx->compose *= 10; ctx->compose += keypad[code - RAW_NUM7]; //wprintf(L"pad = %d compose = %d\n", //keypad[code - RAW_NUM7], ctx->compose); } else if (ctx->keys & KBD_BUCKY_NUM) key = '0' + keypad[code - RAW_NUM7]; else key = keys[code]; } else if (ctx->keys & KBD_BUCKY_SHIFT) key = keys_shift[code]; else key = keys[code]; if (ctx->keys & KBD_BUCKY_CAPS) { if (iswupper(key)) key = towlower(key); else if (iswlower(key)) key = towupper(key); } } } return key | ctx->keys; } size_t kbdRead(Keyboard* ctx, void* buffer, size_t length) { dword ch, *buf = (dword*) buffer; size_t read = 0; while (length > 0) { if (ctx->read == ctx->write) return read; ch = *ctx->read; ctx->read++; if (ctx->read >= ctx->buffer + countof(ctx->buffer)) ctx->read = ctx->buffer; *buf = ch; buf++; length -= sizeof(dword); read += sizeof(dword); } return read; } void kbdDoRequests(Keyboard* ctx) { request_t *req, *next; size_t read; dword key; while (ctx->dev.req_first && (read = kbdRead(ctx, &key, sizeof(key)))) { for (req = ctx->dev.req_first; req; req = next) { /*wprintf(L"read = %d req = %p ", read, req); wprintf(L"buffer = %p size = %d\n", req->params.read.buffer, req->params.read.length); _cputws(L"Writing buffer...");*/ ((dword*) req->params.read.buffer)[req->params.read.length / sizeof(dword)] = key; //_cputws(L"done\nUpdating length..."); req->params.read.length += read; next = req->next; if (req->params.read.length >= req->user_length) devFinishRequest(&ctx->dev, req); //else //_cputws(L"more to do\n"); } } } void kbdKey(Keyboard* ctx, byte scancode) { dword key; if (ctx->write >= ctx->read) { key = kbdScancodeToKey(ctx, scancode); if (key == (KBD_BUCKY_CTRL | KBD_BUCKY_ALT | KEY_DEL)) keShutdown(SHUTDOWN_REBOOT); else if (key == KEY_F11) if (dbgInvoke(thrCurrent(), thrContext(thrCurrent()), 0)) return; if (key) { *ctx->write = key; ctx->write++; if (ctx->write >= ctx->buffer + countof(ctx->buffer)) ctx->write = ctx->buffer; //wprintf(L"read = %d, write = %d\n", ctx->read - ctx->buffer, ctx->write - ctx->buffer); //Read(&key, sizeof(key)); //wprintf(L"%c", key); } kbdDoRequests(ctx); } } bool kbdRequest(device_t* dev, request_t* req) { Keyboard* ctx = (Keyboard*) dev; TRACE2("[%c%c]", req->code / 256, req->code % 256); switch (req->code) { case DEV_READ: devStartRequest(dev, req); req->params.read.length = 0; kbdDoRequests(ctx); return true; case DEV_OPEN: case DEV_CLOSE: hndSignal(req->event, true); return true; case DEV_ISR: kbdKey(ctx, kbdHwRead(ctx)); return true; case CHR_GETSIZE: *((size_t*) req->params.buffered.buffer) = ctx->write - ctx->read; hndSignal(req->event, true); return true; } req->result = ENOTIMPL; return false; } Keyboard* INIT_CODE kbdInit(driver_t* drv, device_config_t *cfg) { Keyboard* ctx; dword i; word port, ctrl; device_t* kdebug; byte status; ctx = (Keyboard*) hndAlloc(sizeof(Keyboard), NULL); if (cfg) i = devFindResource(cfg, dresIo, 0); else i = -1; if (i == (dword) -1) port = KEYB_PORT; else port = cfg->resources[i].u.io.base; if (cfg) i = devFindResource(cfg, dresIo, 1); else i = -1; if (i == (dword) -1) ctrl = KEYB_CTRL; else ctrl = cfg->resources[i].u.io.base; ctx->dev.driver = drv; ctx->dev.request = kbdRequest; ctx->dev.config = cfg; ctx->dev.req_first = ctx->dev.req_last = NULL; ctx->keys = 0; ctx->write = ctx->read = ctx->buffer; ctx->port = port; ctx->ctrl = ctrl; TRACE2("keyboard: port = %x ctrl = %x\n", port, ctrl); /* * The kernel debugger may have registered our IRQ1, which would make a * mess of keyboard initialization. */ kdebug = devOpen(L"debugger", NULL); devRegisterIrq(kdebug, 1, false); devClose(kdebug); #if 0 out(port, 0xff); /*reset keyboard */ do { status = in(ctrl); } while (status & 0x02); out(ctrl, 0xAA); /*selftest */ in(port); out(ctrl, 0xAB); /*interface selftest */ in(port); out(ctrl, 0xAE); /*enable keyboard */ out(port, 0xff); /*reset keyboard */ in(port); in(port); out(ctrl, 0xAD); /*disable keyboard */ out(ctrl, 0x60); out(port, 0x01 | 0x04 | 0x20 | 0x40); out(ctrl, 0xAE); /*enable keyboard */ #else /* Reset keyboard and disable scanning until further down */ TRACE0("Disable..."); kbdHwWriteRead(ctx, ctx->port, KEYB_RESET_DISABLE, KEYB_ACK); /* Set keyboard controller flags: interrupts for keyboard & aux port SYS bit (?) */ TRACE0("done\nFlags..."); kbdHwWrite(ctx, ctx->ctrl, KCTRL_WRITE_CMD_BYTE); kbdHwWrite(ctx, ctx->port, KCTRL_IRQ1 | KCTRL_SYS | KCTRL_IRQ12); TRACE0("done\nIdentify..."); kbdHwWriteRead(ctx, ctx->port, KEYB_IDENTIFY, KEYB_ACK); if (kbdHwRead(ctx) == 0xAB && kbdHwRead(ctx) == 0x83) { TRACE0("[keyboard] PS/2 keyboard detected\n"); /* Program desired scancode set, expect 0xFA (ACK)... */ kbdHwWriteRead(ctx, ctx->port, KEYB_SET_SCANCODE_SET, KEYB_ACK); /* ...send scancode set value, expect 0xFA (ACK) */ kbdHwWriteRead(ctx, ctx->port, 1, KEYB_ACK); /* make all keys typematic (auto-repeat) and make-break. This may work only with scancode set 3, I'm not sure. Expect 0xFA (ACK) */ kbdHwWriteRead(ctx, ctx->port, KEYB_ALL_TYPM_MAKE_BRK, KEYB_ACK); ctx->isps2 = true; } else { /* Argh... bloody bochs */ TRACE0("[keyboard] AT keyboard detected\n"); ctx->isps2 = false; } /* Set typematic delay as short as possible; Repeat as fast as possible, expect ACK... */ TRACE0("Typematic..."); kbdHwWriteRead(ctx, ctx->port, KEYB_SET_TYPEMATIC, KEYB_ACK); /* ...typematic control byte (0 corresponds to MODE CON RATE=30 DELAY=1), expect 0xFA (ACK) */ kbdHwWriteRead(ctx, ctx->port, 0, KEYB_ACK); /* Enable keyboard, expect 0xFA (ACK) */ TRACE0("done\nEnable..."); kbdHwWriteRead(ctx, ctx->port, KEYB_ENABLE, KEYB_ACK); #endif TRACE0("done\nIRQ..."); devRegisterIrq(&ctx->dev, 1, true); TRACE0("done\n"); return ctx; } device_t* kbdAddDevice(driver_t* drv, const wchar_t* name, device_config_t* cfg) { return (device_t*) kbdInit(drv, cfg); } bool STDCALL INIT_CODE drvInit(driver_t* drv) { drv->add_device = kbdAddDevice; //devRegister(L"keyboard", kbdAddDevice(drv, L"keyboard", NULL), NULL); return true; } //@}