/*
* QEMU ADB support
- *
+ *
* Copyright (c) 2004 Fabrice Bellard
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "vl.h"
+#include "hw.h"
+#include "ppc_mac.h"
+#include "console.h"
+
+/* debug ADB */
+//#define DEBUG_ADB
+
+#ifdef DEBUG_ADB
+#define ADB_DPRINTF(fmt, ...) \
+do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define ADB_DPRINTF(fmt, ...)
+#endif
/* ADB commands */
#define ADB_BUSRESET 0x00
#define ADB_MODEM 5
#define ADB_MISC 7
+/* error codes */
+#define ADB_RET_NOTPRESENT (-2)
+
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
{
ADBDevice *d;
int devaddr, cmd, i;
cmd = buf[0] & 0xf;
- devaddr = buf[0] >> 4;
- if (buf[1] == ADB_BUSRESET) {
- obuf[0] = 0x00;
- obuf[1] = 0x00;
- return 2;
- }
- if (cmd == ADB_FLUSH) {
- obuf[0] = 0x00;
- obuf[1] = 0x00;
- return 2;
+ if (cmd == ADB_BUSRESET) {
+ for(i = 0; i < s->nb_devices; i++) {
+ d = &s->devices[i];
+ if (d->devreset) {
+ d->devreset(d);
+ }
+ }
+ return 0;
}
-
+ devaddr = buf[0] >> 4;
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devaddr == devaddr) {
return d->devreq(d, obuf, buf, len);
}
}
- return 0;
+ return ADB_RET_NOTPRESENT;
}
+/* XXX: move that to cuda ? */
int adb_poll(ADBBusState *s, uint8_t *obuf)
{
ADBDevice *d;
int olen, i;
+ uint8_t buf[1];
olen = 0;
for(i = 0; i < s->nb_devices; i++) {
if (s->poll_index >= s->nb_devices)
s->poll_index = 0;
d = &s->devices[s->poll_index];
- olen = d->devreq(d, obuf, NULL, 0);
- s->poll_index++;
- if (olen)
+ buf[0] = ADB_READREG | (d->devaddr << 4);
+ olen = adb_request(s, obuf + 1, buf, 1);
+ /* if there is data, we poll again the same device */
+ if (olen > 0) {
+ obuf[0] = buf[0];
+ olen++;
break;
+ }
+ s->poll_index++;
}
return olen;
}
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
- ADBDeviceRequest *devreq,
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+ ADBDeviceRequest *devreq,
+ ADBDeviceReset *devreset,
void *opaque)
{
ADBDevice *d;
d->bus = s;
d->devaddr = devaddr;
d->devreq = devreq;
+ d->devreset = devreset;
d->opaque = opaque;
+ qemu_register_reset((QEMUResetHandler *)devreset, d);
+ d->devreset(d);
return d;
}
adb_keycode = pc_to_adb_keycode[keycode | 0x80];
else
adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
- obuf[0] = (d->devaddr << 4) | 0x0c;
- obuf[1] = adb_keycode | (keycode & 0x80);
- obuf[2] = 0xff;
- olen = 3;
+ obuf[0] = adb_keycode | (keycode & 0x80);
+ /* NOTE: could put a second keycode if needed */
+ obuf[1] = 0xff;
+ olen = 2;
ext_keycode = 0;
break;
}
static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
+ KBDState *s = d->opaque;
int cmd, reg, olen;
- if (!buf) {
- return adb_kbd_poll(d, obuf);
+ if ((buf[0] & 0x0f) == ADB_FLUSH) {
+ /* flush keyboard fifo */
+ s->wptr = s->rptr = s->count = 0;
+ return 0;
}
cmd = buf[0] & 0xc;
break;
case ADB_READREG:
switch(reg) {
+ case 0:
+ olen = adb_kbd_poll(d, obuf);
+ break;
case 1:
break;
case 2:
return olen;
}
+static void adb_kbd_save(QEMUFile *f, void *opaque)
+{
+ KBDState *s = (KBDState *)opaque;
+
+ qemu_put_buffer(f, s->data, sizeof(s->data));
+ qemu_put_sbe32s(f, &s->rptr);
+ qemu_put_sbe32s(f, &s->wptr);
+ qemu_put_sbe32s(f, &s->count);
+}
+
+static int adb_kbd_load(QEMUFile *f, void *opaque, int version_id)
+{
+ KBDState *s = (KBDState *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_buffer(f, s->data, sizeof(s->data));
+ qemu_get_sbe32s(f, &s->rptr);
+ qemu_get_sbe32s(f, &s->wptr);
+ qemu_get_sbe32s(f, &s->count);
+
+ return 0;
+}
+
+static int adb_kbd_reset(ADBDevice *d)
+{
+ KBDState *s = d->opaque;
+
+ d->handler = 1;
+ d->devaddr = ADB_KEYBOARD;
+ memset(s, 0, sizeof(KBDState));
+
+ return 0;
+}
+
void adb_kbd_init(ADBBusState *bus)
{
ADBDevice *d;
KBDState *s;
s = qemu_mallocz(sizeof(KBDState));
- d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, s);
- d->handler = 1;
+ d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
+ adb_kbd_reset, s);
qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
+ register_savevm("adb_kbd", -1, 1, adb_kbd_save,
+ adb_kbd_load, s);
}
/***************************************************************/
if (s->last_buttons_state == s->buttons_state &&
s->dx == 0 && s->dy == 0)
return 0;
-
+
dx = s->dx;
if (dx < -63)
dx = -63;
else if (dx > 63)
dx = 63;
-
+
dy = s->dy;
if (dy < -63)
dy = -63;
else if (dy > 63)
dy = 63;
-
+
s->dx -= dx;
s->dy -= dy;
s->last_buttons_state = s->buttons_state;
-
+
dx &= 0x7f;
dy &= 0x7f;
-
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+
+ if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
dy |= 0x80;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+ if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
dx |= 0x80;
-
- obuf[0] = (d->devaddr << 4) | 0x0c;
- obuf[1] = dy;
- obuf[2] = dx;
- return 3;
+
+ obuf[0] = dy;
+ obuf[1] = dx;
+ return 2;
}
static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
+ MouseState *s = d->opaque;
int cmd, reg, olen;
-
- if (!buf) {
- return adb_mouse_poll(d, obuf);
+
+ if ((buf[0] & 0x0f) == ADB_FLUSH) {
+ /* flush mouse fifo */
+ s->buttons_state = s->last_buttons_state;
+ s->dx = 0;
+ s->dy = 0;
+ s->dz = 0;
+ return 0;
}
cmd = buf[0] & 0xc;
olen = 0;
switch(cmd) {
case ADB_WRITEREG:
+ ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
switch(reg) {
case 2:
break;
break;
case ADB_READREG:
switch(reg) {
+ case 0:
+ olen = adb_mouse_poll(d, obuf);
+ break;
case 1:
break;
case 3:
olen = 2;
break;
}
+ ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
+ obuf[0], obuf[1]);
break;
}
return olen;
}
+static int adb_mouse_reset(ADBDevice *d)
+{
+ MouseState *s = d->opaque;
+
+ d->handler = 2;
+ d->devaddr = ADB_MOUSE;
+ memset(s, 0, sizeof(MouseState));
+
+ return 0;
+}
+
+static void adb_mouse_save(QEMUFile *f, void *opaque)
+{
+ MouseState *s = (MouseState *)opaque;
+
+ qemu_put_sbe32s(f, &s->buttons_state);
+ qemu_put_sbe32s(f, &s->last_buttons_state);
+ qemu_put_sbe32s(f, &s->dx);
+ qemu_put_sbe32s(f, &s->dy);
+ qemu_put_sbe32s(f, &s->dz);
+}
+
+static int adb_mouse_load(QEMUFile *f, void *opaque, int version_id)
+{
+ MouseState *s = (MouseState *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_sbe32s(f, &s->buttons_state);
+ qemu_get_sbe32s(f, &s->last_buttons_state);
+ qemu_get_sbe32s(f, &s->dx);
+ qemu_get_sbe32s(f, &s->dy);
+ qemu_get_sbe32s(f, &s->dz);
+
+ return 0;
+}
+
void adb_mouse_init(ADBBusState *bus)
{
ADBDevice *d;
MouseState *s;
s = qemu_mallocz(sizeof(MouseState));
- d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, s);
- d->handler = 2;
- qemu_add_mouse_event_handler(adb_mouse_event, d);
+ d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
+ adb_mouse_reset, s);
+ qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
+ register_savevm("adb_mouse", -1, 1, adb_mouse_save,
+ adb_mouse_load, s);
}