aboutsummaryrefslogtreecommitdiff
path: root/hw/misc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/misc')
-rw-r--r--hw/misc/mac_via.c411
-rw-r--r--hw/misc/macio/cuda.c60
-rw-r--r--hw/misc/macio/pmu.c47
-rw-r--r--hw/misc/trace-events3
4 files changed, 320 insertions, 201 deletions
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index 9cd313c..d76d7b2 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -599,179 +599,310 @@ static void via1_rtc_update(MacVIAState *m)
m->cmd = REG_EMPTY;
}
-static int adb_via_poll(MacVIAState *s, int state, uint8_t *data)
+static void adb_via_poll(void *opaque)
{
- if (state != ADB_STATE_IDLE) {
- return 0;
- }
+ MacVIAState *m = opaque;
+ MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1);
+ MOS6522State *s = MOS6522(v1s);
+ ADBBusState *adb_bus = &m->adb_bus;
+ uint8_t obuf[9];
+ uint8_t *data = &s->sr;
+ int olen;
+ uint16_t pending;
- if (s->adb_data_in_size < s->adb_data_in_index) {
- return 0;
- }
+ /*
+ * Setting vADBInt below indicates that an autopoll reply has been
+ * received, however we must block autopoll until the point where
+ * the entire reply has been read back to the host
+ */
+ adb_autopoll_block(adb_bus);
+
+ m->adb_data_in_index = 0;
+ m->adb_data_out_index = 0;
+ olen = adb_poll(adb_bus, obuf, adb_bus->autopoll_mask);
+
+ if (olen > 0) {
+ /* Autopoll response */
+ *data = obuf[0];
+ olen--;
+ memcpy(m->adb_data_in, &obuf[1], olen);
+ m->adb_data_in_size = olen;
+
+ s->b &= ~VIA1B_vADBInt;
+ qemu_irq_raise(m->adb_data_ready);
+ } else if (olen < 0) {
+ /* Bus timeout (device does not exist) */
+ *data = 0xff;
+ s->b |= VIA1B_vADBInt;
+ adb_autopoll_unblock(adb_bus);
+ } else {
+ pending = adb_bus->pending & ~(1 << (m->adb_autopoll_cmd >> 4));
+
+ if (pending) {
+ /*
+ * Bus timeout (device exists but another device has data). Block
+ * autopoll so the OS can read out the first EVEN and first ODD
+ * byte to determine bus timeout and SRQ status
+ */
+ *data = m->adb_autopoll_cmd;
+ s->b &= ~VIA1B_vADBInt;
- if (s->adb_data_out_index != 0) {
- return 0;
- }
+ obuf[0] = 0xff;
+ obuf[1] = 0xff;
+ olen = 2;
- s->adb_data_in_index = 0;
- s->adb_data_out_index = 0;
- s->adb_data_in_size = adb_poll(&s->adb_bus, s->adb_data_in, 0xffff);
+ memcpy(m->adb_data_in, obuf, olen);
+ m->adb_data_in_size = olen;
- if (s->adb_data_in_size) {
- *data = s->adb_data_in[s->adb_data_in_index++];
- qemu_irq_raise(s->adb_data_ready);
+ qemu_irq_raise(m->adb_data_ready);
+ } else {
+ /* Bus timeout (device exists but no other device has data) */
+ *data = 0;
+ s->b |= VIA1B_vADBInt;
+ adb_autopoll_unblock(adb_bus);
+ }
}
- return s->adb_data_in_size;
+ trace_via1_adb_poll(*data, (s->b & VIA1B_vADBInt) ? "+" : "-",
+ adb_bus->status, m->adb_data_in_index, olen);
}
-static int adb_via_send(MacVIAState *s, int state, uint8_t data)
+static int adb_via_send_len(uint8_t data)
{
- switch (state) {
- case ADB_STATE_NEW:
- s->adb_data_out_index = 0;
- break;
- case ADB_STATE_EVEN:
- if ((s->adb_data_out_index & 1) == 0) {
- return 0;
- }
- break;
- case ADB_STATE_ODD:
- if (s->adb_data_out_index & 1) {
- return 0;
+ /* Determine the send length from the given ADB command */
+ uint8_t cmd = data & 0xc;
+ uint8_t reg = data & 0x3;
+
+ switch (cmd) {
+ case 0x8:
+ /* Listen command */
+ switch (reg) {
+ case 2:
+ /* Register 2 is only used for the keyboard */
+ return 3;
+ case 3:
+ /*
+ * Fortunately our devices only implement writes
+ * to register 3 which is fixed at 2 bytes
+ */
+ return 3;
+ default:
+ qemu_log_mask(LOG_UNIMP, "ADB unknown length for register %d\n",
+ reg);
+ return 1;
}
- break;
- case ADB_STATE_IDLE:
- return 0;
+ default:
+ /* Talk, BusReset */
+ return 1;
}
-
- assert(s->adb_data_out_index < sizeof(s->adb_data_out) - 1);
-
- s->adb_data_out[s->adb_data_out_index++] = data;
- qemu_irq_raise(s->adb_data_ready);
- return 1;
}
-static int adb_via_receive(MacVIAState *s, int state, uint8_t *data)
+static void adb_via_send(MacVIAState *s, int state, uint8_t data)
{
+ MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&s->mos6522_via1);
+ MOS6522State *ms = MOS6522(v1s);
+ ADBBusState *adb_bus = &s->adb_bus;
+ uint16_t autopoll_mask;
+
switch (state) {
case ADB_STATE_NEW:
- return 0;
-
- case ADB_STATE_EVEN:
- if (s->adb_data_in_size <= 0) {
- qemu_irq_raise(s->adb_data_ready);
- return 0;
- }
-
- if (s->adb_data_in_index >= s->adb_data_in_size) {
- *data = 0;
- qemu_irq_raise(s->adb_data_ready);
- return 1;
- }
-
- if ((s->adb_data_in_index & 1) == 0) {
- return 0;
+ /*
+ * Command byte: vADBInt tells host autopoll data already present
+ * in VIA shift register and ADB transceiver
+ */
+ adb_autopoll_block(adb_bus);
+
+ if (adb_bus->status & ADB_STATUS_POLLREPLY) {
+ /* Tell the host the existing data is from autopoll */
+ ms->b &= ~VIA1B_vADBInt;
+ } else {
+ ms->b |= VIA1B_vADBInt;
+ s->adb_data_out_index = 0;
+ s->adb_data_out[s->adb_data_out_index++] = data;
}
+ trace_via1_adb_send(" NEW", data, (ms->b & VIA1B_vADBInt) ? "+" : "-");
+ qemu_irq_raise(s->adb_data_ready);
break;
+ case ADB_STATE_EVEN:
case ADB_STATE_ODD:
- if (s->adb_data_in_size <= 0) {
- qemu_irq_raise(s->adb_data_ready);
- return 0;
- }
-
- if (s->adb_data_in_index >= s->adb_data_in_size) {
- *data = 0;
- qemu_irq_raise(s->adb_data_ready);
- return 1;
- }
-
- if (s->adb_data_in_index & 1) {
- return 0;
- }
+ ms->b |= VIA1B_vADBInt;
+ s->adb_data_out[s->adb_data_out_index++] = data;
+ trace_via1_adb_send(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
+ data, (ms->b & VIA1B_vADBInt) ? "+" : "-");
+ qemu_irq_raise(s->adb_data_ready);
break;
case ADB_STATE_IDLE:
- if (s->adb_data_out_index == 0) {
- return 0;
- }
+ return;
+ }
- s->adb_data_in_size = adb_request(&s->adb_bus, s->adb_data_in,
+ /* If the command is complete, execute it */
+ if (s->adb_data_out_index == adb_via_send_len(s->adb_data_out[0])) {
+ s->adb_data_in_size = adb_request(adb_bus, s->adb_data_in,
s->adb_data_out,
s->adb_data_out_index);
- s->adb_data_out_index = 0;
s->adb_data_in_index = 0;
- if (s->adb_data_in_size < 0) {
- *data = 0xff;
- qemu_irq_raise(s->adb_data_ready);
- return -1;
- }
- if (s->adb_data_in_size == 0) {
- return 0;
+ if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
+ /*
+ * Bus timeout (but allow first EVEN and ODD byte to indicate
+ * timeout via vADBInt and SRQ status)
+ */
+ s->adb_data_in[0] = 0xff;
+ s->adb_data_in[1] = 0xff;
+ s->adb_data_in_size = 2;
}
- break;
- }
-
- assert(s->adb_data_in_index < sizeof(s->adb_data_in) - 1);
+ /*
+ * If last command is TALK, store it for use by autopoll and adjust
+ * the autopoll mask accordingly
+ */
+ if ((s->adb_data_out[0] & 0xc) == 0xc) {
+ s->adb_autopoll_cmd = s->adb_data_out[0];
- *data = s->adb_data_in[s->adb_data_in_index++];
- qemu_irq_raise(s->adb_data_ready);
- if (*data == 0xff || *data == 0) {
- return 0;
+ autopoll_mask = 1 << (s->adb_autopoll_cmd >> 4);
+ adb_set_autopoll_mask(adb_bus, autopoll_mask);
+ }
}
- return 1;
}
-static void via1_adb_update(MacVIAState *m)
+static void adb_via_receive(MacVIAState *s, int state, uint8_t *data)
{
- MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1);
- MOS6522State *s = MOS6522(v1s);
- int state;
- int ret;
+ MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&s->mos6522_via1);
+ MOS6522State *ms = MOS6522(v1s);
+ ADBBusState *adb_bus = &s->adb_bus;
+ uint16_t pending;
- state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift;
+ switch (state) {
+ case ADB_STATE_NEW:
+ ms->b |= VIA1B_vADBInt;
+ return;
- if (s->acr & VIA1ACR_vShiftOut) {
- /* output mode */
- ret = adb_via_send(m, state, s->sr);
- if (ret > 0) {
- s->b &= ~VIA1B_vADBInt;
+ case ADB_STATE_IDLE:
+ /*
+ * Since adb_request() will have already consumed the data from the
+ * device, we must detect this extra state change and re-inject the
+ * reponse as either a "fake" autopoll reply or bus timeout
+ * accordingly
+ */
+ if (s->adb_data_in_index == 0) {
+ if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
+ *data = 0xff;
+ ms->b |= VIA1B_vADBInt;
+ qemu_irq_raise(s->adb_data_ready);
+ } else if (s->adb_data_in_size > 0) {
+ adb_bus->status = ADB_STATUS_POLLREPLY;
+ *data = s->adb_autopoll_cmd;
+ ms->b &= ~VIA1B_vADBInt;
+ qemu_irq_raise(s->adb_data_ready);
+ }
} else {
- s->b |= VIA1B_vADBInt;
+ ms->b |= VIA1B_vADBInt;
+ adb_autopoll_unblock(adb_bus);
}
- } else {
- /* input mode */
- ret = adb_via_receive(m, state, &s->sr);
- if (ret > 0 && s->sr != 0xff) {
- s->b &= ~VIA1B_vADBInt;
- } else {
- s->b |= VIA1B_vADBInt;
+
+ trace_via1_adb_receive("IDLE", *data,
+ (ms->b & VIA1B_vADBInt) ? "+" : "-", adb_bus->status,
+ s->adb_data_in_index, s->adb_data_in_size);
+
+ break;
+
+ case ADB_STATE_EVEN:
+ case ADB_STATE_ODD:
+ switch (s->adb_data_in_index) {
+ case 0:
+ /* First EVEN byte: vADBInt indicates bus timeout */
+ trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
+ *data, (ms->b & VIA1B_vADBInt) ? "+" : "-",
+ adb_bus->status, s->adb_data_in_index,
+ s->adb_data_in_size);
+
+ *data = s->adb_data_in[s->adb_data_in_index++];
+ if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
+ ms->b &= ~VIA1B_vADBInt;
+ } else {
+ ms->b |= VIA1B_vADBInt;
+ }
+ break;
+
+ case 1:
+ /* First ODD byte: vADBInt indicates SRQ */
+ trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
+ *data, (ms->b & VIA1B_vADBInt) ? "+" : "-",
+ adb_bus->status, s->adb_data_in_index,
+ s->adb_data_in_size);
+
+ *data = s->adb_data_in[s->adb_data_in_index++];
+ pending = adb_bus->pending & ~(1 << (s->adb_autopoll_cmd >> 4));
+ if (pending) {
+ ms->b &= ~VIA1B_vADBInt;
+ } else {
+ ms->b |= VIA1B_vADBInt;
+ }
+ break;
+
+ default:
+ /*
+ * Otherwise vADBInt indicates end of data. Note that Linux
+ * specifically checks for the sequence 0x0 0xff to confirm the
+ * end of the poll reply, so provide these extra bytes below to
+ * keep it happy
+ */
+ trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
+ *data, (ms->b & VIA1B_vADBInt) ? "+" : "-",
+ adb_bus->status, s->adb_data_in_index,
+ s->adb_data_in_size);
+
+ if (s->adb_data_in_index < s->adb_data_in_size) {
+ /* Next data byte */
+ *data = s->adb_data_in[s->adb_data_in_index++];
+ ms->b |= VIA1B_vADBInt;
+ } else if (s->adb_data_in_index == s->adb_data_in_size) {
+ if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
+ /* Bus timeout (no more data) */
+ *data = 0xff;
+ } else {
+ /* Return 0x0 after reply */
+ *data = 0;
+ }
+ s->adb_data_in_index++;
+ ms->b &= ~VIA1B_vADBInt;
+ } else {
+ /* Bus timeout (no more data) */
+ *data = 0xff;
+ ms->b &= ~VIA1B_vADBInt;
+ adb_bus->status = 0;
+ adb_autopoll_unblock(adb_bus);
+ }
+ break;
}
+
+ qemu_irq_raise(s->adb_data_ready);
+ break;
}
}
-static void via_adb_poll(void *opaque)
+static void via1_adb_update(MacVIAState *m)
{
- MacVIAState *m = opaque;
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1);
MOS6522State *s = MOS6522(v1s);
- int state;
+ int oldstate, state;
- if (s->b & VIA1B_vADBInt) {
- state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift;
- if (adb_via_poll(m, state, &s->sr)) {
- s->b &= ~VIA1B_vADBInt;
+ oldstate = (v1s->last_b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift;
+ state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift;
+
+ if (state != oldstate) {
+ if (s->acr & VIA1ACR_vShiftOut) {
+ /* output mode */
+ adb_via_send(m, state, s->sr);
+ } else {
+ /* input mode */
+ adb_via_receive(m, state, &s->sr);
}
}
-
- timer_mod(m->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ));
}
static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size)
@@ -802,11 +933,21 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque);
+ MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1);
MOS6522State *ms = MOS6522(v1s);
addr = (addr >> 9) & 0xf;
mos6522_write(ms, addr, val, size);
+ switch (addr) {
+ case VIA_REG_B:
+ via1_rtc_update(m);
+ via1_adb_update(m);
+
+ v1s->last_b = ms->b;
+ break;
+ }
+
via1_one_second_update(v1s);
via1_VBL_update(v1s);
}
@@ -854,10 +995,9 @@ static void mac_via_reset(DeviceState *dev)
{
MacVIAState *m = MAC_VIA(dev);
MOS6522Q800VIA1State *v1s = &m->mos6522_via1;
+ ADBBusState *adb_bus = &m->adb_bus;
- timer_mod(m->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ));
+ adb_set_autopoll_enabled(adb_bus, true);
timer_del(v1s->VBL_timer);
v1s->next_VBL = 0;
@@ -872,6 +1012,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp)
{
MacVIAState *m = MAC_VIA(dev);
MOS6522State *ms;
+ ADBBusState *adb_bus = &m->adb_bus;
struct tm tm;
int ret;
@@ -907,7 +1048,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp)
qemu_get_timedate(&tm, 0);
m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
- m->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via_adb_poll, m);
+ adb_register_autopoll_callback(adb_bus, adb_via_poll, m);
m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq",
VIA1_IRQ_ADB_READY_BIT);
@@ -980,8 +1121,8 @@ static int mac_via_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_mac_via = {
.name = "mac-via",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.post_load = mac_via_post_load,
.fields = (VMStateField[]) {
/* VIAs */
@@ -1005,12 +1146,12 @@ static const VMStateDescription vmstate_mac_via = {
VMSTATE_INT32(wprotect, MacVIAState),
VMSTATE_INT32(alt, MacVIAState),
/* ADB */
- VMSTATE_TIMER_PTR(adb_poll_timer, MacVIAState),
VMSTATE_INT32(adb_data_in_size, MacVIAState),
VMSTATE_INT32(adb_data_in_index, MacVIAState),
VMSTATE_INT32(adb_data_out_index, MacVIAState),
VMSTATE_BUFFER(adb_data_in, MacVIAState),
VMSTATE_BUFFER(adb_data_out, MacVIAState),
+ VMSTATE_UINT8(adb_autopoll_cmd, MacVIAState),
VMSTATE_END_OF_LIST()
}
};
@@ -1039,18 +1180,6 @@ static TypeInfo mac_via_info = {
};
/* VIA 1 */
-static void mos6522_q800_via1_portB_write(MOS6522State *s)
-{
- MOS6522Q800VIA1State *v1s = container_of(s, MOS6522Q800VIA1State,
- parent_obj);
- MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1);
-
- via1_rtc_update(m);
- via1_adb_update(m);
-
- v1s->last_b = s->b;
-}
-
static void mos6522_q800_via1_reset(DeviceState *dev)
{
MOS6522State *ms = MOS6522(dev);
@@ -1073,10 +1202,8 @@ static void mos6522_q800_via1_init(Object *obj)
static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc);
dc->reset = mos6522_q800_via1_reset;
- mdc->portB_write = mos6522_q800_via1_portB_write;
}
static const TypeInfo mos6522_q800_via1_type_info = {
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index 47aa3b0..5bbc777 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -116,6 +116,7 @@ static void cuda_update(CUDAState *s)
{
MOS6522CUDAState *mcs = &s->mos6522_cuda;
MOS6522State *ms = MOS6522(mcs);
+ ADBBusState *adb_bus = &s->adb_bus;
int packet_received, len;
packet_received = 0;
@@ -126,6 +127,9 @@ static void cuda_update(CUDAState *s)
/* data output */
if ((ms->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
if (s->data_out_index < sizeof(s->data_out)) {
+ if (s->data_out_index == 0) {
+ adb_autopoll_block(adb_bus);
+ }
trace_cuda_data_send(ms->sr);
s->data_out[s->data_out_index++] = ms->sr;
cuda_delay_set_sr_int(s);
@@ -140,6 +144,7 @@ static void cuda_update(CUDAState *s)
/* indicate end of transfer */
if (s->data_in_index >= s->data_in_size) {
ms->b = (ms->b | TREQ);
+ adb_autopoll_unblock(adb_bus);
}
cuda_delay_set_sr_int(s);
}
@@ -201,17 +206,16 @@ static void cuda_send_packet_to_host(CUDAState *s,
static void cuda_adb_poll(void *opaque)
{
CUDAState *s = opaque;
+ ADBBusState *adb_bus = &s->adb_bus;
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
- olen = adb_poll(&s->adb_bus, obuf + 2, s->adb_poll_mask);
+ olen = adb_poll(adb_bus, obuf + 2, adb_bus->autopoll_mask);
if (olen > 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x40; /* polled data */
cuda_send_packet_to_host(s, obuf, olen + 2);
}
- timer_mod(s->adb_poll_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms)));
}
/* description of commands */
@@ -227,23 +231,16 @@ static bool cuda_cmd_autopoll(CUDAState *s,
const uint8_t *in_data, int in_len,
uint8_t *out_data, int *out_len)
{
- int autopoll;
+ ADBBusState *adb_bus = &s->adb_bus;
+ bool autopoll;
if (in_len != 1) {
return false;
}
- autopoll = (in_data[0] != 0);
- if (autopoll != s->autopoll) {
- s->autopoll = autopoll;
- if (autopoll) {
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms)));
- } else {
- timer_del(s->adb_poll_timer);
- }
- }
+ autopoll = (in_data[0] != 0) ? true : false;
+
+ adb_set_autopoll_enabled(adb_bus, autopoll);
return true;
}
@@ -251,6 +248,8 @@ static bool cuda_cmd_set_autorate(CUDAState *s,
const uint8_t *in_data, int in_len,
uint8_t *out_data, int *out_len)
{
+ ADBBusState *adb_bus = &s->adb_bus;
+
if (in_len != 1) {
return false;
}
@@ -261,12 +260,7 @@ static bool cuda_cmd_set_autorate(CUDAState *s,
return false;
}
- s->autopoll_rate_ms = in_data[0];
- if (s->autopoll) {
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms)));
- }
+ adb_set_autopoll_rate_ms(adb_bus, in_data[0]);
return true;
}
@@ -274,11 +268,16 @@ static bool cuda_cmd_set_device_list(CUDAState *s,
const uint8_t *in_data, int in_len,
uint8_t *out_data, int *out_len)
{
+ ADBBusState *adb_bus = &s->adb_bus;
+ uint16_t mask;
+
if (in_len != 2) {
return false;
}
- s->adb_poll_mask = (((uint16_t)in_data[0]) << 8) | in_data[1];
+ mask = (((uint16_t)in_data[0]) << 8) | in_data[1];
+
+ adb_set_autopoll_mask(adb_bus, mask);
return true;
}
@@ -489,8 +488,8 @@ static const MemoryRegionOps mos6522_cuda_ops = {
static const VMStateDescription vmstate_cuda = {
.name = "cuda",
- .version_id = 5,
- .minimum_version_id = 5,
+ .version_id = 6,
+ .minimum_version_id = 6,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(mos6522_cuda.parent_obj, CUDAState, 0, vmstate_mos6522,
MOS6522State),
@@ -499,13 +498,9 @@ static const VMStateDescription vmstate_cuda = {
VMSTATE_INT32(data_in_size, CUDAState),
VMSTATE_INT32(data_in_index, CUDAState),
VMSTATE_INT32(data_out_index, CUDAState),
- VMSTATE_UINT8(autopoll, CUDAState),
- VMSTATE_UINT8(autopoll_rate_ms, CUDAState),
- VMSTATE_UINT16(adb_poll_mask, CUDAState),
VMSTATE_BUFFER(data_in, CUDAState),
VMSTATE_BUFFER(data_out, CUDAState),
VMSTATE_UINT32(tick_offset, CUDAState),
- VMSTATE_TIMER_PTR(adb_poll_timer, CUDAState),
VMSTATE_TIMER_PTR(sr_delay_timer, CUDAState),
VMSTATE_END_OF_LIST()
}
@@ -514,11 +509,13 @@ static const VMStateDescription vmstate_cuda = {
static void cuda_reset(DeviceState *dev)
{
CUDAState *s = CUDA(dev);
+ ADBBusState *adb_bus = &s->adb_bus;
s->data_in_size = 0;
s->data_in_index = 0;
s->data_out_index = 0;
- s->autopoll = 0;
+
+ adb_set_autopoll_enabled(adb_bus, false);
}
static void cuda_realize(DeviceState *dev, Error **errp)
@@ -526,6 +523,7 @@ static void cuda_realize(DeviceState *dev, Error **errp)
CUDAState *s = CUDA(dev);
Error *err = NULL;
SysBusDevice *sbd;
+ ADBBusState *adb_bus = &s->adb_bus;
struct tm tm;
sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), &err);
@@ -544,9 +542,7 @@ static void cuda_realize(DeviceState *dev, Error **errp)
s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s);
s->sr_delay_ns = 20 * SCALE_US;
- s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s);
- s->adb_poll_mask = 0xffff;
- s->autopoll_rate_ms = 20;
+ adb_register_autopoll_callback(adb_bus, cuda_adb_poll, s);
}
static void cuda_init(Object *obj)
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
index 41b626c..598d8e7 100644
--- a/hw/misc/macio/pmu.c
+++ b/hw/misc/macio/pmu.c
@@ -92,10 +92,11 @@ static void pmu_update_extirq(PMUState *s)
static void pmu_adb_poll(void *opaque)
{
PMUState *s = opaque;
+ ADBBusState *adb_bus = &s->adb_bus;
int olen;
if (!(s->intbits & PMU_INT_ADB)) {
- olen = adb_poll(&s->adb_bus, s->adb_reply, s->adb_poll_mask);
+ olen = adb_poll(adb_bus, s->adb_reply, adb_bus->autopoll_mask);
trace_pmu_adb_poll(olen);
if (olen > 0) {
@@ -104,9 +105,6 @@ static void pmu_adb_poll(void *opaque)
pmu_update_extirq(s);
}
}
-
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30);
}
static void pmu_one_sec_timer(void *opaque)
@@ -173,18 +171,15 @@ static void pmu_cmd_set_int_mask(PMUState *s,
static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask)
{
- trace_pmu_cmd_set_adb_autopoll(mask);
+ ADBBusState *adb_bus = &s->adb_bus;
- if (s->autopoll_mask == mask) {
- return;
- }
+ trace_pmu_cmd_set_adb_autopoll(mask);
- s->autopoll_mask = mask;
if (mask) {
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30);
+ adb_set_autopoll_mask(adb_bus, mask);
+ adb_set_autopoll_enabled(adb_bus, true);
} else {
- timer_del(s->adb_poll_timer);
+ adb_set_autopoll_enabled(adb_bus, false);
}
}
@@ -267,6 +262,8 @@ static void pmu_cmd_adb_poll_off(PMUState *s,
const uint8_t *in_data, uint8_t in_len,
uint8_t *out_data, uint8_t *out_len)
{
+ ADBBusState *adb_bus = &s->adb_bus;
+
if (in_len != 0) {
qemu_log_mask(LOG_GUEST_ERROR,
"PMU: ADB POLL OFF command, invalid len: %d want: 0\n",
@@ -274,9 +271,8 @@ static void pmu_cmd_adb_poll_off(PMUState *s,
return;
}
- if (s->has_adb && s->autopoll_mask) {
- timer_del(s->adb_poll_timer);
- s->autopoll_mask = false;
+ if (s->has_adb) {
+ adb_set_autopoll_enabled(adb_bus, false);
}
}
@@ -521,6 +517,7 @@ static void pmu_update(PMUState *s)
{
MOS6522PMUState *mps = &s->mos6522_pmu;
MOS6522State *ms = MOS6522(mps);
+ ADBBusState *adb_bus = &s->adb_bus;
/* Only react to changes in reg B */
if (ms->b == s->last_b) {
@@ -582,6 +579,7 @@ static void pmu_update(PMUState *s)
s->cmd_rsp_pos = 0;
s->cmd_state = pmu_state_cmd;
+ adb_autopoll_block(adb_bus);
trace_pmu_debug_protocol_cmd(s->cmd, s->cmdlen, s->rsplen);
break;
@@ -640,6 +638,7 @@ static void pmu_update(PMUState *s)
if (s->cmd_state == pmu_state_rsp && s->rsplen == s->cmd_rsp_pos) {
trace_pmu_debug_protocol_cmd_resp_complete(ms->ier);
+ adb_autopoll_unblock(adb_bus);
s->cmd_state = pmu_state_idle;
}
}
@@ -684,12 +683,10 @@ static bool pmu_adb_state_needed(void *opaque)
static const VMStateDescription vmstate_pmu_adb = {
.name = "pmu/adb",
- .version_id = 0,
- .minimum_version_id = 0,
+ .version_id = 1,
+ .minimum_version_id = 1,
.needed = pmu_adb_state_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT16(adb_poll_mask, PMUState),
- VMSTATE_TIMER_PTR(adb_poll_timer, PMUState),
VMSTATE_UINT8(adb_reply_size, PMUState),
VMSTATE_BUFFER(adb_reply, PMUState),
VMSTATE_END_OF_LIST()
@@ -698,8 +695,8 @@ static const VMStateDescription vmstate_pmu_adb = {
static const VMStateDescription vmstate_pmu = {
.name = "pmu",
- .version_id = 0,
- .minimum_version_id = 0,
+ .version_id = 1,
+ .minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(mos6522_pmu.parent_obj, PMUState, 0, vmstate_mos6522,
MOS6522State),
@@ -714,8 +711,6 @@ static const VMStateDescription vmstate_pmu = {
VMSTATE_BUFFER(cmd_rsp, PMUState),
VMSTATE_UINT8(intbits, PMUState),
VMSTATE_UINT8(intmask, PMUState),
- VMSTATE_UINT8(autopoll_rate_ms, PMUState),
- VMSTATE_UINT8(autopoll_mask, PMUState),
VMSTATE_UINT32(tick_offset, PMUState),
VMSTATE_TIMER_PTR(one_sec_timer, PMUState),
VMSTATE_INT64(one_sec_target, PMUState),
@@ -735,7 +730,6 @@ static void pmu_reset(DeviceState *dev)
s->intbits = 0;
s->cmd_state = pmu_state_idle;
- s->autopoll_mask = 0;
}
static void pmu_realize(DeviceState *dev, Error **errp)
@@ -743,6 +737,7 @@ static void pmu_realize(DeviceState *dev, Error **errp)
PMUState *s = VIA_PMU(dev);
Error *err = NULL;
SysBusDevice *sbd;
+ ADBBusState *adb_bus = &s->adb_bus;
struct tm tm;
sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), &err);
@@ -764,9 +759,7 @@ static void pmu_realize(DeviceState *dev, Error **errp)
if (s->has_adb) {
qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
dev, "adb.0");
- s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_adb_poll, s);
- s->adb_poll_mask = 0xffff;
- s->autopoll_rate_ms = 20;
+ adb_register_autopoll_callback(adb_bus, pmu_adb_poll, s);
}
}
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 5561746..68a6d9f 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -202,6 +202,9 @@ via1_rtc_cmd_pram_read(int addr, int value) "addr=%u value=0x%02x"
via1_rtc_cmd_pram_write(int addr, int value) "addr=%u value=0x%02x"
via1_rtc_cmd_pram_sect_read(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x"
via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x"
+via1_adb_send(const char *state, uint8_t data, const char *vadbint) "state %s data=0x%02x vADBInt=%s"
+via1_adb_receive(const char *state, uint8_t data, const char *vadbint, int status, int index, int size) "state %s data=0x%02x vADBInt=%s status=0x%x index=%d size=%d"
+via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size) "data=0x%02x vADBInt=%s status=0x%x index=%d size=%d"
# grlib_ahb_apb_pnp.c
grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x"