4 * Copyright (c) 2004 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
27 #define ADB_BUSRESET 0x00
28 #define ADB_FLUSH 0x01
29 #define ADB_WRITEREG 0x08
30 #define ADB_READREG 0x0c
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
38 /* ADB default device IDs (upper 4 bits of ADB command byte) */
40 #define ADB_KEYBOARD 2
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
55 static void adb_send_packet1(ADBBusState
*s
, uint8_t reply
)
57 adb_send_packet(s
, &reply
, 1);
60 void adb_receive_packet(ADBBusState
*s
, const uint8_t *buf
, int len
)
67 devaddr
= buf
[1] >> 4;
68 if (buf
[1] == ADB_BUSRESET
) {
71 adb_send_packet(s
, obuf
, 2);
74 if (cmd
== ADB_FLUSH
) {
77 adb_send_packet(s
, obuf
, 2);
81 for(i
= 0; i
< s
->nb_devices
; i
++) {
83 if (d
->devaddr
== devaddr
) {
84 d
->receive_packet(d
, buf
, len
);
88 adb_send_packet1(s
, ADB_RET_NOTPRESENT
);
91 ADBDevice
*adb_register_device(ADBBusState
*s
, int devaddr
,
92 ADBDeviceReceivePacket
*receive_packet
,
96 if (s
->nb_devices
>= MAX_ADB_DEVICES
)
98 d
= &s
->devices
[s
->nb_devices
++];
100 d
->devaddr
= devaddr
;
101 d
->receive_packet
= receive_packet
;
106 /***************************************************************/
107 /* Keyboard ADB device */
109 static 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,
128 static void adb_kbd_put_keycode(void *opaque
, int keycode
)
130 static int ext_keycode
;
131 ADBDevice
*d
= opaque
;
135 if (keycode
== 0xe0) {
140 adb_keycode
= pc_to_adb_keycode
[keycode
| 0x80];
142 adb_keycode
= pc_to_adb_keycode
[keycode
& 0x7f];
145 buf
[1] = (d
->devaddr
<< 4) | 0x0c;
146 buf
[2] = adb_keycode
| (keycode
& 0x80);
148 adb_send_packet(d
->bus
, buf
, 4);
153 static void adb_kbd_receive_packet(ADBDevice
*d
, const uint8_t *buf
, int len
)
165 adb_send_packet1(d
->bus
, ADB_RET_OK
);
169 case ADB_CMD_SELF_TEST
:
170 adb_send_packet1(d
->bus
, ADB_RET_OK
);
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
);
179 /* XXX: check this */
180 d
->devaddr
= buf
[1] & 0xf;
182 adb_send_packet1(d
->bus
, ADB_RET_OK
);
190 adb_send_packet1(d
->bus
, ADB_RET_OK
);
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);
199 obuf
[0] = ADB_RET_OK
;
200 obuf
[1] = d
->handler
;
201 obuf
[2] = d
->devaddr
;
202 adb_send_packet(d
->bus
, obuf
, 3);
209 void adb_kbd_init(ADBBusState
*bus
)
213 d
= adb_register_device(bus
, ADB_KEYBOARD
, adb_kbd_receive_packet
, NULL
);
214 qemu_add_kbd_event_handler(adb_kbd_put_keycode
, d
);
217 /***************************************************************/
218 /* Mouse ADB device */
220 static void adb_mouse_event(void *opaque
,
221 int dx1
, int dy1
, int dz1
, int buttons_state
)
223 ADBDevice
*d
= opaque
;
242 if (buttons_state
& MOUSE_EVENT_LBUTTON
)
244 if (buttons_state
& MOUSE_EVENT_RBUTTON
)
248 buf
[1] = (d
->devaddr
<< 4) | 0x0c;
251 adb_send_packet(d
->bus
, buf
, 4);
254 static void adb_mouse_receive_packet(ADBDevice
*d
, const uint8_t *buf
, int len
)
265 adb_send_packet1(d
->bus
, ADB_RET_OK
);
269 case ADB_CMD_SELF_TEST
:
270 adb_send_packet1(d
->bus
, ADB_RET_OK
);
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
);
279 /* XXX: check this */
280 d
->devaddr
= buf
[1] & 0xf;
281 adb_send_packet1(d
->bus
, ADB_RET_OK
);
289 adb_send_packet1(d
->bus
, ADB_RET_OK
);
292 obuf
[0] = ADB_RET_OK
;
293 obuf
[1] = d
->handler
;
294 obuf
[2] = d
->devaddr
;
295 adb_send_packet(d
->bus
, obuf
, 3);
302 void adb_mouse_init(ADBBusState
*bus
)
306 d
= adb_register_device(bus
, ADB_MOUSE
, adb_mouse_receive_packet
, NULL
);
307 qemu_add_mouse_event_handler(adb_mouse_event
, d
);