X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Fslavio_serial.c;h=2eb3379b490a7733da392c3031812c4f9c214f27;hb=cd346349b45ef056f138a184f660b8c34c3213cc;hp=0a2c8733007a2af0e6668322bba015573cd5659c;hpb=5aca8c3b2fbada188ff86781fba24685d346cef9;p=qemu diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 0a2c873..2eb3379 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -1,8 +1,8 @@ /* * QEMU Sparc SLAVIO serial port emulation - * + * * Copyright (c) 2003-2005 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 @@ -35,7 +35,7 @@ * This is the serial port, mouse and keyboard part of chip STP2001 * (Slave I/O), also produced as NCR89C105. See * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * + * * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, * mouse and keyboard ports don't implement all functions and they are * only asynchronous. There is no DMA. @@ -95,6 +95,7 @@ typedef struct ChannelState { uint8_t rx, tx, wregs[16], rregs[16]; SERIOQueue queue; CharDriverState *chr; + int e0_mode, led_mode, caps_lock_mode, num_lock_mode; } ChannelState; struct SerialState { @@ -136,9 +137,9 @@ static uint32_t get_queue(void *opaque) ChannelState *s = opaque; SERIOQueue *q = &s->queue; int val; - + if (q->count == 0) { - return 0; + return 0; } else { val = q->data[q->rptr]; if (++q->rptr == SERIO_QUEUE_SIZE) @@ -147,17 +148,17 @@ static uint32_t get_queue(void *opaque) } SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val); if (q->count > 0) - serial_receive_byte(s, 0); + serial_receive_byte(s, 0); return val; } static int slavio_serial_update_irq_chn(ChannelState *s) { if ((s->wregs[1] & 1) && // interrupts enabled - (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending - ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && - s->rxint == 1) || // rx ints enabled, pending - ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p + (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending + ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && + s->rxint == 1) || // rx ints enabled, pending + ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p return 1; } return 0; @@ -180,8 +181,8 @@ static void slavio_serial_reset_chn(ChannelState *s) s->reg = 0; for (i = 0; i < SERIAL_SIZE; i++) { - s->rregs[i] = 0; - s->wregs[i] = 0; + s->rregs[i] = 0; + s->wregs[i] = 0; } s->wregs[4] = 4; s->wregs[9] = 0xc0; @@ -194,6 +195,7 @@ static void slavio_serial_reset_chn(ChannelState *s) s->rx = s->tx = 0; s->rxint = s->txint = 0; s->rxint_under_svc = s->txint_under_svc = 0; + s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0; clear_queue(s); } @@ -354,7 +356,7 @@ static void slavio_serial_update_parameters(ChannelState *s) static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - SerialState *ser = opaque; + SerialState *serial = opaque; ChannelState *s; uint32_t saddr; int newreg, channel; @@ -362,91 +364,91 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint val &= 0xff; saddr = (addr & 3) >> 1; channel = (addr & SERIAL_MAXADDR) >> 2; - s = &ser->chn[channel]; + s = &serial->chn[channel]; switch (saddr) { case 0: - SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); - newreg = 0; - switch (s->reg) { - case 0: - newreg = val & 7; - val &= 0x38; - switch (val) { - case 8: - newreg |= 0x8; - break; - case 0x28: + SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); + newreg = 0; + switch (s->reg) { + case 0: + newreg = val & 7; + val &= 0x38; + switch (val) { + case 8: + newreg |= 0x8; + break; + case 0x28: clr_txint(s); - break; - case 0x38: + break; + case 0x38: if (s->rxint_under_svc) clr_rxint(s); else if (s->txint_under_svc) clr_txint(s); - break; - default: - break; - } - break; + break; + default: + break; + } + break; case 1 ... 3: case 6 ... 8: case 10 ... 11: case 14 ... 15: - s->wregs[s->reg] = val; - break; + s->wregs[s->reg] = val; + break; case 4: case 5: case 12: case 13: - s->wregs[s->reg] = val; + s->wregs[s->reg] = val; slavio_serial_update_parameters(s); - break; - case 9: - switch (val & 0xc0) { - case 0: - default: - break; - case 0x40: - slavio_serial_reset_chn(&ser->chn[1]); - return; - case 0x80: - slavio_serial_reset_chn(&ser->chn[0]); - return; - case 0xc0: - slavio_serial_reset(ser); - return; - } - break; - default: - break; - } - if (s->reg == 0) - s->reg = newreg; - else - s->reg = 0; - break; + break; + case 9: + switch (val & 0xc0) { + case 0: + default: + break; + case 0x40: + slavio_serial_reset_chn(&serial->chn[1]); + return; + case 0x80: + slavio_serial_reset_chn(&serial->chn[0]); + return; + case 0xc0: + slavio_serial_reset(serial); + return; + } + break; + default: + break; + } + if (s->reg == 0) + s->reg = newreg; + else + s->reg = 0; + break; case 1: - SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); - if (s->wregs[5] & 8) { // tx enabled - s->tx = val; - if (s->chr) - qemu_chr_write(s->chr, &s->tx, 1); - else if (s->type == kbd) { - handle_kbd_command(s, val); - } - s->rregs[0] |= 4; // Tx buffer empty - s->rregs[1] |= 1; // All sent - set_txint(s); - } - break; + SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); + s->tx = val; + if (s->wregs[5] & 8) { // tx enabled + if (s->chr) + qemu_chr_write(s->chr, &s->tx, 1); + else if (s->type == kbd) { + handle_kbd_command(s, val); + } + } + s->rregs[0] |= 4; // Tx buffer empty + s->rregs[1] |= 1; // All sent + set_txint(s); + break; default: - break; + break; } } static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) { - SerialState *ser = opaque; + SerialState *serial = opaque; ChannelState *s; uint32_t saddr; uint32_t ret; @@ -454,24 +456,24 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) saddr = (addr & 3) >> 1; channel = (addr & SERIAL_MAXADDR) >> 2; - s = &ser->chn[channel]; + s = &serial->chn[channel]; switch (saddr) { case 0: - SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); - ret = s->rregs[s->reg]; - s->reg = 0; - return ret; + SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); + ret = s->rregs[s->reg]; + s->reg = 0; + return ret; case 1: - s->rregs[0] &= ~1; + s->rregs[0] &= ~1; clr_rxint(s); - if (s->type == kbd || s->type == mouse) - ret = get_queue(s); - else - ret = s->rx; - SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); - return ret; + if (s->type == kbd || s->type == mouse) + ret = get_queue(s); + else + ret = s->rx; + SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); + return ret; default: - break; + break; } return 0; } @@ -482,10 +484,10 @@ static int serial_can_receive(void *opaque) int ret; if (((s->wregs[3] & 1) == 0) // Rx not enabled - || ((s->rregs[0] & 1) == 1)) // char already available - ret = 0; + || ((s->rregs[0] & 1) == 1)) // char already available + ret = 0; else - ret = 1; + ret = 1; //SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret); return ret; } @@ -582,7 +584,7 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) ret = slavio_serial_load_chn(f, &s->chn[0], version_id); if (ret != 0) - return ret; + return ret; ret = slavio_serial_load_chn(f, &s->chn[1], version_id); return ret; @@ -605,13 +607,13 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, s->chn[1].chr = chr2; for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; - s->chn[i].chn = 1 - i; - s->chn[i].type = ser; - if (s->chn[i].chr) { - qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, + s->chn[i].irq = irq; + s->chn[i].chn = 1 - i; + s->chn[i].type = ser; + if (s->chn[i].chr) { + qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, serial_receive1, serial_event, &s->chn[i]); - } + } } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; @@ -632,37 +634,89 @@ static const uint8_t keycodes[128] = { 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, }; +static const uint8_t e0_keycodes[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112, + 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + static void sunkbd_event(void *opaque, int ch) { ChannelState *s = opaque; int release = ch & 0x80; - ch = keycodes[ch & 0x7f]; - KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press"); + KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : "press"); + switch (ch) { + case 58: // Caps lock press + s->caps_lock_mode ^= 1; + if (s->caps_lock_mode == 2) + return; // Drop second press + break; + case 69: // Num lock press + s->num_lock_mode ^= 1; + if (s->num_lock_mode == 2) + return; // Drop second press + break; + case 186: // Caps lock release + s->caps_lock_mode ^= 2; + if (s->caps_lock_mode == 3) + return; // Drop first release + break; + case 197: // Num lock release + s->num_lock_mode ^= 2; + if (s->num_lock_mode == 3) + return; // Drop first release + break; + case 0xe0: + s->e0_mode = 1; + return; + default: + break; + } + if (s->e0_mode) { + s->e0_mode = 0; + ch = e0_keycodes[ch & 0x7f]; + } else { + ch = keycodes[ch & 0x7f]; + } + KBD_DPRINTF("Translated keycode %2.2x\n", ch); put_queue(s, ch | release); } static void handle_kbd_command(ChannelState *s, int val) { KBD_DPRINTF("Command %d\n", val); + if (s->led_mode) { // Ignore led byte + s->led_mode = 0; + return; + } switch (val) { case 1: // Reset, return type code clear_queue(s); - put_queue(s, 0xff); - put_queue(s, 4); // Type 4 - break; + put_queue(s, 0xff); + put_queue(s, 4); // Type 4 + put_queue(s, 0x7f); + break; + case 0xe: // Set leds + s->led_mode = 1; + break; case 7: // Query layout case 0xf: clear_queue(s); - put_queue(s, 0xfe); - put_queue(s, 19); // XXX, layout? - break; + put_queue(s, 0xfe); + put_queue(s, 0); // XXX, layout? + break; default: - break; + break; } } -static void sunmouse_event(void *opaque, +static void sunmouse_event(void *opaque, int dx, int dy, int dz, int buttons_state) { ChannelState *s = opaque; @@ -714,9 +768,9 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq) if (!s) return; for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; - s->chn[i].chn = 1 - i; - s->chn[i].chr = NULL; + s->chn[i].irq = irq; + s->chn[i].chn = 1 - i; + s->chn[i].chr = NULL; } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0];