cleanup warnings in gcc, fixed some hw module cleanup routines
[dcpu16] / hw_keyboard.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #ifdef HAVE_LIBVNCSERVER
6 #include <rfb/rfb.h>
7 #include <rfb/keysym.h>
8 #endif /* HAVE_LIBVNCSERVER */
9
10 #include "dcpu16.h"
11 #include "hw_keyboard.h"
12
13 #define BUF_SZ 32
14
15 #ifdef WANT_VARIADIC_VOIDP_CAST
16 #define VOIDP(__x__) ((void *)(__x__))
17 #else
18 #define VOIDP(__x__) (__x__)
19 #endif
20
21 static dcpu16_hw_signal_t keyboard_reset_;
22 static dcpu16_hw_signal_t keyboard_cycle_;
23 static dcpu16_hw_signal_t keyboard_hwi_;
24 static struct dcpu16_hw hw_ = {
25 .vm = NULL,
26 .name_ = "Generic Keyboard (compatible)",
27 .id_l = 0x7406,
28 .id_h = 0x30cf,
29 .ver = 0x0001,
30 .mfg_l = 0x0000,
31 .mfg_h = 0x0000,
32 .hwi = keyboard_hwi_,
33 .cycle = keyboard_cycle_,
34 .reset = keyboard_reset_,
35 .data = (struct keyboard_ *)NULL
36 };
37
38 struct keyboard_ {
39 char *buf;
40 size_t buf_sz;
41 size_t buf_head;
42 size_t buf_tail;
43 DCPU16_WORD interrupt_message;
44 unsigned char keys_pressed[256];
45 };
46
47 #ifdef HAVE_LIBVNCSERVER
48
49 static const struct keysym_map_ {
50 unsigned int rfb_start;
51 unsigned int rfb_end;
52 DCPU16_WORD dcpu_start;
53 } keymap_[] = {
54 { XK_space, XK_asciitilde, 0x20 }, /* ASCII range */
55 { XK_Delete, XK_Delete, 0x7f }, /* ASCII del */
56 { XK_BackSpace, XK_BackSpace, 0x10 }, /* bs */
57 { XK_Return, XK_Return, 0x11 }, /* ret */
58 { XK_Insert, XK_Insert, 0x12 }, /* ins */
59 { XK_Delete, XK_Delete, 0x13 }, /* del */
60 { XK_Up, XK_Up, 0x80 }, /* arrow up */
61 { XK_Down, XK_Down, 0x81 }, /* arrow down */
62 { XK_Left, XK_Left, 0x82 }, /* arrow left */
63 { XK_Right, XK_Right, 0x83 }, /* arrow right */
64 { XK_Shift_L, XK_Shift_R, 0x90 }, /* shift range */
65 { XK_Control_L, XK_Control_R, 0x91 }, /* control range */
66 { 0, 0, 0x0 }
67 };
68
69 static int keysym_rfbtodcpu(unsigned int rfb, DCPU16_WORD *dcpu) {
70 const struct keysym_map_ *map;
71
72 for (map = keymap_; map->rfb_start; map++) {
73 if (rfb >= map->rfb_start
74 && rfb <= map->rfb_end) {
75 *dcpu = (map->dcpu_start + (rfb - map->rfb_start));
76 return 0;
77 }
78 }
79
80 *dcpu = 0x00;
81 return -1;
82 }
83
84 static
85 void keyboard_rfbevent_(rfbBool down, rfbKeySym key, rfbClientPtr cl) {
86 DCPU16_WORD dcpu_key;
87 struct dcpu16_hw *hw = (struct dcpu16_hw *)cl->screen->screenData;
88 struct keyboard_ *keyboard = (struct keyboard_ *)hw->data;
89
90 keysym_rfbtodcpu(key, &dcpu_key);
91
92 fprintf(stderr, "%s: down:%u key:0x%04x dcpu_key:0x%04x\n",
93 __func__,
94 down,
95 key,
96 dcpu_key);
97
98 fprintf(stderr, "%s: hw:%p name:%s vm:%p\n",
99 __func__,
100 VOIDP(hw),
101 hw->name_,
102 VOIDP(hw->vm));
103
104 keyboard->keys_pressed[dcpu_key] = (down ? 1 : 0);
105 if (down) {
106 if ((keyboard->buf_tail + 1) % keyboard->buf_sz == keyboard->buf_head) {
107 hw->vm->warn_cb_("keyboard buffer overflow");
108 return;
109 }
110 keyboard->buf[keyboard->buf_tail] = dcpu_key;
111 keyboard->buf_tail += 1;
112 keyboard->buf_tail %= keyboard->buf_sz;
113 }
114 if (keyboard->interrupt_message) {
115 dcpu16_interrupt(hw->vm, keyboard->interrupt_message);
116 }
117 }
118
119 void keyboard_vnc_associate(struct dcpu16_hw *hw, rfbScreenInfoPtr rfbScreen) {
120 rfbScreen->screenData = hw;
121 rfbScreen->kbdAddEvent = keyboard_rfbevent_;
122 }
123 #endif /* HAVE_LIBVNCSERVER */
124
125 static
126 void keyboard_reset_(struct dcpu16 *vm, void *data) {
127 struct keyboard_ *keyboard = (struct keyboard_ *)data;
128
129 (void)vm;
130
131 keyboard->interrupt_message = 0;
132 memset(keyboard->buf, 0, keyboard->buf_sz);
133 }
134
135 static
136 void keyboard_cycle_(struct dcpu16 *vm, void *data) {
137 struct keyboard_ *keyboard = (struct keyboard_ *)data;
138
139 (void)vm, (void)keyboard;
140 }
141
142 static
143 void keyboard_hwi_(struct dcpu16 *vm, void *data) {
144 struct keyboard_ *keyboard = (struct keyboard_ *)data;
145 DCPU16_WORD reg_a = vm->reg[DCPU16_REG_A];
146 DCPU16_WORD reg_b = vm->reg[DCPU16_REG_B];
147
148 switch (reg_a) {
149 case 0: /* clear keyboard buffer */
150 memset(keyboard->buf, 0, keyboard->buf_sz);
151 keyboard->buf_head = 0;
152 keyboard->buf_tail = 0;
153 break;
154
155 case 1: /* get next key from buffer as C */
156 if (keyboard->buf_head == keyboard->buf_tail)
157 break;
158 vm->reg[DCPU16_REG_C] = keyboard->buf[keyboard->buf_head];
159 keyboard->buf_head += 1;
160 keyboard->buf_head %= keyboard->buf_sz;
161 break;
162
163 case 2: /* get currently-pressed-state of key in B as C */
164 vm->reg[DCPU16_REG_C] = keyboard->keys_pressed[reg_b & 0x00ff];
165 break;
166
167 case 3: /* set interrupt state */
168 keyboard->interrupt_message = reg_b;
169 break;
170
171 }
172 }
173
174 struct dcpu16_hw *keyboard_new(struct dcpu16 *vm) {
175 struct dcpu16_hw *hw;
176 char *b;
177
178 hw = calloc(1, sizeof *hw);
179 if (hw == NULL) {
180 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
181 return NULL;
182 }
183 memcpy(hw, &hw_, sizeof *hw);
184 hw->data = calloc(1, sizeof hw->data);
185 if (hw->data == NULL) {
186 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
187 free(hw);
188 return NULL;
189 }
190
191 b = calloc(BUF_SZ, sizeof *b);
192 if (b == NULL) {
193 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
194 free(hw->data);
195 free(hw);
196 return NULL;
197 }
198 ((struct keyboard_ *)(hw->data))->buf = b;
199 ((struct keyboard_ *)(hw->data))->buf_sz = BUF_SZ;
200
201 hw->vm = vm;
202
203 return hw;
204 }
205
206 void keyboard_del(struct dcpu16_hw **hw) {
207 if (hw) {
208 if (*hw) {
209 if ((*hw)->data) {
210 free(((struct keyboard_ *)((*hw)->data))->buf);
211 ((struct keyboard_ *)((*hw)->data))->buf = NULL;
212
213 free((*hw)->data);
214 (*hw)->data = NULL;
215 }
216 free(*hw);
217 *hw = NULL;
218 }
219 }
220 }