]> git.proxmox.com Git - qemu.git/blame - hw/adb.c
avoid using anonymous struct extension (not supported by all gcc 3.x)
[qemu.git] / hw / adb.c
CommitLineData
267002cd
FB
1/*
2 * QEMU ADB support
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "vl.h"
25
26/* ADB commands */
27#define ADB_BUSRESET 0x00
28#define ADB_FLUSH 0x01
29#define ADB_WRITEREG 0x08
30#define ADB_READREG 0x0c
31
32/* ADB device commands */
33#define ADB_CMD_SELF_TEST 0xff
34#define ADB_CMD_CHANGE_ID 0xfe
35#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
36#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
37
38/* ADB default device IDs (upper 4 bits of ADB command byte) */
39#define ADB_DONGLE 1
40#define ADB_KEYBOARD 2
41#define ADB_MOUSE 3
42#define ADB_TABLET 4
43#define ADB_MODEM 5
44#define ADB_MISC 7
45
46#define ADB_RET_OK 0
47#define ADB_RET_INUSE 1
48#define ADB_RET_NOTPRESENT 2
49#define ADB_RET_TIMEOUT 3
50#define ADB_RET_UNEXPECTED_RESULT 4
51#define ADB_RET_REQUEST_ERROR 5
52#define ADB_RET_BUS_ERROR 6
53
54
55static void adb_send_packet1(ADBBusState *s, uint8_t reply)
56{
57 adb_send_packet(s, &reply, 1);
58}
59
60void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len)
61{
62 ADBDevice *d;
63 int devaddr, cmd, i;
64 uint8_t obuf[4];
65
66 cmd = buf[1] & 0xf;
67 devaddr = buf[1] >> 4;
68 if (buf[1] == ADB_BUSRESET) {
69 obuf[0] = 0x00;
70 obuf[1] = 0x00;
71 adb_send_packet(s, obuf, 2);
72 return;
73 }
74 if (cmd == ADB_FLUSH) {
75 obuf[0] = 0x00;
76 obuf[1] = 0x00;
77 adb_send_packet(s, obuf, 2);
78 return;
79 }
80
81 for(i = 0; i < s->nb_devices; i++) {
82 d = &s->devices[i];
83 if (d->devaddr == devaddr) {
84 d->receive_packet(d, buf, len);
85 return;
86 }
87 }
88 adb_send_packet1(s, ADB_RET_NOTPRESENT);
89}
90
91ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
92 ADBDeviceReceivePacket *receive_packet,
93 void *opaque)
94{
95 ADBDevice *d;
96 if (s->nb_devices >= MAX_ADB_DEVICES)
97 return NULL;
98 d = &s->devices[s->nb_devices++];
99 d->bus = s;
100 d->devaddr = devaddr;
101 d->receive_packet = receive_packet;
102 d->opaque = opaque;
103 return d;
104}
105
106/***************************************************************/
107/* Keyboard ADB device */
108
109static const uint8_t pc_to_adb_keycode[256] = {
110 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
111 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1,
112 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
113 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
114 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
115 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0,
116 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117,
117 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102,
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126};
127
128static void adb_kbd_put_keycode(void *opaque, int keycode)
129{
130 static int ext_keycode;
131 ADBDevice *d = opaque;
132 uint8_t buf[4];
133 int adb_keycode;
134
135 if (keycode == 0xe0) {
136 ext_keycode = 1;
137 } else {
138
139 if (ext_keycode)
140 adb_keycode = pc_to_adb_keycode[keycode | 0x80];
141 else
142 adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
143
144 buf[0] = 0x40;
145 buf[1] = (d->devaddr << 4) | 0x0c;
146 buf[2] = adb_keycode | (keycode & 0x80);
147 buf[3] = 0xff;
148 adb_send_packet(d->bus, buf, 4);
149 ext_keycode = 0;
150 }
151}
152
153static void adb_kbd_receive_packet(ADBDevice *d, const uint8_t *buf, int len)
154{
155 int cmd, reg;
156 uint8_t obuf[4];
157
158 cmd = buf[0] & 0xc;
159 reg = buf[0] & 0x3;
160 switch(cmd) {
161 case ADB_WRITEREG:
162 switch(reg) {
163 case 2:
164 /* LED status */
165 adb_send_packet1(d->bus, ADB_RET_OK);
166 break;
167 case 3:
168 switch(buf[2]) {
169 case ADB_CMD_SELF_TEST:
170 adb_send_packet1(d->bus, ADB_RET_OK);
171 break;
172 case ADB_CMD_CHANGE_ID:
173 case ADB_CMD_CHANGE_ID_AND_ACT:
174 case ADB_CMD_CHANGE_ID_AND_ENABLE:
175 d->devaddr = buf[1] & 0xf;
176 adb_send_packet1(d->bus, ADB_RET_OK);
177 break;
178 default:
179 /* XXX: check this */
180 d->devaddr = buf[1] & 0xf;
181 d->handler = buf[2];
182 adb_send_packet1(d->bus, ADB_RET_OK);
183 break;
184 }
185 }
186 break;
187 case ADB_READREG:
188 switch(reg) {
189 case 1:
190 adb_send_packet1(d->bus, ADB_RET_OK);
191 break;
192 case 2:
193 obuf[0] = ADB_RET_OK;
194 obuf[1] = 0x00; /* XXX: check this */
195 obuf[2] = 0x07; /* led status */
196 adb_send_packet(d->bus, obuf, 3);
197 break;
198 case 3:
199 obuf[0] = ADB_RET_OK;
200 obuf[1] = d->handler;
201 obuf[2] = d->devaddr;
202 adb_send_packet(d->bus, obuf, 3);
203 break;
204 }
205 break;
206 }
207}
208
209void adb_kbd_init(ADBBusState *bus)
210{
211 ADBDevice *d;
212
213 d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_receive_packet, NULL);
214 qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
215}
216
217/***************************************************************/
218/* Mouse ADB device */
219
220static void adb_mouse_event(void *opaque,
221 int dx1, int dy1, int dz1, int buttons_state)
222{
223 ADBDevice *d = opaque;
224 uint8_t buf[4];
225 int dx, dy;
226
227 dx = dx1;
228 if (dx < -63)
229 dx = -63;
230 else if (dx > 63)
231 dx = 63;
232
233 dy = dy1;
234 if (dy < -63)
235 dy = -63;
236 else if (dy > 63)
237 dy = 63;
238
239 dx &= 0x7f;
240 dy &= 0x7f;
241
242 if (buttons_state & MOUSE_EVENT_LBUTTON)
243 dy |= 0x80;
244 if (buttons_state & MOUSE_EVENT_RBUTTON)
245 dx |= 0x80;
246
247 buf[0] = 0x40;
248 buf[1] = (d->devaddr << 4) | 0x0c;
249 buf[2] = dy;
250 buf[3] = dx;
251 adb_send_packet(d->bus, buf, 4);
252}
253
254static void adb_mouse_receive_packet(ADBDevice *d, const uint8_t *buf, int len)
255{
256 int cmd, reg;
257 uint8_t obuf[4];
258
259 cmd = buf[0] & 0xc;
260 reg = buf[0] & 0x3;
261 switch(cmd) {
262 case ADB_WRITEREG:
263 switch(reg) {
264 case 2:
265 adb_send_packet1(d->bus, ADB_RET_OK);
266 break;
267 case 3:
268 switch(buf[2]) {
269 case ADB_CMD_SELF_TEST:
270 adb_send_packet1(d->bus, ADB_RET_OK);
271 break;
272 case ADB_CMD_CHANGE_ID:
273 case ADB_CMD_CHANGE_ID_AND_ACT:
274 case ADB_CMD_CHANGE_ID_AND_ENABLE:
275 d->devaddr = buf[1] & 0xf;
276 adb_send_packet1(d->bus, ADB_RET_OK);
277 break;
278 default:
279 /* XXX: check this */
280 d->devaddr = buf[1] & 0xf;
281 adb_send_packet1(d->bus, ADB_RET_OK);
282 break;
283 }
284 }
285 break;
286 case ADB_READREG:
287 switch(reg) {
288 case 1:
289 adb_send_packet1(d->bus, ADB_RET_OK);
290 break;
291 case 3:
292 obuf[0] = ADB_RET_OK;
293 obuf[1] = d->handler;
294 obuf[2] = d->devaddr;
295 adb_send_packet(d->bus, obuf, 3);
296 break;
297 }
298 break;
299 }
300}
301
302void adb_mouse_init(ADBBusState *bus)
303{
304 ADBDevice *d;
305
306 d = adb_register_device(bus, ADB_MOUSE, adb_mouse_receive_packet, NULL);
307 qemu_add_mouse_event_handler(adb_mouse_event, d);
308}