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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • 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.