diff --git a/c/src/lib/libbsp/powerpc/shared/ChangeLog b/c/src/lib/libbsp/powerpc/shared/ChangeLog index bae1ecb54a..1c122761e0 100644 --- a/c/src/lib/libbsp/powerpc/shared/ChangeLog +++ b/c/src/lib/libbsp/powerpc/shared/ChangeLog @@ -1,3 +1,14 @@ +2003-02-20 Till Straumann + + PR 349/bsps + * console/console.c, console/uart.c, console/uart.h: implement + IOCTLs for the serial (UART) console to install/retrieve a BREAK-IRQ + callback. The callback routine (if installed) is invoked from the + UART ISR when a BREAK interrupt is detected. This can be used + e.g. to enforce a "hotkey" reboot a la vxWorks Ctrl-X (although we + use the serial line break condition) NOTE: The callback runs in + ISR context. + 2003-01-20 Joel Sherrill * startup/linkcmds*: Add FreeBSD sysctl() sections. diff --git a/c/src/lib/libbsp/powerpc/shared/console/console.c b/c/src/lib/libbsp/powerpc/shared/console/console.c index b6d9b73095..4fcef5a2a9 100644 --- a/c/src/lib/libbsp/powerpc/shared/console/console.c +++ b/c/src/lib/libbsp/powerpc/shared/console/console.c @@ -257,11 +257,24 @@ console_write(rtems_device_major_number major, * Handle ioctl request. */ rtems_device_driver -console_control(rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg +console_control(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { +/* does the BSP support break callbacks ? */ +#if defined(BIOCSETBREAKCB) && defined(BIOCGETBREAKCB) +rtems_libio_ioctl_args_t *ioa=arg; + switch (ioa->command) { + case BIOCSETBREAKCB: + return BSP_uart_set_break_cb(minor, ioa); + case BIOCGETBREAKCB: + return BSP_uart_get_break_cb(minor, ioa); + + default: + break; + } +#endif return rtems_termios_ioctl (arg); } diff --git a/c/src/lib/libbsp/powerpc/shared/console/polled_io.c b/c/src/lib/libbsp/powerpc/shared/console/polled_io.c index 18f67ac381..edc1f06f0a 100644 --- a/c/src/lib/libbsp/powerpc/shared/console/polled_io.c +++ b/c/src/lib/libbsp/powerpc/shared/console/polled_io.c @@ -888,7 +888,7 @@ static int skip_atoi(const char **s) * bloat has been limited since we basically only need %u, %x, %s and %c. * But we need 64 bit values ! */ -int vsprintf(char *buf, const char *fmt, va_list args); +int k_vsprintf(char *buf, const char *fmt, va_list args); int printk(const char *fmt, ...) { va_list args; @@ -897,7 +897,7 @@ int printk(const char *fmt, ...) { char buf[1024]; va_start(args, fmt); - i = vsprintf(buf, fmt, args); + i = k_vsprintf(buf, fmt, args); va_end(args); puts(buf); return i; @@ -988,7 +988,7 @@ static char * number(char * str, int size, int type, u64 num) return str; } -int vsprintf(char *buf, const char *fmt, va_list args) +int k_vsprintf(char *buf, const char *fmt, va_list args) { int len; u64 num; diff --git a/c/src/lib/libbsp/powerpc/shared/console/reboot.c b/c/src/lib/libbsp/powerpc/shared/console/reboot.c index a6e10db647..b6a760b532 100644 --- a/c/src/lib/libbsp/powerpc/shared/console/reboot.c +++ b/c/src/lib/libbsp/powerpc/shared/console/reboot.c @@ -1,6 +1,8 @@ /* $Id$ */ #include "console.inl" +#include +#include /*-------------------------------------------------------------------------+ | Function: rtemsReboot @@ -11,6 +13,8 @@ +--------------------------------------------------------------------------*/ void rtemsReboot(void) { + printk("Printing a stack trace for your convenience :-)\n"); + CPU_print_stack(); /* shutdown and reboot */ kbd_outb(0x4, 0xFE); /* use keyboard controler to do the job... */ } /* rtemsReboot */ diff --git a/c/src/lib/libbsp/powerpc/shared/console/uart.c b/c/src/lib/libbsp/powerpc/shared/console/uart.c index 8ad744d06b..bbaa1b5382 100644 --- a/c/src/lib/libbsp/powerpc/shared/console/uart.c +++ b/c/src/lib/libbsp/powerpc/shared/console/uart.c @@ -11,6 +11,7 @@ #include #include #include +#include #include /* @@ -19,9 +20,10 @@ struct uart_data { - unsigned long ioBase; - int hwFlow; - int baud; + unsigned long ioBase; + int hwFlow; + int baud; + BSP_UartBreakCbRec breakCallback; }; /* @@ -74,11 +76,13 @@ uwrite(int uart, int reg, unsigned int val) out_8((unsigned char*)(uart_data[uart].ioBase + reg), val); } +#define UARTDEBUG #ifdef UARTDEBUG static void -uartError(int uart) +uartError(int uart, void *termiosPrivate) { unsigned char uartStatus, dummy; + BSP_UartBreakCbProc h; uartStatus = uread(uart, LSR); dummy = uread(uart, RBR); @@ -89,19 +93,32 @@ uartError(int uart) printk("********* Parity Error **********\n"); if (uartStatus & FE) printk("********* Framing Error **********\n"); - if (uartStatus & BI) - printk("********* Parity Error **********\n"); + if (uartStatus & BI) { + printk("********* BREAK INTERRUPT *********\n"); + if ((h=uart_data[uart].breakCallback.handler)) + h(uart, + (dummy<<8)|uartStatus, + termiosPrivate, + uart_data[uart].breakCallback.private); + + } if (uartStatus & ERFIFO) printk("********* Error receive Fifo **********\n"); } #else -inline void uartError(int uart) +inline void uartError(int uart, void *termiosPrivate) { - unsigned char uartStatus; + unsigned char uartStatus,dummy; + BSP_UartBreakCbProc h; uartStatus = uread(uart, LSR); - uartStatus = uread(uart, RBR); + dummy = uread(uart, RBR); + if ((uartStatus & BI) && (h=uart_data[uart].breakCallback.handler)) + h(uart, + (dummy<<8)|uartStatus, + termiosPrivate, + uart_data[uart].breakCallback.private); } #endif @@ -644,7 +661,7 @@ BSP_uart_termios_isr_com(int uart) break; case RECEIVER_ERROR: /* RX error: eat character */ - uartError(uart); + uartError(uart, termios_ttyp_com[uart]); break; default: /* Should not happen */ @@ -666,3 +683,30 @@ BSP_uart_termios_isr_com2(void) BSP_uart_termios_isr_com(BSP_UART_COM2); } +/* retrieve 'break' handler info */ +int +BSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg) +{ +BSP_UartBreakCb cb=arg->buffer; +unsigned long flags; + SANITY_CHECK(uart); + rtems_interrupt_disable(flags); + *cb = uart_data[uart].breakCallback; + rtems_interrupt_enable(flags); + arg->ioctl_return=0; + return RTEMS_SUCCESSFUL; +} + +/* install 'break' handler */ +int +BSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg) +{ +BSP_UartBreakCb cb=arg->buffer; +unsigned long flags; + SANITY_CHECK(uart); + rtems_interrupt_disable(flags); + uart_data[uart].breakCallback = *cb; + rtems_interrupt_enable(flags); + arg->ioctl_return=0; + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/powerpc/shared/console/uart.h b/c/src/lib/libbsp/powerpc/shared/console/uart.h index 6fe17d47e8..98399bf500 100644 --- a/c/src/lib/libbsp/powerpc/shared/console/uart.h +++ b/c/src/lib/libbsp/powerpc/shared/console/uart.h @@ -12,6 +12,9 @@ #include +#include +#include + void BSP_uart_init(int uart, int baud, int hwFlow); void BSP_uart_set_baud(int aurt, int baud); void BSP_uart_intr_ctrl(int uart, int cmd); @@ -28,11 +31,32 @@ void BSP_uart_dbgisr_com1(void); void BSP_uart_dbgisr_com2(void); int BSP_uart_install_isr(int uart, rtems_irq_hdl handler); int BSP_uart_remove_isr(int uart, rtems_irq_hdl handler); +int BSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg); +int BSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg); extern unsigned BSP_poll_char_via_serial(void); extern void BSP_output_char_via_serial(int val); extern int BSPConsolePort; extern int BSPBaseBaud; + +/* Special IOCTLS to install a lowlevel 'BREAK' handler */ + +/* pass a BSP_UartBreakCb pointer to ioctl when retrieving + * or installing break callback + */ +typedef void (*BSP_UartBreakCbProc)(int uartMinor, + unsigned uartRBRLSRStatus, + void *termiosPrivatePtr, + void *private); + +typedef struct BSP_UartBreakCbRec_ { + BSP_UartBreakCbProc handler; /* NOTE NOTE this handler runs in INTERRUPT CONTEXT */ + void *private; /* closure pointer which is passed to the callback */ +} BSP_UartBreakCbRec, *BSP_UartBreakCb; + +#define BIOCGETBREAKCB _IOR('b',1,sizeof(BSP_UartBreakCbRec)) +#define BIOCSETBREAKCB _IOW('b',2,sizeof(BSP_UartBreakCbRec)) + /* * Command values for BSP_uart_intr_ctrl(), * values are strange in order to catch errors