/* * Copyright (c) 2005 Jakub Jermar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup ia64 * @{ */ /** @file */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define SKI_KBD_INR 0 static irq_t ski_kbd_irq; static devno_t ski_kbd_devno; chardev_t ski_console; chardev_t ski_uconsole; static bool kbd_disabled; /** Display character on debug console * * Use SSC (Simulator System Call) to * display character on debug console. * * @param d Character device. * @param ch Character to be printed. */ static void ski_putchar(chardev_t *d, const char ch, bool silent) { if (!silent) { asm volatile ( "mov r15 = %0\n" "mov r32 = %1\n" /* r32 is in0 */ "break 0x80000\n" /* modifies r8 */ : : "i" (SKI_PUTCHAR), "r" (ch) : "r15", "in0", "r8" ); if (ch == '\n') ski_putchar(d, '\r', false); } } /** Ask debug console if a key was pressed. * * Use SSC (Simulator System Call) to * get character from debug console. * * This call is non-blocking. * * @return ASCII code of pressed key or 0 if no key pressed. */ static int32_t ski_getchar(void) { uint64_t ch; asm volatile ( "mov r15 = %1\n" "break 0x80000;;\n" /* modifies r8 */ "mov %0 = r8;;\n" : "=r" (ch) : "i" (SKI_GETCHAR) : "r15", "r8" ); return (int32_t) ch; } /** * This is a blocking wrapper for ski_getchar(). * To be used when the kernel crashes. */ static char ski_getchar_blocking(chardev_t *d) { int ch; while(!(ch = ski_getchar())); if (ch == '\r') ch = '\n'; return (char) ch; } /** Ask keyboard if a key was pressed. */ static void poll_keyboard(void) { char ch; static char last; ipl_t ipl; ipl = interrupts_disable(); if (kbd_disabled) { interrupts_restore(ipl); return; } spinlock_lock(&ski_kbd_irq.lock); ch = ski_getchar(); if(ch == '\r') ch = '\n'; if (ch) { if (ski_kbd_irq.notif_cfg.notify && ski_kbd_irq.notif_cfg.answerbox) { chardev_push_character(&ski_uconsole, ch); /* XXX: send notification to userspace */ } else { chardev_push_character(&ski_console, ch); } last = ch; spinlock_unlock(&ski_kbd_irq.lock); interrupts_restore(ipl); return; } if (last) { if (ski_kbd_irq.notif_cfg.notify && ski_kbd_irq.notif_cfg.answerbox) { chardev_push_character(&ski_uconsole, 0); /* XXX: send notification to userspace */ } last = 0; } spinlock_unlock(&ski_kbd_irq.lock); interrupts_restore(ipl); } /* Called from getc(). */ static void ski_kbd_enable(chardev_t *d) { kbd_disabled = false; } /* Called from getc(). */ static void ski_kbd_disable(chardev_t *d) { kbd_disabled = true; } /** Decline to service hardware IRQ. * * This is only a virtual IRQ, so always decline. * * @return Always IRQ_DECLINE. */ static irq_ownership_t ski_kbd_claim(irq_t *irq) { return IRQ_DECLINE; } static chardev_operations_t ski_ops = { .resume = ski_kbd_enable, .suspend = ski_kbd_disable, .write = ski_putchar, .read = ski_getchar_blocking }; /** Initialize debug console * * Issue SSC (Simulator System Call) to * to open debug console. */ void ski_init_console(void) { asm volatile ( "mov r15 = %0\n" "break 0x80000\n" : : "i" (SKI_INIT_CONSOLE) : "r15", "r8" ); chardev_initialize("ski_console", &ski_console, &ski_ops); chardev_initialize("ski_uconsole", &ski_uconsole, &ski_ops); stdin = &ski_console; stdout = &ski_console; ski_kbd_devno = device_assign_devno(); irq_initialize(&ski_kbd_irq); ski_kbd_irq.inr = SKI_KBD_INR; ski_kbd_irq.devno = ski_kbd_devno; ski_kbd_irq.claim = ski_kbd_claim; irq_register(&ski_kbd_irq); sysinfo_set_item_val("kbd", NULL, true); sysinfo_set_item_val("kbd.inr", NULL, SKI_KBD_INR); sysinfo_set_item_val("kbd.devno", NULL, ski_kbd_devno); sysinfo_set_item_val("kbd.type", NULL, KBD_SKI); sysinfo_set_item_val("fb", NULL, false); } void ski_kbd_grab(void) { ipl_t ipl = interrupts_disable(); spinlock_lock(&ski_kbd_irq.lock); ski_kbd_irq.notif_cfg.notify = false; spinlock_unlock(&ski_kbd_irq.lock); interrupts_restore(ipl); } void ski_kbd_release(void) { ipl_t ipl = interrupts_disable(); spinlock_lock(&ski_kbd_irq.lock); if (ski_kbd_irq.notif_cfg.answerbox) ski_kbd_irq.notif_cfg.notify = true; spinlock_unlock(&ski_kbd_irq.lock); interrupts_restore(ipl); } #define POLL_INTERVAL 50000 /* 50 ms */ /** Kernel thread for polling keyboard. */ void kkbdpoll(void *arg) { while (1) { poll_keyboard(); thread_usleep(POLL_INTERVAL); } } /** @} */