1 /* $Id: kb-sun.c,v 1.2 2003/10/16 02:48:25 fredette Exp $ */
2
3 /* serial/kb-sun.c - Sun serial keyboard emulation: */
4
5 /*
6 * Copyright (c) 2003 Matt Fredette
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Matt Fredette.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <tme/common.h>
37 _TME_RCSID("$Id: kb-sun.c,v 1.2 2003/10/16 02:48:25 fredette Exp $");
38
39 /* includes: */
40 #include "serial-kb.h"
41
42 /* macros: */
43
44 /* Sun keyboard serial output data: */
45 #define KB_SUN_DATAOUT_RESET (0xff)
46 #define KB_SUN_DATAOUT_LAYOUT (0xfe)
47 #define KB_SUN_DATAOUT_IDLE (0x7f)
48 #define KB_SUN_DATAOUT_ERROR (0x7e)
49 #define KB_SUN_DATAOUT_KEYCODE_MASK (0x7f)
50 #define KB_SUN_DATAOUT_KEYCODE_RELEASE (0x80)
51
52 /* Sun keyboard serial input data. these are also
53 used as state machine states: */
54 #define KB_SUN_DATAIN_NONE (0x00)
55 #define KB_SUN_DATAIN_RESET (0x01)
56 #define KB_SUN_DATAIN_BELL_ON (0x02)
57 #define KB_SUN_DATAIN_BELL_OFF (0x03)
58 #define KB_SUN_DATAIN_CLICK_ON (0x0a)
59 #define KB_SUN_DATAIN_CLICK_OFF (0x0b)
60 #define KB_SUN_DATAIN_LEDS_SET (0x0e)
61 #define KB_SUN_DATAIN_LAYOUT_GET (0x0f)
62
63 /* Sun LED numbers: */
64 #define KB_SUN_LED_NUM_LOCK (0x1)
65 #define KB_SUN_LED_COMPOSE (0x2)
66 #define KB_SUN_LED_SCROLL_LOCK (0x4)
67 #define KB_SUN_LED_CAPS_LOCK (0x8)
68
69 /* types: */
70
71 /* keyboard type information: */
72 struct tme_kb_sun_type_info {
73
74 /* the keyboard type name: */
75 const char *tme_kb_sun_type_name;
76
77 /* the keyboard type code: */
78 tme_uint8_t tme_kb_sun_type_code;
79
80 /* the keyboard type layout: */
81 tme_uint8_t tme_kb_sun_type_layout;
82 };
83
84 /* the Sun serial keyboard state: */
85 struct tme_serial_kb_sun {
86
87 /* the keyboard type information: */
88 const struct tme_kb_sun_type_info *tme_serial_kb_sun_type;
89
90 /* our serial input state: */
91 tme_uint8_t tme_serial_kb_sun_input_state;
92
93 /* the Num_Lock modifier: */
94 int tme_serial_kb_sun_mod_num_lock;
95 };
96
97 /* globals: */
98 const struct tme_kb_sun_type_info tme_kb_sun_types[] = {
99
100 /* the type 2 keyboard: */
101 { "sun-type-2", 2, 0x00 },
102
103 /* the type 3 keyboard: */
104 { "sun-type-3", 3, 0x00 },
105
106 /* the type 4 keyboards: */
107 { "sun-type-4-us", 4, 0x00 },
108
109 /* the type 5 keyboards: */
110 { "sun-type-5-us", 5, 0x21 },
111 { "sun-type-5-unix", 5, 0x22 },
112 };
113
114 /* this is called to handle serial input: */
115 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)116 _tme_kb_sun_input(struct tme_serial_kb *serial_kb,
117 tme_uint8_t *data,
118 unsigned int count,
119 tme_serial_data_flags_t data_flags)
120 {
121 struct tme_serial_kb_sun *kb_sun;
122 tme_uint8_t c, output_buffer[2];
123 int new_callouts;
124 unsigned int old_empty, old_controls;
125 tme_keyboard_modifiers_t modifiers_clear, modifiers_set;
126 int modifier;
127
128 /* recover our data structure: */
129 kb_sun = serial_kb->tme_serial_kb_type_state;
130
131 /* assume that we won't need any new callouts: */
132 new_callouts = 0;
133
134 /* note if the serial buffer was empty, and its old controls: */
135 old_empty
136 = tme_serial_buffer_is_empty(&serial_kb->tme_serial_kb_serial_buffer);
137 old_controls
138 = serial_kb->tme_serial_kb_keyboard_ctrl;
139
140 /* loop over the data: */
141 for (; count > 0; count--) {
142
143 /* get this data: */
144 c = *(data++);
145
146 /* dispatch on our state: */
147 switch (kb_sun->tme_serial_kb_sun_input_state) {
148 case KB_SUN_DATAIN_NONE:
149
150 /* dispatch on the data: */
151 switch (c) {
152
153 case KB_SUN_DATAIN_RESET:
154
155 /* add the RESET byte and our keyboard type byte to our output: */
156 output_buffer[0] = KB_SUN_DATAOUT_RESET;
157 output_buffer[1] = kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_code;
158 tme_serial_buffer_copyin(&serial_kb->tme_serial_kb_serial_buffer,
159 output_buffer,
160 2,
161 TME_SERIAL_DATA_NORMAL,
162 TME_SERIAL_COPY_FULL_IS_OVERRUN);
163 break;
164
165 case KB_SUN_DATAIN_BELL_ON:
166 serial_kb->tme_serial_kb_keyboard_ctrl
167 |= TME_KEYBOARD_CTRL_BELL;
168 break;
169
170 case KB_SUN_DATAIN_BELL_OFF:
171 serial_kb->tme_serial_kb_keyboard_ctrl
172 &= ~TME_KEYBOARD_CTRL_BELL;
173 break;
174
175 case KB_SUN_DATAIN_CLICK_ON:
176 case KB_SUN_DATAIN_CLICK_OFF:
177 /* do nothing for now; the generic keyboard interface
178 doesn't support keyboard click: */
179 break;
180
181 /* KB_SUN_DATAIN_LEDS_SET is only supported on type 4 and
182 later keyboards: */
183 case KB_SUN_DATAIN_LEDS_SET:
184 if (kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_code
185 >= 4) {
186 kb_sun->tme_serial_kb_sun_input_state = c;
187 }
188 break;
189
190 /* KB_SUN_DATAIN_LAYOUT_GET is only supported on type 4 and
191 later keyboards: */
192 case KB_SUN_DATAIN_LAYOUT_GET:
193 if (kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_code
194 >= 4) {
195
196 /* add the LAYOUT byte and our keyboard layout byte to our output: */
197 output_buffer[0] = KB_SUN_DATAOUT_LAYOUT;
198 output_buffer[1] = kb_sun->tme_serial_kb_sun_type->tme_kb_sun_type_layout;
199 tme_serial_buffer_copyin(&serial_kb->tme_serial_kb_serial_buffer,
200 output_buffer,
201 2,
202 TME_SERIAL_DATA_NORMAL,
203 TME_SERIAL_COPY_FULL_IS_OVERRUN);
204 }
205 break;
206
207 default:
208 /* ignore this byte: */
209 break;
210 }
211 break;
212
213 case KB_SUN_DATAIN_LEDS_SET:
214
215 /* update the keyboard controls and the output modifiers: */
216 /* XXX the mapping of Sun keyboard LED to generic LED is
217 arbitrary: */
218 modifiers_clear = 0;
219 modifiers_set = 0;
220 modifier = kb_sun->tme_serial_kb_sun_mod_num_lock;
221 if (c & KB_SUN_LED_NUM_LOCK) {
222 serial_kb->tme_serial_kb_keyboard_ctrl
223 |= TME_KEYBOARD_CTRL_LED0;
224 if (modifier != TME_KEYBOARD_MODIFIER_NONE) {
225 modifiers_set |= (1 << modifier);
226 }
227 }
228 else {
229 serial_kb->tme_serial_kb_keyboard_ctrl
230 &= ~TME_KEYBOARD_CTRL_LED0;
231 if (modifier != TME_KEYBOARD_MODIFIER_NONE) {
232 modifiers_clear |= (1 << modifier);
233 }
234 }
235 if (c & KB_SUN_LED_COMPOSE) {
236 serial_kb->tme_serial_kb_keyboard_ctrl
237 |= TME_KEYBOARD_CTRL_LED1;
238 }
239 else {
240 serial_kb->tme_serial_kb_keyboard_ctrl
241 &= ~TME_KEYBOARD_CTRL_LED1;
242 }
243 if (c & KB_SUN_LED_SCROLL_LOCK) {
244 serial_kb->tme_serial_kb_keyboard_ctrl
245 |= TME_KEYBOARD_CTRL_LED2;
246 }
247 else {
248 serial_kb->tme_serial_kb_keyboard_ctrl
249 &= ~TME_KEYBOARD_CTRL_LED2;
250 }
251 if (c & KB_SUN_LED_CAPS_LOCK) {
252 serial_kb->tme_serial_kb_keyboard_ctrl
253 |= TME_KEYBOARD_CTRL_LED3;
254 modifiers_set |= (1 << TME_KEYBOARD_MODIFIER_LOCK);
255 }
256 else {
257 serial_kb->tme_serial_kb_keyboard_ctrl
258 &= ~TME_KEYBOARD_CTRL_LED3;
259 modifiers_clear |= (1 << TME_KEYBOARD_MODIFIER_LOCK);
260 }
261
262 tme_keyboard_buffer_out_modifiers(serial_kb->tme_serial_kb_keyboard_buffer,
263 modifiers_clear,
264 modifiers_set);
265
266 kb_sun->tme_serial_kb_sun_input_state = KB_SUN_DATAIN_NONE;
267 break;
268
269 default: assert(FALSE);
270 }
271 }
272
273 /* if the serial buffer was empty before and it isn't now,
274 update the serial controls and call them out: */
275 if (old_empty
276 && !tme_serial_buffer_is_empty(&serial_kb->tme_serial_kb_serial_buffer)) {
277 new_callouts
278 |= TME_SERIAL_KB_CALLOUT_SERIAL_CTRL;
279 }
280
281 /* if the keyboard controls have changed, call them out: */
282 if (old_controls
283 != serial_kb->tme_serial_kb_keyboard_ctrl) {
284 new_callouts
285 |= TME_SERIAL_KB_CALLOUT_KEYBOARD_CTRL;
286 }
287
288 /* set these new callouts: */
289 serial_kb->tme_serial_kb_callout_flags |= new_callouts;
290
291 return (TME_OK);
292 }
293
294 /* this is called before a map entry has been added: */
295 static int
_tme_kb_sun_map_add_pre(struct tme_serial_kb * serial_kb,struct tme_keyboard_map * map)296 _tme_kb_sun_map_add_pre(struct tme_serial_kb *serial_kb,
297 struct tme_keyboard_map *map)
298 {
299 /* make sure that the keyboard code is within range: */
300 if (map->tme_keyboard_map_keycode >= KB_SUN_DATAOUT_IDLE) {
301 return (EINVAL);
302 }
303 return (TME_OK);
304 }
305
306 /* this is called after a map entry has been added: */
307 static int
_tme_kb_sun_map_add_post(struct tme_serial_kb * serial_kb,const struct tme_keyboard_map * map)308 _tme_kb_sun_map_add_post(struct tme_serial_kb *serial_kb,
309 const struct tme_keyboard_map *map)
310 {
311 struct tme_serial_kb_sun *kb_sun;
312 int mode;
313 int rc;
314
315 /* recover our data structure: */
316 kb_sun = serial_kb->tme_serial_kb_type_state;
317
318 /* if this key is attached to a modifier: */
319 if (map->tme_keyboard_map_modifier
320 != TME_KEYBOARD_MODIFIER_NONE) {
321
322 /* modifiers cannot autorepeat: */
323 mode
324 = (TME_KEYBOARD_MODE_PASSTHROUGH
325 | TME_KEYBOARD_MODE_FLAG_NO_AUTOREPEATS);
326
327 /* if this key is attached to the lock modifier, it soft-locks: */
328 if (map->tme_keyboard_map_modifier
329 == TME_KEYBOARD_MODIFIER_LOCK) {
330 mode |= TME_KEYBOARD_MODE_FLAG_LOCK_SOFT;
331 }
332
333 /* set the output mode on this key: */
334 rc = tme_keyboard_buffer_out_mode(serial_kb->tme_serial_kb_keyboard_buffer,
335 map->tme_keyboard_map_keycode,
336 mode);
337 assert (rc == TME_OK);
338
339 /* if this key is Num_Lock, remember
340 which modifier: */
341 if (map->tme_keyboard_map_keysym_note
342 == TME_KEYBOARD_KEYSYM_NOTE_NUM_LOCK) {
343 kb_sun->tme_serial_kb_sun_mod_num_lock
344 = map->tme_keyboard_map_modifier;
345 }
346 }
347
348 return (TME_OK);
349 }
350
351 /* this is called to get serial data from a keyboard event: */
352 static tme_uint8_t
_tme_kb_sun_event(struct tme_serial_kb * serial_kb,const struct tme_keyboard_event * event)353 _tme_kb_sun_event(struct tme_serial_kb *serial_kb,
354 const struct tme_keyboard_event *event)
355 {
356 tme_uint8_t data;
357
358 /* Sun keyboard key-release data has the high bit set: */
359 data = event->tme_keyboard_event_keyval;
360 if (event->tme_keyboard_event_type
361 == TME_KEYBOARD_EVENT_RELEASE) {
362 data |= KB_SUN_DATAOUT_KEYCODE_RELEASE;
363 }
364 return (data);
365 }
366
367 /* this initializes Sun serial keyboard emulation: */
368 int
_tme_serial_kb_sun_init(struct tme_serial_kb * serial_kb)369 _tme_serial_kb_sun_init(struct tme_serial_kb *serial_kb)
370 {
371 struct tme_serial_kb_sun *kb_sun;
372 const struct tme_kb_sun_type_info *type_info;
373 struct tme_serial_config *config;
374 unsigned int type_info_i;
375 int rc;
376
377 /* allocate the Sun serial keyboard state: */
378 kb_sun = tme_new0(struct tme_serial_kb_sun, 1);
379 serial_kb->tme_serial_kb_type_state = kb_sun;
380
381 /* initialize our state: */
382 kb_sun->tme_serial_kb_sun_mod_num_lock
383 = TME_KEYBOARD_MODIFIER_NONE;
384
385 /* find the information for this keyboard type: */
386 type_info = NULL;
387 for (type_info_i = 0;
388 type_info_i < TME_ARRAY_ELS(tme_kb_sun_types);
389 type_info_i++) {
390 if (!strcmp(tme_kb_sun_types[type_info_i].tme_kb_sun_type_name,
391 serial_kb->tme_serial_kb_type)) {
392 type_info = &tme_kb_sun_types[type_info_i];
393 break;
394 }
395 }
396 assert (type_info != NULL);
397 kb_sun->tme_serial_kb_sun_type = type_info;
398
399 /* set the global output keyboard mode. most keys on Sun keyboards
400 can follow the host: */
401 rc = tme_keyboard_buffer_out_mode(serial_kb->tme_serial_kb_keyboard_buffer,
402 TME_KEYBOARD_KEYVAL_UNDEF,
403 TME_KEYBOARD_MODE_PASSTHROUGH);
404 assert (rc == TME_OK);
405
406 /* set our type-dependent functions: */
407 serial_kb->tme_serial_kb_type_map_add_pre = _tme_kb_sun_map_add_pre;
408 serial_kb->tme_serial_kb_type_map_add_post = _tme_kb_sun_map_add_post;
409 serial_kb->tme_serial_kb_type_event = _tme_kb_sun_event;
410 serial_kb->tme_serial_kb_type_serial_ctrl = NULL;
411 serial_kb->tme_serial_kb_type_serial_input = _tme_kb_sun_input;
412
413 /* set our serial configuration: */
414 config = &serial_kb->tme_serial_kb_type_config;
415 memset(config, 0, sizeof(*config));
416 config->tme_serial_config_baud = 1200;
417 config->tme_serial_config_bits_data = 8;
418 config->tme_serial_config_bits_stop = 1;
419 config->tme_serial_config_parity = TME_SERIAL_PARITY_NONE;
420
421 return (TME_OK);
422 }
423