source: mainline/uspace/srv/hid/input/gsp.c@ 72c72d4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 72c72d4 was 76d0981d, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Use proper boolean constant in while loops.

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