diff options
Diffstat (limited to 'c')
-rw-r--r-- | c/src/lib/libchip/serial/STATUS | 5 | ||||
-rw-r--r-- | c/src/lib/libchip/serial/ns16550.c | 193 | ||||
-rw-r--r-- | c/src/lib/libchip/serial/ns16550_p.h | 11 | ||||
-rw-r--r-- | c/src/libchip/serial/STATUS | 5 | ||||
-rw-r--r-- | c/src/libchip/serial/ns16550.c | 193 | ||||
-rw-r--r-- | c/src/libchip/serial/ns16550_p.h | 11 |
6 files changed, 168 insertions, 250 deletions
diff --git a/c/src/lib/libchip/serial/STATUS b/c/src/lib/libchip/serial/STATUS index c5cf7da1b7..16c256615e 100644 --- a/c/src/lib/libchip/serial/STATUS +++ b/c/src/lib/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/lib/libchip/serial/ns16550.c b/c/src/lib/libchip/serial/ns16550.c index 8b962b9844..21bc839002 100644 --- a/c/src/lib/libchip/serial/ns16550.c +++ b/c/src/lib/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<len;) { - if(Ring_buffer_Is_full(&Console_Port_Data[minor].TxBuffer)) { - if(!Console_Port_Data[minor].bActive) { - /* - * Wake up the device - */ - rtems_interrupt_disable(Irql); - Console_Port_Data[minor].bActive = TRUE; - if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) { - ns16550_assert_RTS(minor); - } - ns16550_process(minor); - rtems_interrupt_enable(Irql); - } else { - /* - * Yield - */ - rtems_task_wake_after(RTEMS_YIELD_PROCESSOR); - } + unsigned32 Irql; + unsigned32 pNS16550; + setRegister_f setReg; - /* - * Wait for ring buffer to empty - */ - continue; - } - else { - Ring_buffer_Add_character( &Console_Port_Data[minor].TxBuffer, buf[i]); - i++; - } - } + setReg = Console_Port_Tbl[minor].setRegister; + pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1; /* - * Ensure that characters are on the way + * We are using interrupt driven output and termios only sends us + * one character at a time. */ - if(!Console_Port_Data[minor].bActive) { - /* - * Wake up the device - */ - rtems_interrupt_disable(Irql); - Console_Port_Data[minor].bActive = TRUE; - if(Console_Port_Tbl[minor].pDeviceFlow !=&ns16550_flow_RTSCTS) { - ns16550_assert_RTS(minor); - } - ns16550_process(minor); - rtems_interrupt_enable(Irql); + + if ( !len ) + return 0; + + if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) { + ns16550_assert_RTS(minor); } - return (len); + rtems_interrupt_disable(Irql); + if ( Console_Port_Data[minor].bActive == FALSE) { + Console_Port_Data[minor].bActive = TRUE; + ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR); + } + (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, *buf); + rtems_interrupt_enable(Irql); + + return 1; } /* @@ -544,6 +496,7 @@ NS16550_STATIC int ns16550_write_support_int( * Console Termios output entry point. * */ + NS16550_STATIC int ns16550_write_support_polled( int minor, const char *buf, diff --git a/c/src/lib/libchip/serial/ns16550_p.h b/c/src/lib/libchip/serial/ns16550_p.h index 95d4ec77b1..1ffd0725c7 100644 --- a/c/src/lib/libchip/serial/ns16550_p.h +++ b/c/src/lib/libchip/serial/ns16550_p.h @@ -82,6 +82,10 @@ typedef volatile struct _SP_WRITE_REGISTERS { #define SP_INT_LS_ENABLE 0x04 #define SP_INT_MS_ENABLE 0x08 +#define NS16550_ENABLE_ALL_INTR (SP_INT_RX_ENABLE | SP_INT_TX_ENABLE) +#define NS16550_DISABLE_ALL_INTR 0x00 +#define NS16550_ENABLE_ALL_INTR_EXCEPT_TX (SP_INT_RX_ENABLE) + /* * Define serial port interrupt id register structure. */ @@ -201,8 +205,6 @@ NS16550_STATIC int ns16550_negate_DTR( NS16550_STATIC void ns16550_initialize_interrupts(int minor); -NS16550_STATIC int ns16550_flush(int major, int minor, void *arg); - NS16550_STATIC int ns16550_write_support_int( int minor, const char *buf, @@ -219,6 +221,11 @@ NS16550_STATIC int ns16550_inbyte_nonblocking_polled( int minor ); +NS16550_STATIC void ns16550_enable_interrupts( + int minor, + int mask +); + #ifdef __cplusplus } #endif 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<len;) { - if(Ring_buffer_Is_full(&Console_Port_Data[minor].TxBuffer)) { - if(!Console_Port_Data[minor].bActive) { - /* - * Wake up the device - */ - rtems_interrupt_disable(Irql); - Console_Port_Data[minor].bActive = TRUE; - if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) { - ns16550_assert_RTS(minor); - } - ns16550_process(minor); - rtems_interrupt_enable(Irql); - } else { - /* - * Yield - */ - rtems_task_wake_after(RTEMS_YIELD_PROCESSOR); - } + unsigned32 Irql; + unsigned32 pNS16550; + setRegister_f setReg; - /* - * Wait for ring buffer to empty - */ - continue; - } - else { - Ring_buffer_Add_character( &Console_Port_Data[minor].TxBuffer, buf[i]); - i++; - } - } + setReg = Console_Port_Tbl[minor].setRegister; + pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1; /* - * Ensure that characters are on the way + * We are using interrupt driven output and termios only sends us + * one character at a time. */ - if(!Console_Port_Data[minor].bActive) { - /* - * Wake up the device - */ - rtems_interrupt_disable(Irql); - Console_Port_Data[minor].bActive = TRUE; - if(Console_Port_Tbl[minor].pDeviceFlow !=&ns16550_flow_RTSCTS) { - ns16550_assert_RTS(minor); - } - ns16550_process(minor); - rtems_interrupt_enable(Irql); + + if ( !len ) + return 0; + + if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) { + ns16550_assert_RTS(minor); } - return (len); + rtems_interrupt_disable(Irql); + if ( Console_Port_Data[minor].bActive == FALSE) { + Console_Port_Data[minor].bActive = TRUE; + ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR); + } + (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, *buf); + rtems_interrupt_enable(Irql); + + return 1; } /* @@ -544,6 +496,7 @@ NS16550_STATIC int ns16550_write_support_int( * Console Termios output entry point. * */ + NS16550_STATIC int ns16550_write_support_polled( int minor, const char *buf, diff --git a/c/src/libchip/serial/ns16550_p.h b/c/src/libchip/serial/ns16550_p.h index 95d4ec77b1..1ffd0725c7 100644 --- a/c/src/libchip/serial/ns16550_p.h +++ b/c/src/libchip/serial/ns16550_p.h @@ -82,6 +82,10 @@ typedef volatile struct _SP_WRITE_REGISTERS { #define SP_INT_LS_ENABLE 0x04 #define SP_INT_MS_ENABLE 0x08 +#define NS16550_ENABLE_ALL_INTR (SP_INT_RX_ENABLE | SP_INT_TX_ENABLE) +#define NS16550_DISABLE_ALL_INTR 0x00 +#define NS16550_ENABLE_ALL_INTR_EXCEPT_TX (SP_INT_RX_ENABLE) + /* * Define serial port interrupt id register structure. */ @@ -201,8 +205,6 @@ NS16550_STATIC int ns16550_negate_DTR( NS16550_STATIC void ns16550_initialize_interrupts(int minor); -NS16550_STATIC int ns16550_flush(int major, int minor, void *arg); - NS16550_STATIC int ns16550_write_support_int( int minor, const char *buf, @@ -219,6 +221,11 @@ NS16550_STATIC int ns16550_inbyte_nonblocking_polled( int minor ); +NS16550_STATIC void ns16550_enable_interrupts( + int minor, + int mask +); + #ifdef __cplusplus } #endif |