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,7 +88,7 @@ typedef struct { | ||
| 88 | typedef struct ChannelState { | 88 | typedef struct ChannelState { |
| 89 | int irq; | 89 | int irq; |
| 90 | int reg; | 90 | int reg; |
| 91 | - int rxint, txint; | 91 | + int rxint, txint, rxint_under_svc, txint_under_svc; |
| 92 | chn_id_t chn; // this channel, A (base+4) or B (base+0) | 92 | chn_id_t chn; // this channel, A (base+4) or B (base+0) |
| 93 | chn_type_t type; | 93 | chn_type_t type; |
| 94 | struct ChannelState *otherchn; | 94 | struct ChannelState *otherchn; |
| @@ -106,6 +106,7 @@ struct SerialState { | @@ -106,6 +106,7 @@ struct SerialState { | ||
| 106 | static void handle_kbd_command(ChannelState *s, int val); | 106 | static void handle_kbd_command(ChannelState *s, int val); |
| 107 | static int serial_can_receive(void *opaque); | 107 | static int serial_can_receive(void *opaque); |
| 108 | static void serial_receive_byte(ChannelState *s, int ch); | 108 | static void serial_receive_byte(ChannelState *s, int ch); |
| 109 | +static inline void set_txint(ChannelState *s); | ||
| 109 | 110 | ||
| 110 | static void put_queue(void *opaque, int b) | 111 | static void put_queue(void *opaque, int b) |
| 111 | { | 112 | { |
| @@ -142,17 +143,26 @@ static uint32_t get_queue(void *opaque) | @@ -142,17 +143,26 @@ static uint32_t get_queue(void *opaque) | ||
| 142 | return val; | 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 | if ((s->wregs[1] & 1) && // interrupts enabled | 148 | if ((s->wregs[1] & 1) && // interrupts enabled |
| 148 | (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending | 149 | (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending |
| 149 | ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && | 150 | ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && |
| 150 | s->rxint == 1) || // rx ints enabled, pending | 151 | s->rxint == 1) || // rx ints enabled, pending |
| 151 | ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p | 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 | static void slavio_serial_reset_chn(ChannelState *s) | 168 | static void slavio_serial_reset_chn(ChannelState *s) |
| @@ -174,6 +184,7 @@ static void slavio_serial_reset_chn(ChannelState *s) | @@ -174,6 +184,7 @@ static void slavio_serial_reset_chn(ChannelState *s) | ||
| 174 | 184 | ||
| 175 | s->rx = s->tx = 0; | 185 | s->rx = s->tx = 0; |
| 176 | s->rxint = s->txint = 0; | 186 | s->rxint = s->txint = 0; |
| 187 | + s->rxint_under_svc = s->txint_under_svc = 0; | ||
| 177 | } | 188 | } |
| 178 | 189 | ||
| 179 | static void slavio_serial_reset(void *opaque) | 190 | static void slavio_serial_reset(void *opaque) |
| @@ -186,45 +197,63 @@ static void slavio_serial_reset(void *opaque) | @@ -186,45 +197,63 @@ static void slavio_serial_reset(void *opaque) | ||
| 186 | static inline void clr_rxint(ChannelState *s) | 197 | static inline void clr_rxint(ChannelState *s) |
| 187 | { | 198 | { |
| 188 | s->rxint = 0; | 199 | s->rxint = 0; |
| 200 | + s->rxint_under_svc = 0; | ||
| 189 | if (s->chn == 0) | 201 | if (s->chn == 0) |
| 190 | s->rregs[3] &= ~0x20; | 202 | s->rregs[3] &= ~0x20; |
| 191 | else { | 203 | else { |
| 192 | s->otherchn->rregs[3] &= ~4; | 204 | s->otherchn->rregs[3] &= ~4; |
| 193 | } | 205 | } |
| 206 | + if (s->txint) | ||
| 207 | + set_txint(s); | ||
| 208 | + else | ||
| 209 | + s->rregs[2] = 6; | ||
| 194 | slavio_serial_update_irq(s); | 210 | slavio_serial_update_irq(s); |
| 195 | } | 211 | } |
| 196 | 212 | ||
| 197 | static inline void set_rxint(ChannelState *s) | 213 | static inline void set_rxint(ChannelState *s) |
| 198 | { | 214 | { |
| 199 | s->rxint = 1; | 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 | static inline void clr_txint(ChannelState *s) | 228 | static inline void clr_txint(ChannelState *s) |
| 209 | { | 229 | { |
| 210 | s->txint = 0; | 230 | s->txint = 0; |
| 231 | + s->txint_under_svc = 0; | ||
| 211 | if (s->chn == 0) | 232 | if (s->chn == 0) |
| 212 | s->rregs[3] &= ~0x10; | 233 | s->rregs[3] &= ~0x10; |
| 213 | else { | 234 | else { |
| 214 | s->otherchn->rregs[3] &= ~2; | 235 | s->otherchn->rregs[3] &= ~2; |
| 215 | } | 236 | } |
| 237 | + if (s->rxint) | ||
| 238 | + set_rxint(s); | ||
| 239 | + else | ||
| 240 | + s->rregs[2] = 6; | ||
| 216 | slavio_serial_update_irq(s); | 241 | slavio_serial_update_irq(s); |
| 217 | } | 242 | } |
| 218 | 243 | ||
| 219 | static inline void set_txint(ChannelState *s) | 244 | static inline void set_txint(ChannelState *s) |
| 220 | { | 245 | { |
| 221 | s->txint = 1; | 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 | static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | 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,15 +279,14 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint | ||
| 250 | case 8: | 279 | case 8: |
| 251 | newreg |= 0x8; | 280 | newreg |= 0x8; |
| 252 | break; | 281 | break; |
| 253 | - case 0x20: | ||
| 254 | - clr_rxint(s); | ||
| 255 | - break; | ||
| 256 | case 0x28: | 282 | case 0x28: |
| 257 | clr_txint(s); | 283 | clr_txint(s); |
| 258 | break; | 284 | break; |
| 259 | case 0x38: | 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 | break; | 290 | break; |
| 263 | default: | 291 | default: |
| 264 | break; | 292 | break; |
| @@ -301,11 +329,9 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint | @@ -301,11 +329,9 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint | ||
| 301 | else if (s->type == kbd) { | 329 | else if (s->type == kbd) { |
| 302 | handle_kbd_command(s, val); | 330 | handle_kbd_command(s, val); |
| 303 | } | 331 | } |
| 304 | - s->txint = 1; | ||
| 305 | s->rregs[0] |= 4; // Tx buffer empty | 332 | s->rregs[0] |= 4; // Tx buffer empty |
| 306 | s->rregs[1] |= 1; // All sent | 333 | s->rregs[1] |= 1; // All sent |
| 307 | set_txint(s); | 334 | set_txint(s); |
| 308 | - slavio_serial_update_irq(s); | ||
| 309 | } | 335 | } |
| 310 | break; | 336 | break; |
| 311 | default: | 337 | default: |
| @@ -348,11 +374,15 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) | @@ -348,11 +374,15 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) | ||
| 348 | static int serial_can_receive(void *opaque) | 374 | static int serial_can_receive(void *opaque) |
| 349 | { | 375 | { |
| 350 | ChannelState *s = opaque; | 376 | ChannelState *s = opaque; |
| 377 | + int ret; | ||
| 378 | + | ||
| 351 | if (((s->wregs[3] & 1) == 0) // Rx not enabled | 379 | if (((s->wregs[3] & 1) == 0) // Rx not enabled |
| 352 | || ((s->rregs[0] & 1) == 1)) // char already available | 380 | || ((s->rregs[0] & 1) == 1)) // char already available |
| 353 | - return 0; | 381 | + ret = 0; |
| 354 | else | 382 | else |
| 355 | - return 1; | 383 | + ret = 1; |
| 384 | + SER_DPRINTF("can receive %d\n", ret); | ||
| 385 | + return ret; | ||
| 356 | } | 386 | } |
| 357 | 387 | ||
| 358 | static void serial_receive_byte(ChannelState *s, int ch) | 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,6 +430,8 @@ static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) | ||
| 400 | qemu_put_be32s(f, &s->reg); | 430 | qemu_put_be32s(f, &s->reg); |
| 401 | qemu_put_be32s(f, &s->rxint); | 431 | qemu_put_be32s(f, &s->rxint); |
| 402 | qemu_put_be32s(f, &s->txint); | 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 | qemu_put_8s(f, &s->rx); | 435 | qemu_put_8s(f, &s->rx); |
| 404 | qemu_put_8s(f, &s->tx); | 436 | qemu_put_8s(f, &s->tx); |
| 405 | qemu_put_buffer(f, s->wregs, 16); | 437 | qemu_put_buffer(f, s->wregs, 16); |
| @@ -416,13 +448,17 @@ static void slavio_serial_save(QEMUFile *f, void *opaque) | @@ -416,13 +448,17 @@ static void slavio_serial_save(QEMUFile *f, void *opaque) | ||
| 416 | 448 | ||
| 417 | static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) | 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 | return -EINVAL; | 452 | return -EINVAL; |
| 421 | 453 | ||
| 422 | qemu_get_be32s(f, &s->irq); | 454 | qemu_get_be32s(f, &s->irq); |
| 423 | qemu_get_be32s(f, &s->reg); | 455 | qemu_get_be32s(f, &s->reg); |
| 424 | qemu_get_be32s(f, &s->rxint); | 456 | qemu_get_be32s(f, &s->rxint); |
| 425 | qemu_get_be32s(f, &s->txint); | 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 | qemu_get_8s(f, &s->rx); | 462 | qemu_get_8s(f, &s->rx); |
| 427 | qemu_get_8s(f, &s->tx); | 463 | qemu_get_8s(f, &s->tx); |
| 428 | qemu_get_buffer(f, s->wregs, 16); | 464 | qemu_get_buffer(f, s->wregs, 16); |
| @@ -469,7 +505,7 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDr | @@ -469,7 +505,7 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDr | ||
| 469 | } | 505 | } |
| 470 | s->chn[0].otherchn = &s->chn[1]; | 506 | s->chn[0].otherchn = &s->chn[1]; |
| 471 | s->chn[1].otherchn = &s->chn[0]; | 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 | qemu_register_reset(slavio_serial_reset, s); | 509 | qemu_register_reset(slavio_serial_reset, s); |
| 474 | slavio_serial_reset(s); | 510 | slavio_serial_reset(s); |
| 475 | return s; | 511 | return s; |
| @@ -519,6 +555,9 @@ static void sunmouse_event(void *opaque, | @@ -519,6 +555,9 @@ static void sunmouse_event(void *opaque, | ||
| 519 | ChannelState *s = opaque; | 555 | ChannelState *s = opaque; |
| 520 | int ch; | 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 | MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state); | 561 | MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state); |
| 523 | 562 | ||
| 524 | ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ | 563 | ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ |