SHOW:
|
|
- or go back to the newest paste.
1 | /* A component to convert 7i73 bytecodes to bit pins */ | |
2 | #include "rtapi.h" | |
3 | #include "rtapi_app.h" | |
4 | #include "hal.h" | |
5 | #include <linux/input.h> | |
6 | #include <linux/uinput.h> | |
7 | ||
8 | #ifndef SIM // KERNEL (RTAPI) MODE | |
9 | ||
10 | #define keyb_dev_t struct input_dev * | |
11 | #define CREATE_KB_DEV input_allocate_device() | |
12 | #define UNLOAD_KB_DEV(kb) input_unregister_device(kb) | |
13 | #define REGISTER_KB(kb) input_register_device(kb) | |
14 | #define NAME_KB(kb, n) kb->name = n; | |
15 | #define SETEVENT(kb) set_bit(EV_KEY, kb->evbit); | |
16 | #define SETKEY(kb, ev_code) set_bit(ev_code, kb->keybit); | |
17 | #define KEYUP(kb, ev_code) input_report_key(kb, ev_code, 0); \ | |
18 | input_sync(kb); | |
19 | #define KEYDOWN(kb, ev_code)input_report_key(kb, ev_code, 1); \ | |
20 | input_sync(kb); | |
21 | ||
22 | #else // SIM OR USERLAND MODE | |
23 | ||
24 | #include <stdio.h> | |
25 | #include <fcntl.h> | |
26 | #include <unistd.h> | |
27 | #define keyb_dev_t int | |
28 | #define CREATE_KB_DEV open("/dev/uinput", O_WRONLY | O_NONBLOCK) | |
29 | #define UNLOAD_KB_DEV(kb) ioctl(kb, UI_DEV_DESTROY) | |
30 | #define REGISTER_KB(kb) ioctl(kb, UI_DEV_CREATE) | |
31 | //the "if" suppresses a compiler warning. There may be a better way | |
32 | #define NAME_KB(kb, n) snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "%s", n); \ | |
33 | uidev.id.bustype = BUS_VIRTUAL; \ | |
34 | if(write(kb, &uidev, sizeof(uidev))) | |
35 | #define SETEVENT(kb) ioctl(kb, UI_SET_EVBIT, EV_KEY); \ | |
36 | ioctl(kb, UI_SET_EVBIT, EV_SYN) | |
37 | #define SETKEY(kb, ev_code) ioctl(kb, UI_SET_KEYBIT, ev_code) | |
38 | #define KEYUP(kb, ev_code) ev.type = EV_KEY; ev.code = ev_code; ev.value = 0; \ | |
39 | if(write(kb, &ev, sizeof(ev))); \ | |
40 | ev.type = EV_SYN; ev.code = 0; ev.value = 0; \ | |
41 | if(write(kb, &ev, sizeof(ev))) | |
42 | #define KEYDOWN(kb, ev_code)ev.type = EV_KEY; ev.code = ev_code; ev.value = 1; \ | |
43 | if(write(kb, &ev, sizeof(ev))); \ | |
44 | ev.type = EV_SYN; ev.code = 0; ev.value = 0; \ | |
45 | if(write(kb, &ev, sizeof(ev))) | |
46 | #endif | |
47 | ||
48 | #define MAX_CHAN 8 | |
49 | #define MAX_ROLLOVER 8 | |
50 | ||
51 | /* module information */ | |
52 | MODULE_AUTHOR("Andy Pugh"); | |
53 | MODULE_DESCRIPTION("Hal-to-text component for Mesa 7i73 and similar"); | |
54 | MODULE_LICENSE("GPL"); | |
55 | ||
56 | typedef struct { | |
57 | struct { | |
58 | hal_bit_t **key; | |
59 | hal_bit_t **rows; | |
60 | hal_bit_t **cols; | |
61 | hal_u32_t *keycode; | |
62 | } hal; | |
63 | struct { | |
64 | hal_u32_t *code; | |
65 | hal_u32_t rollover; | |
66 | hal_bit_t invert; | |
67 | } param; | |
68 | hal_u32_t ncols; | |
69 | hal_u32_t nrows; | |
70 | hal_u32_t *now; | |
71 | hal_u32_t *then; | |
72 | hal_u32_t keys[MAX_ROLLOVER]; | |
73 | hal_bit_t invert; | |
74 | char name[HAL_NAME_LEN + 1]; | |
75 | keyb_dev_t key_dev; | |
76 | hal_u32_t index; | |
77 | int keydown; | |
78 | int keyup; | |
79 | int rowshift; | |
80 | int row; | |
81 | int num_keys; | |
82 | int lastkey; | |
83 | hal_bit_t scan; | |
84 | hal_bit_t keystroke; | |
85 | }kb_inst_t; | |
86 | ||
87 | typedef struct { | |
88 | kb_inst_t *insts; | |
89 | int num_insts; | |
90 | }kb_t; | |
91 | ||
92 | static int comp_id; | |
93 | static kb_t *kb; | |
94 | struct input_event ev; | |
95 | struct uinput_user_dev uidev; | |
96 | ||
97 | char *config[MAX_CHAN]; | |
98 | RTAPI_MP_ARRAY_STRING(config, MAX_CHAN, "screen formatting scancodes") | |
99 | char *names[MAX_CHAN]; | |
100 | RTAPI_MP_ARRAY_STRING(names, MAX_CHAN, "component names") | |
101 | ||
102 | void keyup(kb_inst_t *inst){ | |
103 | int r, c; | |
104 | int keycode = *inst->hal.keycode & ~(inst->keydown | inst->keyup); | |
105 | ||
106 | r = keycode >> inst->rowshift; | |
107 | c = keycode & ~(0xFFFFFFFF << inst->rowshift); | |
108 | ||
109 | if (r < 0 | |
110 | || c < 0 | |
111 | || r >= inst->nrows | |
112 | || c >= inst->ncols | |
113 | || inst->hal.key[r * inst->ncols + c] == NULL){ | |
114 | return; | |
115 | } | |
116 | ||
117 | if (inst->num_keys > 0) inst->num_keys--; | |
118 | ||
119 | *inst->hal.key[r * inst->ncols + c] = 0; | |
120 | ||
121 | if(inst->keystroke){ | |
122 | if (inst->param.code[r * inst->ncols + c]){ | |
123 | KEYUP(inst->key_dev, inst->param.code[r * inst->ncols + c]); | |
124 | } | |
125 | } | |
126 | ||
127 | } | |
128 | void keydown(kb_inst_t *inst){ | |
129 | int r, c; | |
130 | int keycode = *inst->hal.keycode & ~(inst->keydown | inst->keyup); | |
131 | ||
132 | r = keycode >> inst->rowshift; | |
133 | c = keycode & ~(0xFFFFFFFF << inst->rowshift); | |
134 | ||
135 | if (r < 0 | |
136 | || c < 0 | |
137 | || r >= inst->nrows | |
138 | || c >= inst->ncols | |
139 | || inst->hal.key[r * inst->ncols + c] == NULL){ | |
140 | return; | |
141 | } | |
142 | ||
143 | if (inst->num_keys >= inst->param.rollover) return; | |
144 | inst->num_keys++; | |
145 | ||
146 | *inst->hal.key[r * inst->ncols + c] = 1; | |
147 | ||
148 | if (inst->keystroke){ | |
149 | if (inst->param.code[r * inst->ncols + c]){ | |
150 | KEYDOWN(inst->key_dev, inst->param.code[r * inst->ncols + c]); | |
151 | } | |
152 | } | |
153 | } | |
154 | ||
155 | void loop(void *arg, long period){ | |
156 | int c; | |
157 | hal_u32_t scan = 0; | |
158 | kb_inst_t *inst = arg; | |
159 | ||
160 | if (inst->param.rollover > MAX_ROLLOVER) inst->param.rollover = MAX_ROLLOVER; | |
161 | ||
162 | if (inst->scan){ //scanning request | |
163 | for (c = 0; c < inst->ncols; c++){ | |
164 | scan += ((*inst->hal.cols[c] != inst->param.invert) << c); | |
165 | } | |
166 | if (scan == inst->now[inst->row] && scan != inst->then[inst->row]){ | |
167 | // debounced and changed | |
168 | for (c = 0; c < inst->ncols; c++){ | |
169 | int mask = 1 << c; | |
170 | if ((inst->then[inst->row] & mask) && !(scan & mask)){ //keyup | |
171 | *inst->hal.keycode = inst->keyup | |
172 | + (inst->row << inst->rowshift) | |
173 | + c; | |
174 | keyup(inst); | |
175 | } | |
176 | else if (!(inst->then[inst->row] & mask) && (scan & mask)){//keydown | |
177 | *inst->hal.keycode = inst->keydown | |
178 | + (inst->row << inst->rowshift) | |
179 | + c; | |
180 | ||
181 | keydown(inst); | |
182 | } | |
183 | } | |
184 | } | |
185 | ||
186 | inst->then[inst->row] = inst->now[inst->row]; | |
187 | inst->now[inst->row] = scan; | |
188 | ||
189 | *inst->hal.rows[inst->row] = inst->param.invert; | |
190 | inst->row++; | |
191 | if (inst->row >= inst->nrows) inst->row = 0; | |
192 | *inst->hal.rows[inst->row] = !inst->param.invert; | |
193 | } | |
194 | else | |
195 | { | |
196 | if (*inst->hal.keycode == inst->lastkey) return; | |
197 | //lastkey is just to trap a 7i73 bug: keyup 0,0 == allup. | |
198 | if (*inst->hal.keycode & inst->keydown){ | |
199 | keydown(inst); | |
200 | } | |
201 | else | |
202 | { | |
203 | keyup(inst); | |
204 | } | |
205 | inst->lastkey = *inst->hal.keycode; | |
206 | } | |
207 | } | |
208 | ||
209 | ||
210 | int rtapi_app_main(void){ | |
211 | int i, j, n; | |
212 | int retval; | |
213 | comp_id = hal_init("matrix_kb"); | |
214 | if (comp_id < 0) { | |
215 | rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: ERROR: hal_init() failed\n"); | |
216 | return -1; | |
217 | } | |
218 | ||
219 | // allocate shared memory for data | |
220 | kb = hal_malloc(sizeof(kb_t)); | |
221 | if (kb == 0) { | |
222 | rtapi_print_msg(RTAPI_MSG_ERR, | |
223 | "matrix_kb component: Out of Memory\n"); | |
224 | hal_exit(comp_id); | |
225 | return -1; | |
226 | } | |
227 | ||
228 | // Count the instances. | |
229 | for (kb->num_insts = 0; config[kb->num_insts];kb->num_insts++); | |
230 | // Count the names. | |
231 | for (n = 0; names[n];n++); | |
232 | ||
233 | if (n && n != kb->num_insts){ | |
234 | rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: Number of sizes and number" | |
235 | " of names must match\n"); | |
236 | hal_exit(comp_id); | |
237 | return -1; | |
238 | } | |
239 | ||
240 | kb->insts = hal_malloc(kb->num_insts * sizeof(kb_inst_t)); | |
241 | ||
242 | for (i = 0; i < kb->num_insts; i++){ | |
243 | int a = 0; | |
244 | int c, r; | |
245 | kb_inst_t *inst = &kb->insts[i]; | |
246 | ||
247 | inst->index = i; | |
248 | inst->nrows = 0; | |
249 | inst->ncols = 0; | |
250 | inst->scan = 0; | |
251 | inst->keystroke = 0; | |
252 | inst->hal.keycode = 0; | |
253 | inst->lastkey = 0; | |
254 | inst->param.invert = 1; | |
255 | ||
256 | for(j = 0; config[i][j] !=0; j++){ | |
257 | int n = (config[i][j] | 0x20); //lower case | |
258 | if (n == 'x'){ | |
259 | inst->nrows = a; | |
260 | a = 0; | |
261 | } | |
262 | else if (n >= '0' && n <= '9'){ | |
263 | a = (a * 10) + (n - '0'); | |
264 | } | |
265 | else if (n == 's'){ | |
266 | inst->scan = 1; | |
267 | } | |
268 | else if (n == 'k'){ | |
269 | inst->keystroke = 1; | |
270 | } | |
271 | } | |
272 | inst->ncols = a; | |
273 | ||
274 | if (inst->ncols == 0 || inst->nrows == 0){ | |
275 | rtapi_print_msg(RTAPI_MSG_ERR, | |
276 | "matrix_kb: Invalid size format. should be NxN\n"); | |
277 | hal_exit(comp_id); | |
278 | return -1; | |
279 | } | |
280 | ||
281 | if (inst->ncols > 32){ | |
282 | rtapi_print_msg(RTAPI_MSG_ERR, | |
283 | "matrix_kb: maximum number of columns is 32. Sorry\n"); | |
284 | hal_exit(comp_id); | |
285 | return -1; | |
286 | } | |
287 | ||
288 | for (inst->rowshift = 1; inst->ncols > (1 << inst->rowshift); inst->rowshift++); | |
289 | for (inst->keydown = 0x40, inst->keyup = 0x80 | |
290 | ; (inst->nrows << inst->rowshift) > inst->keydown | |
291 | ; inst->keydown <<= 1, inst->keyup <<= 1); | |
292 | ||
293 | inst->hal.key = (hal_bit_t **)hal_malloc(inst->nrows * inst->ncols * sizeof(hal_bit_t*)); | |
294 | inst->param.code = hal_malloc(inst->nrows * inst->ncols * sizeof(inst->param.code)); | |
295 | inst->now = hal_malloc(inst->nrows * sizeof(hal_u32_t)); | |
296 | inst->then = hal_malloc(inst->nrows * sizeof(hal_u32_t)); | |
297 | inst->row = 0; | |
298 | inst->param.rollover = 2; | |
299 | ||
300 | ||
301 | if (names[i]){ | |
302 | rtapi_snprintf(inst->name, sizeof(inst->name), "%s", names[i]); | |
303 | } | |
304 | else | |
305 | { | |
306 | rtapi_snprintf(inst->name, sizeof(inst->name), "matrix_kb.%i", i); | |
307 | } | |
308 | ||
309 | for (c = 0; c < inst->ncols; c++){ | |
310 | for (r = 0; r < inst->nrows; r++){ | |
311 | retval = hal_pin_bit_newf(HAL_OUT, | |
312 | &(inst->hal.key[r * inst->ncols + c]), | |
313 | comp_id, | |
314 | "%s.key.r%xc%x", | |
315 | inst->name, r, c); | |
316 | if (retval != 0) { | |
317 | rtapi_print_msg(RTAPI_MSG_ERR, | |
318 | "matrix_kb: Failed to create output pin\n"); | |
319 | hal_exit(comp_id); | |
320 | return -1; | |
321 | } | |
322 | ||
323 | if (inst->keystroke){ | |
324 | retval = hal_param_u32_newf(HAL_RW, | |
325 | &inst->param.code[r * inst->ncols + c], | |
326 | comp_id, | |
327 | "%s.code.r%xc%x", | |
328 | inst->name, r, c); | |
329 | if (retval != 0) { | |
330 | rtapi_print_msg(RTAPI_MSG_ERR, | |
331 | "matrix_kb: Failed to create output pin\n"); | |
332 | hal_exit(comp_id); | |
333 | return -1; | |
334 | } | |
335 | } | |
336 | } | |
337 | } | |
338 | ||
339 | if (inst->scan){ //internally generated scanning | |
340 | inst->hal.rows = (hal_bit_t **)hal_malloc(inst->nrows * sizeof(hal_bit_t*)); | |
341 | inst->hal.cols = (hal_bit_t **)hal_malloc(inst->ncols * sizeof(hal_bit_t*)); | |
342 | ||
343 | for (r = 0; r < inst->nrows; r++){ | |
344 | retval = hal_pin_bit_newf(HAL_OUT, | |
345 | &(inst->hal.rows[r]), comp_id, | |
346 | "%s.row-%02i-out",inst->name, r); | |
347 | if (retval != 0) { | |
348 | rtapi_print_msg(RTAPI_MSG_ERR, | |
349 | "matrix_kb: Failed to create output row pin\n"); | |
350 | hal_exit(comp_id); | |
351 | return -1; | |
352 | } | |
353 | } | |
354 | for (c = 0; c < inst->ncols; c++){ | |
355 | retval = hal_pin_bit_newf(HAL_IN, | |
356 | &(inst->hal.cols[c]), comp_id, | |
357 | "%s.col-%02i-in",inst->name, c); | |
358 | if (retval != 0) { | |
359 | rtapi_print_msg(RTAPI_MSG_ERR, | |
360 | "matrix_kb: Failed to create input col pin\n"); | |
361 | hal_exit(comp_id); | |
362 | return -1; | |
363 | } | |
364 | } | |
365 | ||
366 | retval = hal_pin_u32_newf(HAL_OUT, | |
367 | &(inst->hal.keycode), comp_id, | |
368 | "%s.keycode",inst->name); | |
369 | if (retval != 0) { | |
370 | rtapi_print_msg(RTAPI_MSG_ERR, | |
371 | "matrix_kb: Failed to create output pin\n"); | |
372 | hal_exit(comp_id); | |
373 | return -1; | |
374 | } | |
375 | ||
376 | retval = hal_param_bit_newf(HAL_RW, | |
377 | &(inst->param.invert), comp_id, | |
378 | "%s.negative-logic",inst->name); | |
379 | if (retval != 0) { | |
380 | rtapi_print_msg(RTAPI_MSG_ERR, | |
381 | "matrix_kb: Failed to create output pin\n"); | |
382 | hal_exit(comp_id); | |
383 | return -1; | |
384 | } | |
385 | ||
386 | ||
387 | retval = hal_param_u32_newf(HAL_RW, | |
388 | &(inst->param.rollover), comp_id, | |
389 | "%s.key_rollover",inst->name); | |
390 | if (retval != 0) { | |
391 | rtapi_print_msg(RTAPI_MSG_ERR, | |
392 | "matrix_kb: Failed to create rollover param\n"); | |
393 | hal_exit(comp_id); | |
394 | return -1; | |
395 | } | |
396 | ||
397 | } | |
398 | else // scanning by 7i73 or similar | |
399 | { | |
400 | retval = hal_pin_u32_newf(HAL_IN, | |
401 | &(inst->hal.keycode), comp_id, | |
402 | "%s.keycode",inst->name); | |
403 | if (retval != 0) { | |
404 | rtapi_print_msg(RTAPI_MSG_ERR, | |
405 | "matrix_kb: Failed to create input pin\n"); | |
406 | hal_exit(comp_id); | |
407 | return -1; | |
408 | } | |
409 | } | |
410 | ||
411 | retval = hal_export_funct(inst->name, loop, inst, 1, 0, comp_id); //needs fp? | |
412 | if (retval < 0) { | |
413 | rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: ERROR: function export failed\n"); | |
414 | return -1; | |
415 | } | |
416 | ||
417 | if (inst->keystroke){ // keyboard output needed | |
418 | inst->key_dev = CREATE_KB_DEV; | |
419 | if (inst->key_dev <= 0) { | |
420 | rtapi_print_msg(RTAPI_MSG_ERR,"matrix_kb: failed to create dev\n"); | |
421 | return -1; | |
422 | } | |
423 | ||
424 | SETEVENT(inst->key_dev); | |
425 | for(j = 0; j < 226 ; j++){ | |
426 | SETKEY(inst->key_dev, j); | |
427 | } | |
428 | ||
429 | NAME_KB(inst->key_dev, inst->name); | |
430 | retval = REGISTER_KB(inst->key_dev); | |
431 | ||
432 | if (retval < 0) { | |
433 | rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: Failed to register device %i\n", retval); | |
434 | return -1; | |
435 | } | |
436 | } | |
437 | } | |
438 | hal_ready(comp_id); | |
439 | ||
440 | return 0; | |
441 | } | |
442 | ||
443 | void rtapi_app_exit(void) | |
444 | { | |
445 | hal_exit(comp_id); | |
446 | { | |
447 | int i; | |
448 | for (i = 0; i < kb->num_insts ; i++){ | |
449 | if (kb->insts[i].keystroke) UNLOAD_KB_DEV(kb->insts[i].key_dev); | |
450 | } | |
451 | } | |
452 | } |