source: mainline/uspace/srv/hid/kbd/genarch/gsp.c@ 0b4a67a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0b4a67a was 0b4a67a, checked in by Jakub Jermar <jakub@…>, 15 years ago

Use a more portable definition of NULL.

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 * Copyright (c) 2009 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @addtogroup kbdgen generic
31 * @ingroup kbd
32 * @{
33 */
34/** @file
35 * @brief Generic scancode parser.
36 *
37 * The scancode parser is a simple finite state machine. It is described
38 * using sequences of input symbols (scancodes) and the corresponding output
39 * value (mods, key pair). When the parser recognizes a sequence,
40 * it outputs the value and restarts. If a transition is undefined,
41 * the parser restarts, too.
42 *
43 * Apart from precise values, GSP_DEFAULT allows to catch general cases.
44 * I.e. if we knew that after 0x1b 0x4f there always follow two more
45 * scancodes, we can define (0x1b, 0x4f, GSP_DEFAULT, GSP_DEFAULT, GSP_END)
46 * with null output. This will force the parser to read the entire sequence,
47 * not leaving garbage on the input if it does not recognize the specific
48 * sequence.
49 */
50
51#include <gsp.h>
52#include <adt/hash_table.h>
53#include <stdlib.h>
54#include <stdio.h>
55
56#define TRANS_TABLE_CHAINS 256
57
58/*
59 * Hash table operations for the transition function.
60 */
61
62static hash_index_t trans_op_hash(unsigned long key[]);
63static int trans_op_compare(unsigned long key[], hash_count_t keys,
64 link_t *item);
65static void trans_op_remove_callback(link_t *item);
66
67static hash_table_operations_t trans_ops = {
68 .hash = trans_op_hash,
69 .compare = trans_op_compare,
70 .remove_callback = trans_op_remove_callback
71};
72
73static gsp_trans_t *trans_lookup(gsp_t *p, int state, int input);
74static void trans_insert(gsp_t *p, gsp_trans_t *t);
75static gsp_trans_t *trans_new(void);
76
77/** Initialise scancode parser. */
78void gsp_init(gsp_t *p)
79{
80 p->states = 1;
81 hash_table_create(&p->trans, TRANS_TABLE_CHAINS, 2, &trans_ops);
82}
83
84/** Insert a series of definitions into the parser.
85 *
86 * @param p The parser.
87 * @param defs Definition list. Each definition starts with two output values
88 * (mods, key) and continues with a sequence of input values
89 * terminated with GSP_END. The definition list is terminated
90 * with two zeroes (0, 0) for output values.
91 */
92int gsp_insert_defs(gsp_t *p, const int *defs)
93{
94 unsigned mods, key;
95 const int *dp;
96 int rc;
97
98 dp = defs;
99
100 while (1) {
101 /* Read the output values. */
102 mods = *dp++;
103 key = *dp++;
104 if (key == 0) break;
105
106 /* Insert one sequence. */
107 rc = gsp_insert_seq(p, dp, mods, key);
108 if (rc != 0)
109 return rc;
110
111 /* Skip to the next definition. */
112 while (*dp != GSP_END)
113 ++dp;
114 ++dp;
115 }
116
117 return 0;
118}
119
120/** Insert one sequence into the parser.
121 *
122 * @param p The parser.
123 * @param seq Sequence of input values terminated with GSP_END.
124 * @param mods Corresponsing output value.
125 * @param key Corresponsing output value.
126 */
127int gsp_insert_seq(gsp_t *p, const int *seq, unsigned mods, unsigned key)
128{
129 int state;
130 gsp_trans_t *t;
131
132 state = 0;
133 t = NULL;
134
135 /* Input sequence must be non-empty. */
136 if (*seq == GSP_END)
137 return -1;
138
139 while (*(seq + 1) != GSP_END) {
140 t = trans_lookup(p, state, *seq);
141 if (t == NULL) {
142 /* Create new state. */
143 t = trans_new();
144 t->old_state = state;
145 t->input = *seq;
146 t->new_state = p->states++;
147
148 t->out_mods = 0;
149 t->out_key = 0;
150
151 trans_insert(p, t);
152 }
153 state = t->new_state;
154 ++seq;
155 }
156
157 /* Process the last transition. */
158 t = trans_lookup(p, state, *seq);
159 if (t != NULL) {
160 exit(1);
161 return -1; /* Conflicting definition. */
162 }
163
164 t = trans_new();
165 t->old_state = state;
166 t->input = *seq;
167 t->new_state = 0;
168
169 t->out_mods = mods;
170 t->out_key = key;
171
172 trans_insert(p, t);
173
174 return 0;
175}
176
177/** Compute one parser step.
178 *
179 * Computes the next state and output values for a given state and input.
180 * This handles everything including restarts and default branches.
181 *
182 * @param p The parser.
183 * @param state Old state.
184 * @param input Input symbol (scancode).
185 * @param mods Output value (modifier).
186 * @param key Output value (key).
187 * @return New state.
188 */
189int gsp_step(gsp_t *p, int state, int input, unsigned *mods, unsigned *key)
190{
191 gsp_trans_t *t;
192
193 t = trans_lookup(p, state, input);
194 if (t == NULL) {
195 t = trans_lookup(p, state, GSP_DEFAULT);
196 }
197
198 if (t == NULL) {
199 printf("gsp_step: not found\n");
200 *mods = 0;
201 *key = 0;
202 return 0;
203 }
204
205 *mods = t->out_mods;
206 *key = t->out_key;
207 return t->new_state;
208}
209
210/** Transition function lookup.
211 *
212 * Returns the value of the transition function for the given state
213 * and input. Note that the transition must be specified precisely,
214 * to obtain the default branch use input = GSP_DEFAULT.
215 *
216 * @param p Parser.
217 * @param state Current state.
218 * @param input Input value.
219 * @return The transition or @c NULL if not defined.
220 */
221static gsp_trans_t *trans_lookup(gsp_t *p, int state, int input)
222{
223 link_t *item;
224 unsigned long key[2];
225
226 key[0] = state;
227 key[1] = input;
228
229 item = hash_table_find(&p->trans, key);
230 if (item == NULL) return NULL;
231
232 return hash_table_get_instance(item, gsp_trans_t, link);
233}
234
235/** Define a new transition.
236 *
237 * @param p The parser.
238 * @param t Transition with all fields defined.
239 */
240static void trans_insert(gsp_t *p, gsp_trans_t *t)
241{
242 unsigned long key[2];
243
244 key[0] = t->old_state;
245 key[1] = t->input;
246
247 hash_table_insert(&p->trans, key, &t->link);
248}
249
250/** Allocate transition structure. */
251static gsp_trans_t *trans_new(void)
252{
253 gsp_trans_t *t;
254
255 t = malloc(sizeof(gsp_trans_t));
256 if (t == NULL) {
257 printf("Memory allocation failed.\n");
258 exit(1);
259 }
260
261 return t;
262}
263
264/*
265 * Transition function hash table operations.
266 */
267
268static hash_index_t trans_op_hash(unsigned long key[])
269{
270 return (key[0] * 17 + key[1]) % TRANS_TABLE_CHAINS;
271}
272
273static int trans_op_compare(unsigned long key[], hash_count_t keys,
274 link_t *item)
275{
276 gsp_trans_t *t;
277
278 t = hash_table_get_instance(item, gsp_trans_t, link);
279 return ((key[0] == (unsigned long) t->old_state)
280 && (key[1] == (unsigned long) t->input));
281}
282
283static void trans_op_remove_callback(link_t *item)
284{
285}
286
287/**
288 * @}
289 */
Note: See TracBrowser for help on using the repository browser.