/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* or http://www.opensolaris.org/os/licensing.
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Generic Keyboard Support: Polled I/O support for kbtrans-supported keyboards.
*/
#define KEYMAP_SIZE_VARIABLE
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/kbd.h>
#include <sys/kbio.h>
#include <sys/vuid_event.h>
#include <sys/consdev.h>
#include <sys/kbtrans.h>
#include "kbtrans_lower.h"
#include "kbtrans_streams.h"
/*
* Internal Function Prototypes
*/
static void kbtrans_polled_pressed(struct kbtrans *, uint_t, kbtrans_key_t,
uint_t);
static void kbtrans_polled_released(struct kbtrans *, kbtrans_key_t);
static void kbtrans_polled_setled(struct kbtrans *);
static void kbtrans_polled_setup_repeat(struct kbtrans *, uint_t,
kbtrans_key_t);
static void kbtrans_polled_cancel_repeat(struct kbtrans *);
/*
* Functions to be called when a key is translated during polled
* mode
*/
struct keyboard_callback kbtrans_polled_callbacks = {
NULL, /* keypressed_raw */
NULL, /* keyreleased_raw */
kbtrans_polled_pressed, /* keypressed */
kbtrans_polled_released, /* keyreleased */
kbtrans_polled_setup_repeat, /* setup_repeat */
kbtrans_polled_cancel_repeat, /* cancel_repeat */
kbtrans_polled_setled, /* setled */
};
/*
* kbtrans_ischar:
* Return B_TRUE if character is pending, else return B_FALSE
*/
boolean_t
kbtrans_ischar(struct kbtrans *upper)
{
struct kbtrans_callbacks *cb;
struct kbtrans_hardware *hw;
kbtrans_key_t key;
enum keystate state;
/*
* If we've still got input pending, say so.
*/
if (*upper->kbtrans_polled_pending_chars != '\0') {
return (B_TRUE);
}
/*
* Reset to an empty buffer.
*/
upper->kbtrans_polled_buf[0] = '\0';
upper->kbtrans_polled_pending_chars = upper->kbtrans_polled_buf;
cb = upper->kbtrans_streams_hw_callbacks;
hw = upper->kbtrans_streams_hw;
/*
* Process scancodes until either we have input ready
* or we run out of scancodes.
*/
while (cb->kbtrans_polled_keycheck(hw, &key, &state)) {
kbtrans_processkey(&upper->kbtrans_lower,
&kbtrans_polled_callbacks, key, state);
/*
* If that generated any input, we're ready.
*/
if (*upper->kbtrans_polled_pending_chars != '\0') {
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* kbtrans_getchar:
* Return a character
*/
int
kbtrans_getchar(struct kbtrans *upper)
{
while (!kbtrans_ischar(upper))
/* LOOP */;
return (*upper->kbtrans_polled_pending_chars++);
}
void
kbtrans_polled_putcode(struct kbtrans *upper, char code)
{
int i;
/*
* NB: KBTRANS_POLLED_BUF_SIZE is one smaller than
* the size of the buffer, to allow for a trailing
* null.
*/
for (i = 0; i < KBTRANS_POLLED_BUF_SIZE; i++) {
if (upper->kbtrans_polled_buf[i] == '\0') {
upper->kbtrans_polled_buf[i] = code;
upper->kbtrans_polled_buf[i+1] = '\0';
return;
}
}
DPRINTF(PRINT_L2, PRINT_MASK_PACKET,
(upper, "kbtrans_polled_pressed: "
"buffer overflow, character 0x%x discarded\n", code));
/*
* Didn't fit, throw it on the floor.
*/
}
/*
* kbtrans_polled_pressed:
* This function is called when we are in polled mode and a key is
* pressed. The key is put into the kbtrans_polled_buf so that it
* can be picked up later by kbtrans_ischar()
*/
/*ARGSUSED2*/
static void
kbtrans_polled_pressed(
struct kbtrans *upper,
uint_t entrytype,
kbtrans_key_t key,
uint_t entry)
{
struct kbtrans_lower *lower = &upper->kbtrans_lower;
register char *cp;
/*
* Based on the type of key, we may need to do some ASCII
* specific post processing.
*/
switch (entrytype) {
case BUCKYBITS:
case SHIFTKEYS:
case FUNNY:
/*
* There is no ascii equivalent. We will ignore these
* keys
*/
break;
case FUNCKEYS:
/*
* These will no doubt only cause problems. Ignore them.
*/
break;
case STRING:
/*
* These are the multi byte keys (Home, Up, Down ...)
*/
cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
/*
* Copy the string from the keystringtable, and send it
* upstream a character at a time.
*/
while (*cp != '\0') {
kbtrans_polled_putcode(upper, *cp);
cp++;
}
return;
case PADKEYS:
/*
* These are the keys on the keypad. Look up the
* answer in the kb_numlock_table and send it upstream.
*/
kbtrans_polled_putcode(upper,
lower->kbtrans_numlock_table[entry&0x1F]);
break;
case 0: /* normal character */
default:
/*
* Send the byte upstream.
*/
kbtrans_polled_putcode(upper, (char)entry);
break;
}
}
/*
* kbtrans_polled_released:
* This function is called when a key is released. Nothing is
* done.
*/
/*ARGSUSED*/
static void
kbtrans_polled_released(struct kbtrans *upper, kbtrans_key_t key)
{
/* Nothing for now */
}
/*
* kbtrans_polled_setled:
* This function is called to set the LEDs.
*/
static void
kbtrans_polled_setled(struct kbtrans *upper)
{
struct kbtrans_callbacks *cb;
struct kbtrans_hardware *hw;
cb = upper->kbtrans_streams_hw_callbacks;
hw = upper->kbtrans_streams_hw;
cb->kbtrans_polled_setled(hw, upper->kbtrans_lower.kbtrans_led_state);
}
/*
* kbtrans_polled_setup_repeat:
* Function to be called in order to handle a repeating key.
* Nothing is done.
*/
/*ARGSUSED*/
static void
kbtrans_polled_setup_repeat(
struct kbtrans *upper,
uint_t entrytype,
kbtrans_key_t key)
{
/* Nothing for now */
}
/*
* kbtrans_polled_cancel_repeat:
* Function to be called to cancel a repeating key,
* so that we don't end up with an autorepeating key
* on the stream because its release was handled by the
* polled code.
*/
static void
kbtrans_polled_cancel_repeat(struct kbtrans *upper)
{
/*
* Streams code will time out and will discard the
* autorepeat.
*/
upper->kbtrans_lower.kbtrans_repeatkey = 0;
}