Beispiel #1
0
static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
{
    SerialState *ser = opaque;
    ChannelState *s;
    uint32_t saddr;
    uint32_t ret;
    int channel;

    saddr = (addr & 3) >> 1;
    channel = (addr & SERIAL_MAXADDR) >> 2;
    s = &ser->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;
    case 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;
    default:
	break;
    }
    return 0;
}
Beispiel #2
0
static void serial_receive_byte(ChannelState *s, int ch)
{
    SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
    s->rregs[0] |= 1;
    s->rx = ch;
    set_rxint(s);
}
Beispiel #3
0
static void slavio_serial_update_parameters(ChannelState *s)
{
    int speed, parity, data_bits, stop_bits;
    QEMUSerialSetParams ssp;

    if (!s->chr || s->type != ser)
        return;

    if (s->wregs[4] & 1) {
        if (s->wregs[4] & 2)
            parity = 'E';
        else
            parity = 'O';
    } else {
        parity = 'N';
    }
    if ((s->wregs[4] & 0x0c) == 0x0c)
        stop_bits = 2;
    else
        stop_bits = 1;
    switch (s->wregs[5] & 0x60) {
    case 0x00:
        data_bits = 5;
        break;
    case 0x20:
        data_bits = 7;
        break;
    case 0x40:
        data_bits = 6;
        break;
    default:
    case 0x60:
        data_bits = 8;
        break;
    }
    speed = 2457600 / ((s->wregs[12] | (s->wregs[13] << 8)) + 2);
    switch (s->wregs[4] & 0xc0) {
    case 0x00:
        break;
    case 0x40:
        speed /= 16;
        break;
    case 0x80:
        speed /= 32;
        break;
    default:
    case 0xc0:
        speed /= 64;
        break;
    }
    ssp.speed = speed;
    ssp.parity = parity;
    ssp.data_bits = data_bits;
    ssp.stop_bits = stop_bits;
    SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
                speed, parity, data_bits, stop_bits);
    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
Beispiel #4
0
static void slavio_serial_update_parameters(ChannelState *s)
{
    int speed, parity, data_bits, stop_bits;
    QEMUSerialSetParams ssp;

    if (!s->chr || s->type != ser)
        return;

    if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
        if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
            parity = 'E';
        else
            parity = 'O';
    } else {
        parity = 'N';
    }
    if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
        stop_bits = 2;
    else
        stop_bits = 1;
    switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
    case TXCTRL2_5BITS:
        data_bits = 5;
        break;
    case TXCTRL2_7BITS:
        data_bits = 7;
        break;
    case TXCTRL2_6BITS:
        data_bits = 6;
        break;
    default:
    case TXCTRL2_8BITS:
        data_bits = 8;
        break;
    }
    speed = 2457600 / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
    switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
    case TXCTRL1_CLK1X:
        break;
    case TXCTRL1_CLK16X:
        speed /= 16;
        break;
    case TXCTRL1_CLK32X:
        speed /= 32;
        break;
    default:
    case TXCTRL1_CLK64X:
        speed /= 64;
        break;
    }
    ssp.speed = speed;
    ssp.parity = parity;
    ssp.data_bits = data_bits;
    ssp.stop_bits = stop_bits;
    SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
                speed, parity, data_bits, stop_bits);
    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
