mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
423 lines
12 KiB
C
423 lines
12 KiB
C
/* $Id: kb-sun.c,v 1.2 2003/10/16 02:48:25 fredette Exp $ */
|
|
|
|
/* serial/kb-sun.c - Sun serial keyboard emulation: */
|
|
|
|
/*
|
|
* Copyright (c) 2003 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. 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.
|
|
*/
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: kb-sun.c,v 1.2 2003/10/16 02:48:25 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include "serial-kb.h"
|
|
|
|
/* macros: */
|
|
|
|
/* Sun keyboard serial output data: */
|
|
#define KB_SUN_DATAOUT_RESET (0xff)
|
|
#define KB_SUN_DATAOUT_LAYOUT (0xfe)
|
|
#define KB_SUN_DATAOUT_IDLE (0x7f)
|
|
#define KB_SUN_DATAOUT_ERROR (0x7e)
|
|
#define KB_SUN_DATAOUT_KEYCODE_MASK (0x7f)
|
|
#define KB_SUN_DATAOUT_KEYCODE_RELEASE (0x80)
|
|
|
|
/* Sun keyboard serial input data. these are also
|
|
used as state machine states: */
|
|
#define KB_SUN_DATAIN_NONE (0x00)
|
|
#define KB_SUN_DATAIN_RESET (0x01)
|
|
#define KB_SUN_DATAIN_BELL_ON (0x02)
|
|
#define KB_SUN_DATAIN_BELL_OFF (0x03)
|
|
#define KB_SUN_DATAIN_CLICK_ON (0x0a)
|
|
#define KB_SUN_DATAIN_CLICK_OFF (0x0b)
|
|
#define KB_SUN_DATAIN_LEDS_SET (0x0e)
|
|
#define KB_SUN_DATAIN_LAYOUT_GET (0x0f)
|
|
|
|
/* Sun LED numbers: */
|
|
#define KB_SUN_LED_NUM_LOCK (0x1)
|
|
#define KB_SUN_LED_COMPOSE (0x2)
|
|
#define KB_SUN_LED_SCROLL_LOCK (0x4)
|
|
#define KB_SUN_LED_CAPS_LOCK (0x8)
|
|
|
|
/* types: */
|
|
|
|
/* keyboard type information: */
|
|
struct tme_kb_sun_type_info {
|
|
|
|
/* the keyboard type name: */
|
|
const char *tme_kb_sun_type_name;
|
|
|
|
/* the keyboard type code: */
|
|
tme_uint8_t tme_kb_sun_type_code;
|
|
|
|
/* the keyboard type layout: */
|
|
tme_uint8_t tme_kb_sun_type_layout;
|
|
};
|
|
|
|
/* the Sun serial keyboard state: */
|
|
struct tme_serial_kb_sun {
|
|
|
|
/* the keyboard type information: */
|
|
const struct tme_kb_sun_type_info *tme_serial_kb_sun_type;
|
|
|
|
/* our serial input state: */
|
|
tme_uint8_t tme_serial_kb_sun_input_state;
|
|
|
|
/* the Num_Lock modifier: */
|
|
int tme_serial_kb_sun_mod_num_lock;
|
|
};
|
|
|
|
/* globals: */
|
|
const struct tme_kb_sun_type_info tme_kb_sun_types[] = {
|
|
|
|
/* the type 2 keyboard: */
|
|
{ "sun-type-2", 2, 0x00 },
|
|
|
|
/* the type 3 keyboard: */
|
|
{ "sun-type-3", 3, 0x00 },
|
|
|
|
/* the type 4 keyboards: */
|
|
{ "sun-type-4-us", 4, 0x00 },
|
|
|
|
/* the type 5 keyboards: */
|
|
{ "sun-type-5-us", 5, 0x21 },
|
|
{ "sun-type-5-unix", 5, 0x22 },
|
|
};
|
|
|
|
/* this is called to handle serial input: */
|
|
static int
|
|
_tme_kb_sun_input(struct tme_serial_kb *serial_kb,
|
|
tme_uint8_t *data,
|
|
unsigned int count,
|
|
tme_serial_data_flags_t data_flags)
|
|
{
|
|
struct tme_serial_kb_sun *kb_sun;
|
|
tme_uint8_t c, output_buffer[2];
|
|
int new_callouts;
|
|
unsigned int old_empty, old_controls;
|
|
tme_keyboard_modifiers_t modifiers_clear, modifiers_set;
|
|
int modifier;
|
|
|
|
/* recover our data structure: */
|
|
kb_sun = serial_kb->tme_serial_kb_type_state;
|
|
|
|
/* assume that we won't need any new callouts: */
|
|
new_callouts = 0;
|
|
|
|
/* note if the serial buffer was empty, and its old controls: */
|
|
old_empty
|
|
= tme_serial_buffer_is_empty(&serial_kb->tme_serial_kb_serial_buffer);
|
|
old_controls
|
|
= serial_kb->tme_serial_kb_keyboard_ctrl;
|
|
|
|
/* loop over the data: */
|
|
for (; count > 0; count--) {
|
|
|
|
/* get this data: */
|
|
c = *(data++);
|
|
|
|
/* dispatch on our state: */
|
|
switch (kb_sun->tme_serial_kb_sun_input_state) {
|
|
case KB_SUN_DATAIN_NONE:
|
|
|
|
/* dispatch on the data: */
|
|
switch (c) {
|
|
|
|
case KB_SUN_DATAIN_RESET:
|
|
|
|
/* add the RESET byte and our keyboard type byte to our output: */
|
|
output_buffer[0] = KB_SUN_DATAOUT_RESET;
|
|
output_buffer[1] = kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_code;
|
|
tme_serial_buffer_copyin(&serial_kb->tme_serial_kb_serial_buffer,
|
|
output_buffer,
|
|
2,
|
|
TME_SERIAL_DATA_NORMAL,
|
|
TME_SERIAL_COPY_FULL_IS_OVERRUN);
|
|
break;
|
|
|
|
case KB_SUN_DATAIN_BELL_ON:
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
|= TME_KEYBOARD_CTRL_BELL;
|
|
break;
|
|
|
|
case KB_SUN_DATAIN_BELL_OFF:
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
&= ~TME_KEYBOARD_CTRL_BELL;
|
|
break;
|
|
|
|
case KB_SUN_DATAIN_CLICK_ON:
|
|
case KB_SUN_DATAIN_CLICK_OFF:
|
|
/* do nothing for now; the generic keyboard interface
|
|
doesn't support keyboard click: */
|
|
break;
|
|
|
|
/* KB_SUN_DATAIN_LEDS_SET is only supported on type 4 and
|
|
later keyboards: */
|
|
case KB_SUN_DATAIN_LEDS_SET:
|
|
if (kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_code
|
|
>= 4) {
|
|
kb_sun->tme_serial_kb_sun_input_state = c;
|
|
}
|
|
break;
|
|
|
|
/* KB_SUN_DATAIN_LAYOUT_GET is only supported on type 4 and
|
|
later keyboards: */
|
|
case KB_SUN_DATAIN_LAYOUT_GET:
|
|
if (kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_code
|
|
>= 4) {
|
|
|
|
/* add the LAYOUT byte and our keyboard layout byte to our output: */
|
|
output_buffer[0] = KB_SUN_DATAOUT_LAYOUT;
|
|
output_buffer[1] = kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_layout;
|
|
tme_serial_buffer_copyin(&serial_kb->tme_serial_kb_serial_buffer,
|
|
output_buffer,
|
|
2,
|
|
TME_SERIAL_DATA_NORMAL,
|
|
TME_SERIAL_COPY_FULL_IS_OVERRUN);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* ignore this byte: */
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case KB_SUN_DATAIN_LEDS_SET:
|
|
|
|
/* update the keyboard controls and the output modifiers: */
|
|
/* XXX the mapping of Sun keyboard LED to generic LED is
|
|
arbitrary: */
|
|
modifiers_clear = 0;
|
|
modifiers_set = 0;
|
|
modifier = kb_sun->tme_serial_kb_sun_mod_num_lock;
|
|
if (c & KB_SUN_LED_NUM_LOCK) {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
|= TME_KEYBOARD_CTRL_LED0;
|
|
if (modifier != TME_KEYBOARD_MODIFIER_NONE) {
|
|
modifiers_set |= (1 << modifier);
|
|
}
|
|
}
|
|
else {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
&= ~TME_KEYBOARD_CTRL_LED0;
|
|
if (modifier != TME_KEYBOARD_MODIFIER_NONE) {
|
|
modifiers_clear |= (1 << modifier);
|
|
}
|
|
}
|
|
if (c & KB_SUN_LED_COMPOSE) {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
|= TME_KEYBOARD_CTRL_LED1;
|
|
}
|
|
else {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
&= ~TME_KEYBOARD_CTRL_LED1;
|
|
}
|
|
if (c & KB_SUN_LED_SCROLL_LOCK) {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
|= TME_KEYBOARD_CTRL_LED2;
|
|
}
|
|
else {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
&= ~TME_KEYBOARD_CTRL_LED2;
|
|
}
|
|
if (c & KB_SUN_LED_CAPS_LOCK) {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
|= TME_KEYBOARD_CTRL_LED3;
|
|
modifiers_set |= (1 << TME_KEYBOARD_MODIFIER_LOCK);
|
|
}
|
|
else {
|
|
serial_kb->tme_serial_kb_keyboard_ctrl
|
|
&= ~TME_KEYBOARD_CTRL_LED3;
|
|
modifiers_clear |= (1 << TME_KEYBOARD_MODIFIER_LOCK);
|
|
}
|
|
|
|
tme_keyboard_buffer_out_modifiers(serial_kb->tme_serial_kb_keyboard_buffer,
|
|
modifiers_clear,
|
|
modifiers_set);
|
|
|
|
kb_sun->tme_serial_kb_sun_input_state = KB_SUN_DATAIN_NONE;
|
|
break;
|
|
|
|
default: assert(FALSE);
|
|
}
|
|
}
|
|
|
|
/* if the serial buffer was empty before and it isn't now,
|
|
update the serial controls and call them out: */
|
|
if (old_empty
|
|
&& !tme_serial_buffer_is_empty(&serial_kb->tme_serial_kb_serial_buffer)) {
|
|
new_callouts
|
|
|= TME_SERIAL_KB_CALLOUT_SERIAL_CTRL;
|
|
}
|
|
|
|
/* if the keyboard controls have changed, call them out: */
|
|
if (old_controls
|
|
!= serial_kb->tme_serial_kb_keyboard_ctrl) {
|
|
new_callouts
|
|
|= TME_SERIAL_KB_CALLOUT_KEYBOARD_CTRL;
|
|
}
|
|
|
|
/* set these new callouts: */
|
|
serial_kb->tme_serial_kb_callout_flags |= new_callouts;
|
|
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this is called before a map entry has been added: */
|
|
static int
|
|
_tme_kb_sun_map_add_pre(struct tme_serial_kb *serial_kb,
|
|
struct tme_keyboard_map *map)
|
|
{
|
|
/* make sure that the keyboard code is within range: */
|
|
if (map->tme_keyboard_map_keycode >= KB_SUN_DATAOUT_IDLE) {
|
|
return (EINVAL);
|
|
}
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this is called after a map entry has been added: */
|
|
static int
|
|
_tme_kb_sun_map_add_post(struct tme_serial_kb *serial_kb,
|
|
const struct tme_keyboard_map *map)
|
|
{
|
|
struct tme_serial_kb_sun *kb_sun;
|
|
int mode;
|
|
int rc;
|
|
|
|
/* recover our data structure: */
|
|
kb_sun = serial_kb->tme_serial_kb_type_state;
|
|
|
|
/* if this key is attached to a modifier: */
|
|
if (map->tme_keyboard_map_modifier
|
|
!= TME_KEYBOARD_MODIFIER_NONE) {
|
|
|
|
/* modifiers cannot autorepeat: */
|
|
mode
|
|
= (TME_KEYBOARD_MODE_PASSTHROUGH
|
|
| TME_KEYBOARD_MODE_FLAG_NO_AUTOREPEATS);
|
|
|
|
/* if this key is attached to the lock modifier, it soft-locks: */
|
|
if (map->tme_keyboard_map_modifier
|
|
== TME_KEYBOARD_MODIFIER_LOCK) {
|
|
mode |= TME_KEYBOARD_MODE_FLAG_LOCK_SOFT;
|
|
}
|
|
|
|
/* set the output mode on this key: */
|
|
rc = tme_keyboard_buffer_out_mode(serial_kb->tme_serial_kb_keyboard_buffer,
|
|
map->tme_keyboard_map_keycode,
|
|
mode);
|
|
assert (rc == TME_OK);
|
|
|
|
/* if this key is Num_Lock, remember
|
|
which modifier: */
|
|
if (map->tme_keyboard_map_keysym_note
|
|
== TME_KEYBOARD_KEYSYM_NOTE_NUM_LOCK) {
|
|
kb_sun->tme_serial_kb_sun_mod_num_lock
|
|
= map->tme_keyboard_map_modifier;
|
|
}
|
|
}
|
|
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this is called to get serial data from a keyboard event: */
|
|
static tme_uint8_t
|
|
_tme_kb_sun_event(struct tme_serial_kb *serial_kb,
|
|
const struct tme_keyboard_event *event)
|
|
{
|
|
tme_uint8_t data;
|
|
|
|
/* Sun keyboard key-release data has the high bit set: */
|
|
data = event->tme_keyboard_event_keyval;
|
|
if (event->tme_keyboard_event_type
|
|
== TME_KEYBOARD_EVENT_RELEASE) {
|
|
data |= KB_SUN_DATAOUT_KEYCODE_RELEASE;
|
|
}
|
|
return (data);
|
|
}
|
|
|
|
/* this initializes Sun serial keyboard emulation: */
|
|
int
|
|
_tme_serial_kb_sun_init(struct tme_serial_kb *serial_kb)
|
|
{
|
|
struct tme_serial_kb_sun *kb_sun;
|
|
const struct tme_kb_sun_type_info *type_info;
|
|
struct tme_serial_config *config;
|
|
unsigned int type_info_i;
|
|
int rc;
|
|
|
|
/* allocate the Sun serial keyboard state: */
|
|
kb_sun = tme_new0(struct tme_serial_kb_sun, 1);
|
|
serial_kb->tme_serial_kb_type_state = kb_sun;
|
|
|
|
/* initialize our state: */
|
|
kb_sun->tme_serial_kb_sun_mod_num_lock
|
|
= TME_KEYBOARD_MODIFIER_NONE;
|
|
|
|
/* find the information for this keyboard type: */
|
|
type_info = NULL;
|
|
for (type_info_i = 0;
|
|
type_info_i < TME_ARRAY_ELS(tme_kb_sun_types);
|
|
type_info_i++) {
|
|
if (!strcmp(tme_kb_sun_types[type_info_i].tme_kb_sun_type_name,
|
|
serial_kb->tme_serial_kb_type)) {
|
|
type_info = &tme_kb_sun_types[type_info_i];
|
|
break;
|
|
}
|
|
}
|
|
assert (type_info != NULL);
|
|
kb_sun->tme_serial_kb_sun_type = type_info;
|
|
|
|
/* set the global output keyboard mode. most keys on Sun keyboards
|
|
can follow the host: */
|
|
rc = tme_keyboard_buffer_out_mode(serial_kb->tme_serial_kb_keyboard_buffer,
|
|
TME_KEYBOARD_KEYVAL_UNDEF,
|
|
TME_KEYBOARD_MODE_PASSTHROUGH);
|
|
assert (rc == TME_OK);
|
|
|
|
/* set our type-dependent functions: */
|
|
serial_kb->tme_serial_kb_type_map_add_pre = _tme_kb_sun_map_add_pre;
|
|
serial_kb->tme_serial_kb_type_map_add_post = _tme_kb_sun_map_add_post;
|
|
serial_kb->tme_serial_kb_type_event = _tme_kb_sun_event;
|
|
serial_kb->tme_serial_kb_type_serial_ctrl = NULL;
|
|
serial_kb->tme_serial_kb_type_serial_input = _tme_kb_sun_input;
|
|
|
|
/* set our serial configuration: */
|
|
config = &serial_kb->tme_serial_kb_type_config;
|
|
memset(config, 0, sizeof(*config));
|
|
config->tme_serial_config_baud = 1200;
|
|
config->tme_serial_config_bits_data = 8;
|
|
config->tme_serial_config_bits_stop = 1;
|
|
config->tme_serial_config_parity = TME_SERIAL_PARITY_NONE;
|
|
|
|
return (TME_OK);
|
|
}
|