mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
allow host serial port usage (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2153 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
6bcb76c3b6
commit
35db099ddb
1 changed files with 88 additions and 22 deletions
|
@ -74,6 +74,8 @@ typedef enum {
|
|||
chn_a, chn_b,
|
||||
} chn_id_t;
|
||||
|
||||
#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
|
||||
|
||||
typedef enum {
|
||||
ser, kbd, mouse,
|
||||
} chn_type_t;
|
||||
|
@ -113,7 +115,7 @@ static void put_queue(void *opaque, int b)
|
|||
ChannelState *s = opaque;
|
||||
SERIOQueue *q = &s->queue;
|
||||
|
||||
SER_DPRINTF("put: 0x%02x\n", b);
|
||||
SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
|
||||
if (q->count >= SERIO_QUEUE_SIZE)
|
||||
return;
|
||||
q->data[q->wptr] = b;
|
||||
|
@ -137,7 +139,7 @@ static uint32_t get_queue(void *opaque)
|
|||
q->rptr = 0;
|
||||
q->count--;
|
||||
}
|
||||
KBD_DPRINTF("get 0x%02x\n", val);
|
||||
KBD_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
|
||||
if (q->count > 0)
|
||||
serial_receive_byte(s, 0);
|
||||
return val;
|
||||
|
@ -198,11 +200,10 @@ static inline void clr_rxint(ChannelState *s)
|
|||
{
|
||||
s->rxint = 0;
|
||||
s->rxint_under_svc = 0;
|
||||
if (s->chn == 0)
|
||||
if (s->chn == chn_a)
|
||||
s->rregs[3] &= ~0x20;
|
||||
else {
|
||||
else
|
||||
s->otherchn->rregs[3] &= ~4;
|
||||
}
|
||||
if (s->txint)
|
||||
set_txint(s);
|
||||
else
|
||||
|
@ -215,11 +216,10 @@ static inline void set_rxint(ChannelState *s)
|
|||
s->rxint = 1;
|
||||
if (!s->txint_under_svc) {
|
||||
s->rxint_under_svc = 1;
|
||||
if (s->chn == 0)
|
||||
if (s->chn == chn_a)
|
||||
s->rregs[3] |= 0x20;
|
||||
else {
|
||||
else
|
||||
s->otherchn->rregs[3] |= 4;
|
||||
}
|
||||
s->rregs[2] = 4;
|
||||
slavio_serial_update_irq(s);
|
||||
}
|
||||
|
@ -229,11 +229,10 @@ static inline void clr_txint(ChannelState *s)
|
|||
{
|
||||
s->txint = 0;
|
||||
s->txint_under_svc = 0;
|
||||
if (s->chn == 0)
|
||||
if (s->chn == chn_a)
|
||||
s->rregs[3] &= ~0x10;
|
||||
else {
|
||||
else
|
||||
s->otherchn->rregs[3] &= ~2;
|
||||
}
|
||||
if (s->rxint)
|
||||
set_rxint(s);
|
||||
else
|
||||
|
@ -246,16 +245,74 @@ static inline void set_txint(ChannelState *s)
|
|||
s->txint = 1;
|
||||
if (!s->rxint_under_svc) {
|
||||
s->txint_under_svc = 1;
|
||||
if (s->chn == 0)
|
||||
if (s->chn == chn_a)
|
||||
s->rregs[3] |= 0x10;
|
||||
else {
|
||||
else
|
||||
s->otherchn->rregs[3] |= 2;
|
||||
}
|
||||
s->rregs[2] = 0;
|
||||
slavio_serial_update_irq(s);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
SerialState *ser = opaque;
|
||||
|
@ -269,7 +326,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
|
|||
s = &ser->chn[channel];
|
||||
switch (saddr) {
|
||||
case 0:
|
||||
SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
|
||||
SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff);
|
||||
newreg = 0;
|
||||
switch (s->reg) {
|
||||
case 0:
|
||||
|
@ -292,10 +349,19 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 1 ... 8:
|
||||
case 10 ... 15:
|
||||
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:
|
||||
|
@ -321,7 +387,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
|
|||
s->reg = 0;
|
||||
break;
|
||||
case 1:
|
||||
SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
|
||||
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)
|
||||
|
@ -352,7 +418,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
|
|||
s = &ser->chn[channel];
|
||||
switch (saddr) {
|
||||
case 0:
|
||||
SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
|
||||
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;
|
||||
|
@ -363,7 +429,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
|
|||
ret = get_queue(s);
|
||||
else
|
||||
ret = s->rx;
|
||||
SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret);
|
||||
SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
|
||||
return ret;
|
||||
default:
|
||||
break;
|
||||
|
@ -381,13 +447,13 @@ static int serial_can_receive(void *opaque)
|
|||
ret = 0;
|
||||
else
|
||||
ret = 1;
|
||||
SER_DPRINTF("can receive %d\n", ret);
|
||||
//SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void serial_receive_byte(ChannelState *s, int ch)
|
||||
{
|
||||
SER_DPRINTF("put ch %d\n", ch);
|
||||
SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
|
||||
s->rregs[0] |= 1;
|
||||
s->rx = ch;
|
||||
set_rxint(s);
|
||||
|
|
Loading…
Reference in a new issue