source: mainline/uspace/srv/hid/input/gsp.c@ 4e00f87

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

Use NULL instead of 0 as a hash_table_ops_t member initializer.

  • Property mode set to 100644
File size: 7.0 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 input
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 <adt/hash_table.h>
52#include <adt/hash.h>
53#include <stdlib.h>
54#include <stdio.h>
55#include "gsp.h"
56
57/*
58 * Transition function hash table operations.
59 */
60typedef struct {
61 int old_state;
62 int input;
63} trans_key_t;
64
65static size_t trans_key_hash(void *key)
66{
67 trans_key_t *trans_key = (trans_key_t *)key;
68 return hash_combine(trans_key->input, trans_key->old_state);
69}
70
71static size_t trans_hash(const ht_link_t *item)
72{
73 gsp_trans_t *t = hash_table_get_inst(item, gsp_trans_t, link);
74 return hash_combine(t->input, t->old_state);
75}
76
77static bool trans_key_equal(void *key, const ht_link_t *item)
78{
79 trans_key_t *trans_key = (trans_key_t *)key;
80 gsp_trans_t *t = hash_table_get_inst(item, gsp_trans_t, link);
81
82 return trans_key->input == t->input && trans_key->old_state == t->old_state;
83}
84
85static hash_table_ops_t trans_ops = {
86 .hash = trans_hash,
87 .key_hash = trans_key_hash,
88 .key_equal = trans_key_equal,
89 .equal = NULL,
90 .remove_callback = NULL
91};
92
93
94static gsp_trans_t *trans_lookup(gsp_t *p, int state, int input);
95static void trans_insert(gsp_t *p, gsp_trans_t *t);
96static gsp_trans_t *trans_new(void);
97
98/** Initialize scancode parser. */
99void gsp_init(gsp_t *p)
100{
101 p->states = 1;
102 hash_table_create(&p->trans, 0, 0, &trans_ops);
103}
104
105/** Insert a series of definitions into the parser.
106 *
107 * @param p The parser.
108 * @param defs Definition list. Each definition starts with two output values
109 * (mods, key) and continues with a sequence of input values
110 * terminated with GSP_END. The definition list is terminated
111 * with two zeroes (0, 0) for output values.
112 */
113int gsp_insert_defs(gsp_t *p, const int *defs)
114{
115 unsigned mods, key;
116 const int *dp;
117 int rc;
118
119 dp = defs;
120
121 while (1) {
122 /* Read the output values. */
123 mods = *dp++;
124 key = *dp++;
125 if (key == 0) break;
126
127 /* Insert one sequence. */
128 rc = gsp_insert_seq(p, dp, mods, key);
129 if (rc != 0)
130 return rc;
131
132 /* Skip to the next definition. */
133 while (*dp != GSP_END)
134 ++dp;
135 ++dp;
136 }
137
138 return 0;
139}
140
141/** Insert one sequence into the parser.
142 *
143 * @param p The parser.
144 * @param seq Sequence of input values terminated with GSP_END.
145 * @param mods Corresponsing output value.
146 * @param key Corresponsing output value.
147 */
148int gsp_insert_seq(gsp_t *p, const int *seq, unsigned mods, unsigned key)
149{
150 int state;
151 gsp_trans_t *t;
152
153 state = 0;
154 t = NULL;
155
156 /* Input sequence must be non-empty. */
157 if (*seq == GSP_END)
158 return -1;
159
160 while (*(seq + 1) != GSP_END) {
161 t = trans_lookup(p, state, *seq);
162 if (t == NULL) {
163 /* Create new state. */
164 t = trans_new();
165 t->old_state = state;
166 t->input = *seq;
167 t->new_state = p->states++;
168
169 t->out_mods = 0;
170 t->out_key = 0;
171
172 trans_insert(p, t);
173 }
174 state = t->new_state;
175 ++seq;
176 }
177
178 /* Process the last transition. */
179 t = trans_lookup(p, state, *seq);
180 if (t != NULL) {
181 exit(1);
182 return -1; /* Conflicting definition. */
183 }
184
185 t = trans_new();
186 t->old_state = state;
187 t->input = *seq;
188 t->new_state = 0;
189
190 t->out_mods = mods;
191 t->out_key = key;
192
193 trans_insert(p, t);
194
195 return 0;
196}
197
198/** Compute one parser step.
199 *
200 * Computes the next state and output values for a given state and input.
201 * This handles everything including restarts and default branches.
202 *
203 * @param p The parser.
204 * @param state Old state.
205 * @param input Input symbol (scancode).
206 * @param mods Output value (modifier).
207 * @param key Output value (key).
208 * @return New state.
209 */
210int gsp_step(gsp_t *p, int state, int input, unsigned *mods, unsigned *key)
211{
212 gsp_trans_t *t;
213
214 t = trans_lookup(p, state, input);
215 if (t == NULL) {
216 t = trans_lookup(p, state, GSP_DEFAULT);
217 }
218
219 if (t == NULL) {
220 printf("gsp_step: not found, state=%d, input=0x%x\n",
221 state, input);
222 *mods = 0;
223 *key = 0;
224 return 0;
225 }
226
227 *mods = t->out_mods;
228 *key = t->out_key;
229
230 return t->new_state;
231}
232
233/** Transition function lookup.
234 *
235 * Returns the value of the transition function for the given state
236 * and input. Note that the transition must be specified precisely,
237 * to obtain the default branch use input = GSP_DEFAULT.
238 *
239 * @param p Parser.
240 * @param state Current state.
241 * @param input Input value.
242 * @return The transition or @c NULL if not defined.
243 */
244static gsp_trans_t *trans_lookup(gsp_t *p, int state, int input)
245{
246 ht_link_t *item;
247
248 trans_key_t key = {
249 .input = input,
250 .old_state = state
251 };
252
253 item = hash_table_find(&p->trans, &key);
254 if (item == NULL) return NULL;
255
256 return hash_table_get_inst(item, gsp_trans_t, link);
257}
258
259/** Define a new transition.
260 *
261 * @param p The parser.
262 * @param t Transition with all fields defined.
263 */
264static void trans_insert(gsp_t *p, gsp_trans_t *t)
265{
266 hash_table_insert(&p->trans, &t->link);
267}
268
269/** Allocate transition structure. */
270static gsp_trans_t *trans_new(void)
271{
272 gsp_trans_t *t;
273
274 t = malloc(sizeof(gsp_trans_t));
275 if (t == NULL) {
276 printf("Memory allocation failed.\n");
277 exit(1);
278 }
279
280 return t;
281}
282
283
284/**
285 * @}
286 */
Note: See TracBrowser for help on using the repository browser.