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
26 #include "ui/console.h"
32 #define ADB_DPRINTF(fmt, ...) \
33 do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
35 #define ADB_DPRINTF(fmt, ...)
39 #define ADB_BUSRESET 0x00
40 #define ADB_FLUSH 0x01
41 #define ADB_WRITEREG 0x08
42 #define ADB_READREG 0x0c
44 /* ADB device commands */
45 #define ADB_CMD_SELF_TEST 0xff
46 #define ADB_CMD_CHANGE_ID 0xfe
47 #define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
48 #define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
50 /* ADB default device IDs (upper 4 bits of ADB command byte) */
52 #define ADB_KEYBOARD 2
59 #define ADB_RET_NOTPRESENT (-2)
61 int adb_request(ADBBusState
*s
, uint8_t *obuf
, const uint8_t *buf
, int len
)
67 if (cmd
== ADB_BUSRESET
) {
68 for(i
= 0; i
< s
->nb_devices
; i
++) {
76 devaddr
= buf
[0] >> 4;
77 for(i
= 0; i
< s
->nb_devices
; i
++) {
79 if (d
->devaddr
== devaddr
) {
80 return d
->devreq(d
, obuf
, buf
, len
);
83 return ADB_RET_NOTPRESENT
;
86 /* XXX: move that to cuda ? */
87 int adb_poll(ADBBusState
*s
, uint8_t *obuf
)
94 for(i
= 0; i
< s
->nb_devices
; i
++) {
95 if (s
->poll_index
>= s
->nb_devices
)
97 d
= &s
->devices
[s
->poll_index
];
98 buf
[0] = ADB_READREG
| (d
->devaddr
<< 4);
99 olen
= adb_request(s
, obuf
+ 1, buf
, 1);
100 /* if there is data, we poll again the same device */
111 static ADBDevice
*adb_register_device(ADBBusState
*s
, int devaddr
,
112 ADBDeviceRequest
*devreq
,
113 ADBDeviceReset
*devreset
,
117 if (s
->nb_devices
>= MAX_ADB_DEVICES
)
119 d
= &s
->devices
[s
->nb_devices
++];
121 d
->devaddr
= devaddr
;
123 d
->devreset
= devreset
;
125 qemu_register_reset((QEMUResetHandler
*)devreset
, d
);
129 /***************************************************************/
130 /* Keyboard ADB device */
132 typedef struct KBDState
{
134 int rptr
, wptr
, count
;
137 static const uint8_t pc_to_adb_keycode
[256] = {
138 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
139 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1,
140 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
141 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
142 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
143 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0,
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
146 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0,
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0,
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0,
149 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0,
150 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119,
151 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0,
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
156 static void adb_kbd_put_keycode(void *opaque
, int keycode
)
158 ADBDevice
*d
= opaque
;
159 KBDState
*s
= d
->opaque
;
161 if (s
->count
< sizeof(s
->data
)) {
162 s
->data
[s
->wptr
] = keycode
;
163 if (++s
->wptr
== sizeof(s
->data
))
169 static int adb_kbd_poll(ADBDevice
*d
, uint8_t *obuf
)
171 static int ext_keycode
;
172 KBDState
*s
= d
->opaque
;
173 int adb_keycode
, keycode
;
180 keycode
= s
->data
[s
->rptr
];
181 if (++s
->rptr
== sizeof(s
->data
))
185 if (keycode
== 0xe0) {
189 adb_keycode
= pc_to_adb_keycode
[keycode
| 0x80];
191 adb_keycode
= pc_to_adb_keycode
[keycode
& 0x7f];
192 obuf
[0] = adb_keycode
| (keycode
& 0x80);
193 /* NOTE: could put a second keycode if needed */
203 static int adb_kbd_request(ADBDevice
*d
, uint8_t *obuf
,
204 const uint8_t *buf
, int len
)
206 KBDState
*s
= d
->opaque
;
209 if ((buf
[0] & 0x0f) == ADB_FLUSH
) {
210 /* flush keyboard fifo */
211 s
->wptr
= s
->rptr
= s
->count
= 0;
226 case ADB_CMD_SELF_TEST
:
228 case ADB_CMD_CHANGE_ID
:
229 case ADB_CMD_CHANGE_ID_AND_ACT
:
230 case ADB_CMD_CHANGE_ID_AND_ENABLE
:
231 d
->devaddr
= buf
[1] & 0xf;
234 /* XXX: check this */
235 d
->devaddr
= buf
[1] & 0xf;
244 olen
= adb_kbd_poll(d
, obuf
);
249 obuf
[0] = 0x00; /* XXX: check this */
250 obuf
[1] = 0x07; /* led status */
254 obuf
[0] = d
->handler
;
255 obuf
[1] = d
->devaddr
;
264 static const VMStateDescription vmstate_adb_kbd
= {
267 .minimum_version_id
= 1,
268 .minimum_version_id_old
= 1,
269 .fields
= (VMStateField
[]) {
270 VMSTATE_BUFFER(data
, KBDState
),
271 VMSTATE_INT32(rptr
, KBDState
),
272 VMSTATE_INT32(wptr
, KBDState
),
273 VMSTATE_INT32(count
, KBDState
),
274 VMSTATE_END_OF_LIST()
278 static int adb_kbd_reset(ADBDevice
*d
)
280 KBDState
*s
= d
->opaque
;
283 d
->devaddr
= ADB_KEYBOARD
;
284 memset(s
, 0, sizeof(KBDState
));
289 void adb_kbd_init(ADBBusState
*bus
)
293 s
= g_malloc0(sizeof(KBDState
));
294 d
= adb_register_device(bus
, ADB_KEYBOARD
, adb_kbd_request
,
296 qemu_add_kbd_event_handler(adb_kbd_put_keycode
, d
);
297 vmstate_register(NULL
, -1, &vmstate_adb_kbd
, s
);
300 /***************************************************************/
301 /* Mouse ADB device */
303 typedef struct MouseState
{
304 int buttons_state
, last_buttons_state
;
308 static void adb_mouse_event(void *opaque
,
309 int dx1
, int dy1
, int dz1
, int buttons_state
)
311 ADBDevice
*d
= opaque
;
312 MouseState
*s
= d
->opaque
;
317 s
->buttons_state
= buttons_state
;
321 static int adb_mouse_poll(ADBDevice
*d
, uint8_t *obuf
)
323 MouseState
*s
= d
->opaque
;
326 if (s
->last_buttons_state
== s
->buttons_state
&&
327 s
->dx
== 0 && s
->dy
== 0)
344 s
->last_buttons_state
= s
->buttons_state
;
349 if (!(s
->buttons_state
& MOUSE_EVENT_LBUTTON
))
351 if (!(s
->buttons_state
& MOUSE_EVENT_RBUTTON
))
359 static int adb_mouse_request(ADBDevice
*d
, uint8_t *obuf
,
360 const uint8_t *buf
, int len
)
362 MouseState
*s
= d
->opaque
;
365 if ((buf
[0] & 0x0f) == ADB_FLUSH
) {
366 /* flush mouse fifo */
367 s
->buttons_state
= s
->last_buttons_state
;
379 ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg
, buf
[1]);
385 case ADB_CMD_SELF_TEST
:
387 case ADB_CMD_CHANGE_ID
:
388 case ADB_CMD_CHANGE_ID_AND_ACT
:
389 case ADB_CMD_CHANGE_ID_AND_ENABLE
:
390 d
->devaddr
= buf
[1] & 0xf;
393 /* XXX: check this */
394 d
->devaddr
= buf
[1] & 0xf;
402 olen
= adb_mouse_poll(d
, obuf
);
407 obuf
[0] = d
->handler
;
408 obuf
[1] = d
->devaddr
;
412 ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg
,
419 static int adb_mouse_reset(ADBDevice
*d
)
421 MouseState
*s
= d
->opaque
;
424 d
->devaddr
= ADB_MOUSE
;
425 memset(s
, 0, sizeof(MouseState
));
430 static const VMStateDescription vmstate_adb_mouse
= {
433 .minimum_version_id
= 1,
434 .minimum_version_id_old
= 1,
435 .fields
= (VMStateField
[]) {
436 VMSTATE_INT32(buttons_state
, MouseState
),
437 VMSTATE_INT32(last_buttons_state
, MouseState
),
438 VMSTATE_INT32(dx
, MouseState
),
439 VMSTATE_INT32(dy
, MouseState
),
440 VMSTATE_INT32(dz
, MouseState
),
441 VMSTATE_END_OF_LIST()
445 void adb_mouse_init(ADBBusState
*bus
)
450 s
= g_malloc0(sizeof(MouseState
));
451 d
= adb_register_device(bus
, ADB_MOUSE
, adb_mouse_request
,
453 qemu_add_mouse_event_handler(adb_mouse_event
, d
, 0, "QEMU ADB Mouse");
454 vmstate_register(NULL
, -1, &vmstate_adb_mouse
, s
);