This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
pc_serial fifo + hanging fixes
- To: ecos-discuss at sourceware dot cygnus dot com
- Subject: [ECOS] pc_serial fifo + hanging fixes
- From: Rolf Manderscheid <rvm at yottayotta dot com>
- Date: Tue, 7 Nov 2000 21:13:19 -0700
There are a couple of problems with the serial driver on the pc platform:
1) it never uses the fifo:
in the function pc_serial_config_port(), there are a couple of reads
of the scratch register of the uart to determine whether we have
a 16450 or better. Unfortunately, this test:
pc_outb(port->base + SCR, 0xAA) ;
if (pc_inb(port->base + SCR) != 0xAA)
break;
will never succeed, because the definition of pc_inb is (in vectors.S):
movl 4(%esp), %edx
inb %dx, %al
cbtw
cwtl
ret
and is declared in plf_misc.h like this:
int pc_inb(int port);
So, the correct value 0xAA is read from the scratch register, and then
sign extended to a 32 bit integer.
I think the declaration ought to be:
cyg_uint8 pc_inb(int port);
and the definition could drop the sign extensions which would then be
rendered no-ops. Similarly for pc_inw(). I looked briefly at the other
uses of pc_in* and they all seemed to expect an appropriately sized
return value. I made the change in my copy but I can't claim extensive
testing. I can guarantee that it will use the fifo after this change.
2) it can hang:
This is probably a rare problem for most people, but I've turned off the
cache for an unrelated reason, and the resulting sluggish cpu opens up a
big hole. I vaguely recall someone complaining about the paltry 38400
rate on the serial port, this might be why it got turned down so low.
Anyway, the problem lies in pc_serial_DSR ... not all possible sources
of the interrupt are dealt with. My (small!) patch is included below.
The change of the test from (isr == ISR_Rx) to (isr & ISR_Rx) is
important, because having the fifo enabled will occasionally set bit 3
of the isr.
Cheers!
Rolf
----
Rolf Manderscheid YottaYotta, Inc
rmanderscheid@YottaYotta.com #301, 10328 81 Ave
780.439.9000 Edmonton, Alberta, Cananda T6E 1X2
*** pc_serial.c 2000/08/09 17:27:50 1.1
--- pc_serial.c 2000/10/20 20:19:14 1.2
***************
*** 381,398 ****
serial_channel *chan = (serial_channel *)data;
pc_serial_info *port = (pc_serial_info *)chan->dev_priv;
unsigned char isr;
! isr = pc_inb(port->base + ISR) & 0x0E;
! if (isr == ISR_Tx)
! { port->charsInTransmitter = 0 ;
! (chan->callbacks->xmt_char)(chan);
! } else if (isr == ISR_Rx)
! {
! // If we've got s16550a, then read all the characters in the fifo.
! while (pc_inb(port->base + LSR) & LSR_RSR)
! {
! char c = pc_inb(port->base + RHR);
! (chan->callbacks->rcv_char)(chan, c);
! }
}
cyg_drv_interrupt_unmask(port->int_num);
}
--- 381,402 ----
serial_channel *chan = (serial_channel *)data;
pc_serial_info *port = (pc_serial_info *)chan->dev_priv;
unsigned char isr;
!
! while (1) {
! isr = pc_inb(port->base + ISR) & 0x0E;
! if (isr & ISR_Tx) {
! port->charsInTransmitter = 0 ;
! (chan->callbacks->xmt_char)(chan);
! } else if (isr & ISR_Rx) {
! // If we've got s16550a, then read all the characters in the fifo.
! while (pc_inb(port->base + LSR) & LSR_RSR)
! {
! char c = pc_inb(port->base + RHR);
! (chan->callbacks->rcv_char)(chan, c);
! }
! } else {
! break;
! }
}
cyg_drv_interrupt_unmask(port->int_num);
}