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 */ | ... | ... |