Commit e4a89056df2c6fc38f860db172460f4df37cd2ca
1 parent
715748fa
fix serial irq logic (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2151 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
65 additions
and
26 deletions
hw/slavio_serial.c
... | ... | @@ -88,7 +88,7 @@ typedef struct { |
88 | 88 | typedef struct ChannelState { |
89 | 89 | int irq; |
90 | 90 | int reg; |
91 | - int rxint, txint; | |
91 | + int rxint, txint, rxint_under_svc, txint_under_svc; | |
92 | 92 | chn_id_t chn; // this channel, A (base+4) or B (base+0) |
93 | 93 | chn_type_t type; |
94 | 94 | struct ChannelState *otherchn; |
... | ... | @@ -106,6 +106,7 @@ struct SerialState { |
106 | 106 | static void handle_kbd_command(ChannelState *s, int val); |
107 | 107 | static int serial_can_receive(void *opaque); |
108 | 108 | static void serial_receive_byte(ChannelState *s, int ch); |
109 | +static inline void set_txint(ChannelState *s); | |
109 | 110 | |
110 | 111 | static void put_queue(void *opaque, int b) |
111 | 112 | { |
... | ... | @@ -142,17 +143,26 @@ static uint32_t get_queue(void *opaque) |
142 | 143 | return val; |
143 | 144 | } |
144 | 145 | |
145 | -static void slavio_serial_update_irq(ChannelState *s) | |
146 | +static int slavio_serial_update_irq_chn(ChannelState *s) | |
146 | 147 | { |
147 | 148 | if ((s->wregs[1] & 1) && // interrupts enabled |
148 | 149 | (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending |
149 | 150 | ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && |
150 | 151 | s->rxint == 1) || // rx ints enabled, pending |
151 | 152 | ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p |
152 | - pic_set_irq(s->irq, 1); | |
153 | - } else { | |
154 | - pic_set_irq(s->irq, 0); | |
153 | + return 1; | |
155 | 154 | } |
155 | + return 0; | |
156 | +} | |
157 | + | |
158 | +static void slavio_serial_update_irq(ChannelState *s) | |
159 | +{ | |
160 | + int irq; | |
161 | + | |
162 | + irq = slavio_serial_update_irq_chn(s); | |
163 | + irq |= slavio_serial_update_irq_chn(s->otherchn); | |
164 | + | |
165 | + pic_set_irq(s->irq, irq); | |
156 | 166 | } |
157 | 167 | |
158 | 168 | static void slavio_serial_reset_chn(ChannelState *s) |
... | ... | @@ -174,6 +184,7 @@ static void slavio_serial_reset_chn(ChannelState *s) |
174 | 184 | |
175 | 185 | s->rx = s->tx = 0; |
176 | 186 | s->rxint = s->txint = 0; |
187 | + s->rxint_under_svc = s->txint_under_svc = 0; | |
177 | 188 | } |
178 | 189 | |
179 | 190 | static void slavio_serial_reset(void *opaque) |
... | ... | @@ -186,45 +197,63 @@ static void slavio_serial_reset(void *opaque) |
186 | 197 | static inline void clr_rxint(ChannelState *s) |
187 | 198 | { |
188 | 199 | s->rxint = 0; |
200 | + s->rxint_under_svc = 0; | |
189 | 201 | if (s->chn == 0) |
190 | 202 | s->rregs[3] &= ~0x20; |
191 | 203 | else { |
192 | 204 | s->otherchn->rregs[3] &= ~4; |
193 | 205 | } |
206 | + if (s->txint) | |
207 | + set_txint(s); | |
208 | + else | |
209 | + s->rregs[2] = 6; | |
194 | 210 | slavio_serial_update_irq(s); |
195 | 211 | } |
196 | 212 | |
197 | 213 | static inline void set_rxint(ChannelState *s) |
198 | 214 | { |
199 | 215 | s->rxint = 1; |
200 | - if (s->chn == 0) | |
201 | - s->rregs[3] |= 0x20; | |
202 | - else { | |
203 | - s->otherchn->rregs[3] |= 4; | |
216 | + if (!s->txint_under_svc) { | |
217 | + s->rxint_under_svc = 1; | |
218 | + if (s->chn == 0) | |
219 | + s->rregs[3] |= 0x20; | |
220 | + else { | |
221 | + s->otherchn->rregs[3] |= 4; | |
222 | + } | |
223 | + s->rregs[2] = 4; | |
224 | + slavio_serial_update_irq(s); | |
204 | 225 | } |
205 | - slavio_serial_update_irq(s); | |
206 | 226 | } |
207 | 227 | |
208 | 228 | static inline void clr_txint(ChannelState *s) |
209 | 229 | { |
210 | 230 | s->txint = 0; |
231 | + s->txint_under_svc = 0; | |
211 | 232 | if (s->chn == 0) |
212 | 233 | s->rregs[3] &= ~0x10; |
213 | 234 | else { |
214 | 235 | s->otherchn->rregs[3] &= ~2; |
215 | 236 | } |
237 | + if (s->rxint) | |
238 | + set_rxint(s); | |
239 | + else | |
240 | + s->rregs[2] = 6; | |
216 | 241 | slavio_serial_update_irq(s); |
217 | 242 | } |
218 | 243 | |
219 | 244 | static inline void set_txint(ChannelState *s) |
220 | 245 | { |
221 | 246 | s->txint = 1; |
222 | - if (s->chn == 0) | |
223 | - s->rregs[3] |= 0x10; | |
224 | - else { | |
225 | - s->otherchn->rregs[3] |= 2; | |
247 | + if (!s->rxint_under_svc) { | |
248 | + s->txint_under_svc = 1; | |
249 | + if (s->chn == 0) | |
250 | + s->rregs[3] |= 0x10; | |
251 | + else { | |
252 | + s->otherchn->rregs[3] |= 2; | |
253 | + } | |
254 | + s->rregs[2] = 0; | |
255 | + slavio_serial_update_irq(s); | |
226 | 256 | } |
227 | - slavio_serial_update_irq(s); | |
228 | 257 | } |
229 | 258 | |
230 | 259 | static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
... | ... | @@ -250,15 +279,14 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint |
250 | 279 | case 8: |
251 | 280 | newreg |= 0x8; |
252 | 281 | break; |
253 | - case 0x20: | |
254 | - clr_rxint(s); | |
255 | - break; | |
256 | 282 | case 0x28: |
257 | 283 | clr_txint(s); |
258 | 284 | break; |
259 | 285 | case 0x38: |
260 | - clr_rxint(s); | |
261 | - clr_txint(s); | |
286 | + if (s->rxint_under_svc) | |
287 | + clr_rxint(s); | |
288 | + else if (s->txint_under_svc) | |
289 | + clr_txint(s); | |
262 | 290 | break; |
263 | 291 | default: |
264 | 292 | break; |
... | ... | @@ -301,11 +329,9 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint |
301 | 329 | else if (s->type == kbd) { |
302 | 330 | handle_kbd_command(s, val); |
303 | 331 | } |
304 | - s->txint = 1; | |
305 | 332 | s->rregs[0] |= 4; // Tx buffer empty |
306 | 333 | s->rregs[1] |= 1; // All sent |
307 | 334 | set_txint(s); |
308 | - slavio_serial_update_irq(s); | |
309 | 335 | } |
310 | 336 | break; |
311 | 337 | default: |
... | ... | @@ -348,11 +374,15 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) |
348 | 374 | static int serial_can_receive(void *opaque) |
349 | 375 | { |
350 | 376 | ChannelState *s = opaque; |
377 | + int ret; | |
378 | + | |
351 | 379 | if (((s->wregs[3] & 1) == 0) // Rx not enabled |
352 | 380 | || ((s->rregs[0] & 1) == 1)) // char already available |
353 | - return 0; | |
381 | + ret = 0; | |
354 | 382 | else |
355 | - return 1; | |
383 | + ret = 1; | |
384 | + SER_DPRINTF("can receive %d\n", ret); | |
385 | + return ret; | |
356 | 386 | } |
357 | 387 | |
358 | 388 | static void serial_receive_byte(ChannelState *s, int ch) |
... | ... | @@ -400,6 +430,8 @@ static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) |
400 | 430 | qemu_put_be32s(f, &s->reg); |
401 | 431 | qemu_put_be32s(f, &s->rxint); |
402 | 432 | qemu_put_be32s(f, &s->txint); |
433 | + qemu_put_be32s(f, &s->rxint_under_svc); | |
434 | + qemu_put_be32s(f, &s->txint_under_svc); | |
403 | 435 | qemu_put_8s(f, &s->rx); |
404 | 436 | qemu_put_8s(f, &s->tx); |
405 | 437 | qemu_put_buffer(f, s->wregs, 16); |
... | ... | @@ -416,13 +448,17 @@ static void slavio_serial_save(QEMUFile *f, void *opaque) |
416 | 448 | |
417 | 449 | static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) |
418 | 450 | { |
419 | - if (version_id != 1) | |
451 | + if (version_id > 2) | |
420 | 452 | return -EINVAL; |
421 | 453 | |
422 | 454 | qemu_get_be32s(f, &s->irq); |
423 | 455 | qemu_get_be32s(f, &s->reg); |
424 | 456 | qemu_get_be32s(f, &s->rxint); |
425 | 457 | qemu_get_be32s(f, &s->txint); |
458 | + if (version_id >= 2) { | |
459 | + qemu_get_be32s(f, &s->rxint_under_svc); | |
460 | + qemu_get_be32s(f, &s->txint_under_svc); | |
461 | + } | |
426 | 462 | qemu_get_8s(f, &s->rx); |
427 | 463 | qemu_get_8s(f, &s->tx); |
428 | 464 | qemu_get_buffer(f, s->wregs, 16); |
... | ... | @@ -469,7 +505,7 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDr |
469 | 505 | } |
470 | 506 | s->chn[0].otherchn = &s->chn[1]; |
471 | 507 | s->chn[1].otherchn = &s->chn[0]; |
472 | - register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); | |
508 | + register_savevm("slavio_serial", base, 2, slavio_serial_save, slavio_serial_load, s); | |
473 | 509 | qemu_register_reset(slavio_serial_reset, s); |
474 | 510 | slavio_serial_reset(s); |
475 | 511 | return s; |
... | ... | @@ -519,6 +555,9 @@ static void sunmouse_event(void *opaque, |
519 | 555 | ChannelState *s = opaque; |
520 | 556 | int ch; |
521 | 557 | |
558 | + /* XXX: SDL sometimes generates nul events: we delete them */ | |
559 | + if (dx == 0 && dy == 0 && dz == 0 && buttons_state == 0) | |
560 | + return; | |
522 | 561 | MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state); |
523 | 562 | |
524 | 563 | ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ | ... | ... |