This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

pc_serial fifo + hanging fixes


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);
  }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]