mirror of https://gitee.com/openkylin/qemu.git
PC Chipset: Improve serial divisor calculation
This fixes several problems I found in the UART serial implementation. Now all divisor values are allowed, while before divisor values of zero and below the base baud rate were rejected. All changes are in reference to http://www.sci.muni.cz/docs/pc/serport.txt Signed-off-by: Calvin Lee <cyrus296@gmail.com> Message-Id: <20180512000545.966-2-cyrus296@gmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
9ee8a692f1
commit
0147883450
|
@ -150,13 +150,10 @@ static void serial_update_irq(SerialState *s)
|
||||||
|
|
||||||
static void serial_update_parameters(SerialState *s)
|
static void serial_update_parameters(SerialState *s)
|
||||||
{
|
{
|
||||||
int speed, parity, data_bits, stop_bits, frame_size;
|
float speed;
|
||||||
|
int parity, data_bits, stop_bits, frame_size;
|
||||||
QEMUSerialSetParams ssp;
|
QEMUSerialSetParams ssp;
|
||||||
|
|
||||||
if (s->divider == 0 || s->divider > s->baudbase) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start bit. */
|
/* Start bit. */
|
||||||
frame_size = 1;
|
frame_size = 1;
|
||||||
if (s->lcr & 0x08) {
|
if (s->lcr & 0x08) {
|
||||||
|
@ -169,14 +166,16 @@ static void serial_update_parameters(SerialState *s)
|
||||||
} else {
|
} else {
|
||||||
parity = 'N';
|
parity = 'N';
|
||||||
}
|
}
|
||||||
if (s->lcr & 0x04)
|
if (s->lcr & 0x04) {
|
||||||
stop_bits = 2;
|
stop_bits = 2;
|
||||||
else
|
} else {
|
||||||
stop_bits = 1;
|
stop_bits = 1;
|
||||||
|
}
|
||||||
|
|
||||||
data_bits = (s->lcr & 0x03) + 5;
|
data_bits = (s->lcr & 0x03) + 5;
|
||||||
frame_size += data_bits + stop_bits;
|
frame_size += data_bits + stop_bits;
|
||||||
speed = s->baudbase / s->divider;
|
/* Zero divisor should give about 3500 baud */
|
||||||
|
speed = (s->divider == 0) ? 3500 : (float) s->baudbase / s->divider;
|
||||||
ssp.speed = speed;
|
ssp.speed = speed;
|
||||||
ssp.parity = parity;
|
ssp.parity = parity;
|
||||||
ssp.data_bits = data_bits;
|
ssp.data_bits = data_bits;
|
||||||
|
@ -184,7 +183,7 @@ static void serial_update_parameters(SerialState *s)
|
||||||
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
|
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
|
||||||
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
|
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
|
||||||
|
|
||||||
DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
|
DPRINTF("speed=%.2f parity=%c data=%d stop=%d\n",
|
||||||
speed, parity, data_bits, stop_bits);
|
speed, parity, data_bits, stop_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,7 +340,11 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
default:
|
default:
|
||||||
case 0:
|
case 0:
|
||||||
if (s->lcr & UART_LCR_DLAB) {
|
if (s->lcr & UART_LCR_DLAB) {
|
||||||
s->divider = (s->divider & 0xff00) | val;
|
if (size == 2) {
|
||||||
|
s->divider = (s->divider & 0xff00) | val;
|
||||||
|
} else if (size == 4) {
|
||||||
|
s->divider = val;
|
||||||
|
}
|
||||||
serial_update_parameters(s);
|
serial_update_parameters(s);
|
||||||
} else {
|
} else {
|
||||||
s->thr = (uint8_t) val;
|
s->thr = (uint8_t) val;
|
||||||
|
|
Loading…
Reference in New Issue