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