Beispiel #5
0
static void slavio_serial_update_irq(ChannelState *s)
{
    int irq;

    irq = slavio_serial_update_irq_chn(s);
    irq |= slavio_serial_update_irq_chn(s->otherchn);

    SER_DPRINTF("IRQ = %d\n", irq);
    qemu_set_irq(s->irq, irq);
}
Beispiel #6
0
static void put_queue(void *opaque, int b)
{
    ChannelState *s = opaque;
    SERIOQueue *q = &s->queue;

    SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
    if (q->count >= SERIO_QUEUE_SIZE)
        return;
    q->data[q->wptr] = b;
    if (++q->wptr == SERIO_QUEUE_SIZE)
        q->wptr = 0;
    q->count++;
    serial_receive_byte(s, 0);
}
Beispiel #7
0
static uint32_t get_queue(void *opaque)
{
    ChannelState *s = opaque;
    SERIOQueue *q = &s->queue;
    int val;

    if (q->count == 0) {
        return 0;
    } else {
        val = q->data[q->rptr];
        if (++q->rptr == SERIO_QUEUE_SIZE)
            q->rptr = 0;
        q->count--;
    }
    SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
    if (q->count > 0)
        serial_receive_byte(s, 0);
    return val;
}
Beispiel #8
0
static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
    SerialState *ser = opaque;
    ChannelState *s;
    uint32_t saddr;
    int newreg, channel;

    val &= 0xff;
    saddr = (addr & 3) >> 1;
    channel = (addr & SERIAL_MAXADDR) >> 2;
    s = &ser->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:
                clr_txint(s);
		break;
	    case 0x38:
                if (s->rxint_under_svc)
                    clr_rxint(s);
                else if (s->txint_under_svc)
                    clr_txint(s);
		break;
	    default:
		break;
	    }
	    break;
        case 1 ... 3:
        case 6 ... 8:
        case 10 ... 11:
        case 14 ... 15:
	    s->wregs[s->reg] = val;
	    break;
        case 4:
        case 5:
        case 12:
        case 13:
	    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;
    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;
    default:
	break;
    }
}
Beispiel #9
0
static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr,
                                     uint32_t val)
{
    SerialState *serial = opaque;
    ChannelState *s;
    uint32_t saddr;
    int newreg, channel;

    val &= 0xff;
    saddr = (addr & 3) >> 1;
    channel = (addr & SERIAL_MAXADDR) >> 2;
    s = &serial->chn[channel];
    switch (saddr) {
    case SERIAL_CTRL:
        SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
                    val & 0xff);
        newreg = 0;
        switch (s->reg) {
        case W_CMD:
            newreg = val & CMD_PTR_MASK;
            val &= CMD_CMD_MASK;
            switch (val) {
            case CMD_HI:
                newreg |= CMD_HI;
                break;
            case CMD_CLR_TXINT:
                clr_txint(s);
                break;
            case CMD_CLR_IUS:
                if (s->rxint_under_svc)
                    clr_rxint(s);
                else if (s->txint_under_svc)
                    clr_txint(s);
                break;
            default:
                break;
            }
            break;
        case W_INTR ... W_RXCTRL:
        case W_SYNC1 ... W_TXBUF:
        case W_MISC1 ... W_CLOCK:
        case W_MISC2 ... W_EXTINT:
            s->wregs[s->reg] = val;
            break;
        case W_TXCTRL1:
        case W_TXCTRL2:
        case W_BRGLO:
        case W_BRGHI:
            s->wregs[s->reg] = val;
            slavio_serial_update_parameters(s);
            break;
        case W_MINTR:
            switch (val & MINTR_RST_MASK) {
            case 0:
            default:
                break;
            case MINTR_RST_B:
                slavio_serial_reset_chn(&serial->chn[1]);
                return;
            case MINTR_RST_A:
                slavio_serial_reset_chn(&serial->chn[0]);
                return;
            case MINTR_RST_ALL:
                slavio_serial_reset(serial);
                return;
            }
            break;
        default:
            break;
        }
        if (s->reg == 0)
            s->reg = newreg;
        else
            s->reg = 0;
        break;
    case SERIAL_DATA:
        SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
        s->tx = val;
        if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
            if (s->chr)
                qemu_chr_write(s->chr, &s->tx, 1);
            else if (s->type == kbd && !s->disabled) {
                handle_kbd_command(s, val);
            }
        }
        s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
        s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
        set_txint(s);
        break;
    default:
        break;
    }
}