/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Miniature keyboard driver for bootstrap. This allows keyboard
* support to continue after we take over interrupts and disable
* BIOS keyboard support.
*/
#include <sys/archsystm.h>
#include <sys/boot_console.h>
#include "boot_keyboard_table.h"
#if defined(_BOOT)
#include "dboot/dboot_asm.h"
#include "dboot/dboot_xboot.h"
#endif /* _BOOT */
/*
* Definitions for BIOS keyboard state. We use BIOS's variable to store
* state, ensuring that we stay in sync with it.
*/
/*
* Device memory addresses
*
* In dboot under the hypervisor we don't have any memory mappings
* for the first meg of low memory so we can't access devices there.
* Intead we've mapped the device memory that we need to access into
* a local variable within dboot so we can access the device memory
* there.
*/
extern unsigned short *kb_status;
#else /* __xpv && _BOOT */
/* Device memory addresses */
#endif /* __xpv && _BOOT */
/*
* Keyboard controller registers
*/
/*
* Keyboard controller status register bits
*/
/*
* Keyboard controller commands
*/
/*
* Keyboard commands
*/
#ifndef ASSERT
#define ASSERT(x)
#endif
#define peek8(p) (*(p))
static struct {
int led_commanded;
/*
* Possible values:
*
* -1 Nothing pending
* 0x000-0x0ff Pending byte
* 0x100-0x1ff Needs leading zero, then low byte next.
*
* Others undefined.
*/
int pending;
} kb = {
B_FALSE, /* initialized? */
KB_LED_IDLE, /* LED command state */
-1, /* commanded LEDs - force refresh */
-1, /* pending */
};
static int kb_translate(unsigned char code);
static void kb_update_leds(void);
static uchar_t kb_calculate_leds(void);
int
kb_getchar(void)
{
int ret;
while (!kb_ischar())
/* LOOP */;
/*
* kb_ischar() doesn't succeed without leaving kb.pending
* set.
*/
ret = 0;
} else {
}
return (ret);
}
int
kb_ischar(void)
{
unsigned char buffer_stat;
unsigned char code;
unsigned char leds;
if (!kb.initialized) {
kb_init();
}
return (1);
for (;;) {
if (buffer_stat == 0xff)
return (0);
switch (buffer_stat) {
case 0:
case I8042_STAT_AUXBF:
return (0);
case (I8042_STAT_OUTBF | I8042_STAT_AUXBF):
/*
* Discard unwanted mouse data.
*/
(void) inb(I8042_DATA);
continue;
}
switch (code) {
/*
* case 0xAA:
*
* You might think that we should ignore 0xAA on the
* grounds that it is the BAT Complete response and will
* it is ambiguous - this is also the code for a break
* of the left shift key. Since it will be harmless for
* us to "spuriously" process a break of Left Shift,
* we just let the normal code handle it. Perhaps we
* should take a hint and refresh the LEDs, but I
* refuse to get very worried about hot-plug issues
* in this mini-driver.
*/
case 0xFA:
case KB_LED_IDLE:
/*
* Spurious. Oh well, ignore it.
*/
break;
case KB_LED_COMMAND_SENT:
leds = kb_calculate_leds();
break;
case KB_LED_VALUE_SENT:
/*
* Check for changes made while we were
* working on the last change.
*/
break;
}
continue;
case 0xE0:
case 0xE1:
/*
* These are used to distinguish the keys added on
* the AT-101 keyboard from the original 84 keys.
* We don't care, and the codes are carefully arranged
* so that we don't have to.
*/
continue;
default:
if (code & 0x80) {
/* Release */
code &= 0x7f;
case KBTYPE_SPEC_LSHIFT:
break;
case KBTYPE_SPEC_RSHIFT:
break;
case KBTYPE_SPEC_CTRL:
break;
case KBTYPE_SPEC_ALT:
break;
case KBTYPE_SPEC_CAPS_LOCK:
break;
case KBTYPE_SPEC_NUM_LOCK:
break;
case KBTYPE_SPEC_SCROLL_LOCK:
break;
default:
/*
* Ignore all other releases.
*/
break;
}
} else {
/* Press */
return (1);
}
}
}
}
}
int
{
struct keyboard_translate *k;
unsigned short action;
k = keyboard_translate + code;
switch (k->normal & 0xFF00) {
case KBTYPE_NUMPAD:
break;
case KBTYPE_ALPHA:
break;
}
else if (shifted)
else
switch (action & 0xFF00) {
case KBTYPE_NORMAL:
case KBTYPE_ALPHA:
return (action & 0xFF);
case KBTYPE_NUMPAD:
case KBTYPE_FUNC:
case KBTYPE_SPEC:
break;
default:
/*
* Bad entry.
*/
ASSERT(0);
return (-1);
}
/*
* Handle special keys, mostly shifts.
*/
switch (action) {
case KBTYPE_SPEC_NOP:
case KBTYPE_SPEC_UNDEF:
break;
case KBTYPE_SPEC_LSHIFT:
break;
case KBTYPE_SPEC_RSHIFT:
break;
case KBTYPE_SPEC_CTRL:
break;
case KBTYPE_SPEC_ALT:
break;
case KBTYPE_SPEC_CAPS_LOCK:
}
break;
case KBTYPE_SPEC_NUM_LOCK:
}
break;
case KBTYPE_SPEC_SCROLL_LOCK:
}
break;
case KBTYPE_SPEC_MAYBE_REBOOT:
#if 0 /* Solaris doesn't reboot via ctrl-alt-del */
reset();
/* NOTREACHED */
}
#endif
break;
default:
/*
* Bad entry
*/
ASSERT(0);
break;
}
/*
* Consider updating the LEDs. This does nothing if nothing
* needs to be done.
*/
return (-1);
}
void
{
int retries;
for (retries = 0;
retries++)
/* LOOP */;
}
void
kb_update_leds(void)
{
/*
* The state machine will take care of any additional
* changes that are necessary.
*/
return;
}
} else {
}
}
void
kb_init(void)
{
/*
* that the bios, grub, and any optional hypervisor have left
* the keyboard in a sane and usable state. Messing with it now
* could result it making it unusuable, which would break early
* kmdb debugging support. Note that we don't actually need to
* in protected mode and we're not compeating with the bios for
* keyboard access. Also, we don't need to disable the mouse
* port since our polled input routine will just drop any mouse
* data that it recieves.
*/
}
unsigned char
kb_calculate_leds(void)
{
int res;
res = 0;
res |= KB_LED_CAPS_LOCK;
res |= KB_LED_NUM_LOCK;
return ((char)res);
}