From 70a94515a7f0e6de540894beae14fb9534cdc21e Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Sat, 25 Jul 1998 16:53:21 +0000 Subject: Rewrote NS16550 TX interrupt processing to use termios for the buffer and manage the interrupt sources like the other drivers. This let use remove the ns16550_flush() routine. --- c/src/libchip/serial/STATUS | 5 +- c/src/libchip/serial/ns16550.c | 193 +++++++++++++++------------------------ c/src/libchip/serial/ns16550_p.h | 11 ++- 3 files changed, 84 insertions(+), 125 deletions(-) (limited to 'c/src/libchip') diff --git a/c/src/libchip/serial/STATUS b/c/src/libchip/serial/STATUS index c5cf7da1b7..16c256615e 100644 --- a/c/src/libchip/serial/STATUS +++ b/c/src/libchip/serial/STATUS @@ -35,9 +35,8 @@ NS16650 + Not tested in libchip context. Based on Radstone PPC2 driver which worked well. -+ Interrupt code needs to be reworked to eliminate Ring_buffer usage. This - will probably require managing the interrupt mask register as is - done in the mc68681 and z85c30 drivers. ++ Interrupt code has been reworked to not use ring buffer and may be broken + as it has not been tested since this was done. + Missing set attributes function. diff --git a/c/src/libchip/serial/ns16550.c b/c/src/libchip/serial/ns16550.c index 8b962b9844..21bc839002 100644 --- a/c/src/libchip/serial/ns16550.c +++ b/c/src/libchip/serial/ns16550.c @@ -48,7 +48,7 @@ console_fns ns16550_fns = { libchip_serial_default_probe, /* deviceProbe */ ns16550_open, /* deviceFirstOpen */ - ns16550_flush, /* deviceLastClose */ + NULL, /* deviceLastClose */ NULL, /* deviceRead */ ns16550_write_support_int, /* deviceWrite */ ns16550_initialize_interrupts, /* deviceInitialize */ @@ -97,13 +97,15 @@ NS16550_STATIC void ns16550_init(int minor) */ (*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0); - (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, 0x0); + ns16550_enable_interrupts(minor, NS16550_DISABLE_ALL_INTR); /* Set the divisor latch and set the baud rate. */ ulBaudDivisor=NS16550_Baud((unsigned32)Console_Port_Tbl[minor].pDeviceParams); ucDataByte = SP_LINE_DLAB; (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte); + + /* XXX */ (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff); (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff); @@ -119,11 +121,7 @@ NS16550_STATIC void ns16550_init(int minor) ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST; (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte); - /* - * Disable interrupts - */ - ucDataByte = 0; - (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, ucDataByte); + ns16550_enable_interrupts(minor, NS16550_DISABLE_ALL_INTR); /* Set data terminal ready. */ /* And open interrupt tristate line */ @@ -169,6 +167,7 @@ NS16550_STATIC int ns16550_close( /* * ns16550_write_polled */ + NS16550_STATIC void ns16550_write_polled( int minor, char cChar @@ -335,7 +334,7 @@ NS16550_STATIC void ns16550_process( unsigned32 pNS16550; volatile unsigned8 ucLineStatus; volatile unsigned8 ucInterruptId; - char cChar; + unsigned char cChar; getRegister_f getReg; setRegister_f setReg; @@ -360,39 +359,42 @@ NS16550_STATIC void ns16550_process( ); } + /* + * TX all the characters we can + */ + while(TRUE) { - if(Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) { - Console_Port_Data[minor].bActive=FALSE; - if(Console_Port_Tbl[minor].pDeviceFlow !=&ns16550_flow_RTSCTS) { - ns16550_negate_RTS(minor); + ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS); + if(~ucLineStatus & SP_LSR_THOLD) { + /* + * We'll get another interrupt when + * the transmitter holding reg. becomes + * free again + */ + break; } - /* - * There is no data to transmit - */ - break; - } +#if 0 + /* XXX flow control not completely supported in libchip */ - ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS); - if(~ucLineStatus & SP_LSR_THOLD) { - /* - * We'll get another interrupt when - * the transmitter holding reg. becomes - * free again - */ + if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) { + ns16550_negate_RTS(minor); + } +#endif + + if (!rtems_termios_dequeue_characters( + Console_Port_Data[minor].termios_data, 1)) { + if (Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) { + ns16550_negate_RTS(minor); + } + Console_Port_Data[minor].bActive = FALSE; + ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR_EXCEPT_TX); break; } - Ring_buffer_Remove_character( &Console_Port_Data[minor].TxBuffer, cChar); - /* - * transmit character - */ - (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, cChar); + ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID); } - - ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID); - } - while((ucInterruptId&0xf)!=0x1); + } while((ucInterruptId&0xf)!=0x1); } NS16550_STATIC rtems_isr ns16550_isr( @@ -410,132 +412,82 @@ NS16550_STATIC rtems_isr ns16550_isr( } /* - * ns16550_flush - */ -NS16550_STATIC int ns16550_flush(int major, int minor, void *arg) -{ - while(!Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) { - /* - * Yield while we wait - */ - if(_System_state_Is_up(_System_state_Get())) { - rtems_task_wake_after(RTEMS_YIELD_PROCESSOR); - } - } - - ns16550_close(major, minor, arg); - - return(RTEMS_SUCCESSFUL); -} - -/* - * ns16550_initialize_interrupts - * - * This routine initializes the console's receive and transmit - * ring buffers and loads the appropriate vectors to handle the interrupts. + * ns16550_enable_interrupts * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: NONE + * This routine initializes the port to have the specified interrupts masked. */ NS16550_STATIC void ns16550_enable_interrupts( - int minor + int minor, + int mask ) { - unsigned32 pNS16550; - unsigned8 ucDataByte; - setRegister_f setReg; + unsigned32 pNS16550; + setRegister_f setReg; pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1; setReg = Console_Port_Tbl[minor].setRegister; - /* - * Enable interrupts - */ - ucDataByte = SP_INT_RX_ENABLE | SP_INT_TX_ENABLE; - (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, ucDataByte); - + (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask); } +/* + * ns16550_initialize_interrupts + * + * This routine initializes the port to operate in interrupt driver mode. + */ + NS16550_STATIC void ns16550_initialize_interrupts(int minor) { ns16550_init(minor); - Ring_buffer_Initialize(&Console_Port_Data[minor].TxBuffer); - Console_Port_Data[minor].bActive = FALSE; set_vector(ns16550_isr, Console_Port_Tbl[minor].ulIntVector, 1); - ns16550_enable_interrupts(minor); + ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR); } /* * ns16550_write_support_int * * Console Termios output entry point. - * */ + NS16550_STATIC int ns16550_write_support_int( int minor, const char *buf, int len ) { - int i; - unsigned32 Irql; - - for(i=0; i