diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-19 06:28:01 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-20 13:08:32 +0200 |
commit | d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc (patch) | |
tree | caa54b4229e86a68c84ab5961af34e087dce5302 /bsps/i386 | |
parent | bsps/powerpc: Move shared btimer support (diff) | |
download | rtems-d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc.tar.bz2 |
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/i386')
25 files changed, 8340 insertions, 0 deletions
diff --git a/bsps/i386/pc386/console/conscfg.c b/bsps/i386/pc386/console/conscfg.c new file mode 100644 index 0000000000..a4ae88626f --- /dev/null +++ b/bsps/i386/pc386/console/conscfg.c @@ -0,0 +1,198 @@ +/** + * @file + * + * This file contains the libchip configuration information + * to instantiate the libchip driver for the VGA console + * and serial ports on a PC. + */ + +/* + * COPYRIGHT (c) 1989-2014, 2016. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/bspimpl.h> +#include <libchip/serial.h> +#include <libchip/ns16550.h> +#if BSP_ENABLE_VGA +#include <rtems/vgacons.h> +#endif +#include <bsp/irq.h> +#include "../../shared/dev/serial/legacy-console.h" + +#if BSP_ENABLE_VGA +#define VGA_CONSOLE_FUNCTIONS &vgacons_fns +#endif + +#if BSP_ENABLE_COM1_COM4 + #if 0 + #define COM_CONSOLE_FUNCTIONS &ns16550_fns_polled + #else + #define COM_CONSOLE_FUNCTIONS &ns16550_fns + #endif + + /* + * Base IO for UART + */ + #define COM1_BASE_IO 0x3F8 + #define COM2_BASE_IO 0x3E8 + #define COM3_BASE_IO 0x2F8 + #define COM4_BASE_IO 0x2E8 + + #define CLOCK_RATE (115200 * 16) + + static uint8_t com_get_register(uint32_t addr, uint8_t i) + { + register uint8_t val; + + inport_byte( (addr + i), val ); + return val; + } + + static void com_set_register(uint32_t addr, uint8_t i, uint8_t val) + { + outport_byte( (addr + i), val ); + } +#endif + +/* + * Default to the PC VGA console if present and configured. + */ +console_tbl Console_Configuration_Ports[] = { +#if BSP_ENABLE_VGA + /* + * If present the VGA console must always be minor 0. + * See console_control. + */ + { + "/dev/vgacons", /* sDeviceName */ + VGA_CONSOLE, /* deviceType */ + VGA_CONSOLE_FUNCTIONS, /* pDeviceFns */ + vgacons_probe, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *) NULL, /* NULL */ /* pDeviceParams */ + 0x00000000, /* ulCtrlPort1 */ + 0x00000000, /* ulCtrlPort2 */ + 0x00000000, /* ulDataPort */ + NULL, /* getRegister */ + NULL, /* setRegister */ + NULL,/* unused */ /* getData */ + NULL,/* unused */ /* setData */ + 0x0, /* ulClock */ + 0x0 /* ulIntVector -- base for port */ + }, +#endif +}; + +unsigned long Console_Configuration_Count = + (sizeof(Console_Configuration_Ports)/sizeof(console_tbl)); + +static console_tbl Legacy_Ports[] = { +#if BSP_ENABLE_COM1_COM4 + { + "/dev/com1", /* sDeviceName */ + SERIAL_NS16550, /* deviceType */ + COM_CONSOLE_FUNCTIONS, /* pDeviceFns */ + NULL, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *) 9600, /* Baud Rate */ /* pDeviceParams */ + COM1_BASE_IO, /* ulCtrlPort1 */ + 0x00000000, /* ulCtrlPort2 */ + COM1_BASE_IO, /* ulDataPort */ + com_get_register, /* getRegister */ + com_set_register, /* setRegister */ + NULL,/* unused */ /* getData */ + NULL,/* unused */ /* setData */ + CLOCK_RATE, /* ulClock */ + BSP_UART_COM1_IRQ /* ulIntVector -- base for port */ + }, + { + "/dev/com2", /* sDeviceName */ + SERIAL_NS16550, /* deviceType */ + COM_CONSOLE_FUNCTIONS, /* pDeviceFns */ + NULL, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *) 9600, /* Baud Rate */ /* pDeviceParams */ + COM2_BASE_IO, /* ulCtrlPort1 */ + 0x00000000, /* ulCtrlPort2 */ + COM2_BASE_IO, /* ulDataPort */ + com_get_register, /* getRegister */ + com_set_register, /* setRegister */ + NULL,/* unused */ /* getData */ + NULL,/* unused */ /* setData */ + CLOCK_RATE, /* ulClock */ + BSP_UART_COM2_IRQ /* ulIntVector -- base for port */ + }, + { + "/dev/com3", /* sDeviceName */ + SERIAL_NS16550, /* deviceType */ + COM_CONSOLE_FUNCTIONS, /* pDeviceFns */ + NULL, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *) 9600, /* Baud Rate */ /* pDeviceParams */ + COM3_BASE_IO, /* ulCtrlPort1 */ + 0x00000000, /* ulCtrlPort2 */ + COM3_BASE_IO, /* ulDataPort */ + com_get_register, /* getRegister */ + com_set_register, /* setRegister */ + NULL,/* unused */ /* getData */ + NULL,/* unused */ /* setData */ + CLOCK_RATE, /* ulClock */ + BSP_UART_COM3_IRQ /* ulIntVector -- base for port */ + }, + { + "/dev/com4", /* sDeviceName */ + SERIAL_NS16550, /* deviceType */ + COM_CONSOLE_FUNCTIONS, /* pDeviceFns */ + NULL, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *) 9600, /* Baud Rate */ /* pDeviceParams */ + COM4_BASE_IO, /* ulCtrlPort1 */ + 0x00000000, /* ulCtrlPort2 */ + COM4_BASE_IO, /* ulDataPort */ + com_get_register, /* getRegister */ + com_set_register, /* setRegister */ + NULL,/* unused */ /* getData */ + NULL,/* unused */ /* setData */ + CLOCK_RATE, /* ulClock */ + BSP_UART_COM4_IRQ /* ulIntVector -- base for port */ + }, +#endif +}; + +#define Legacy_Port_Count \ + (sizeof(Legacy_Ports)/sizeof(console_tbl)) + +void legacy_uart_probe(void) +{ +#if BSP_ENABLE_COM1_COM4 + const char *opt; + /* + * Check the command line to see if com1-com4 are disabled. + */ + opt = bsp_cmdline_arg("--disable-com1-com4"); + if ( opt ) { + printk( "COM1-COM4: disabled\n" ); + } else { + if (Legacy_Port_Count) { + printk("Legacy UART Ports: COM1-COM4\n"); + console_register_devices( Legacy_Ports, Legacy_Port_Count ); + } + } +#endif +} diff --git a/bsps/i386/pc386/console/console_control.c b/bsps/i386/pc386/console/console_control.c new file mode 100644 index 0000000000..a04ae2bc3b --- /dev/null +++ b/bsps/i386/pc386/console/console_control.c @@ -0,0 +1,71 @@ +/* + * This file is an extension of the generic console driver + * shell used by all console drivers using libchip, it contains + * the console_control routine, This bsp needs its own version + * of this method to handle the keyboard and mouse as a single + * device. + */ + +/* + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <stdlib.h> +#include <assert.h> +#include <termios.h> +#include <rtems/libio.h> +#include <rtems/console.h> + +#include <bsp/irq.h> + +#include <rtems/termiostypes.h> +#include <libchip/serial.h> +#include <rtems/mouse_parser.h> +#if BSP_ENABLE_VGA +#include <rtems/keyboard.h> +#endif +#include "../../shared/dev/serial/legacy-console.h" + +/* + * console_control + * + * this routine uses the termios driver to process io + */ +rtems_device_driver console_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ +#if BSP_ENABLE_VGA + if (minor == 0) { + rtems_libio_ioctl_args_t *args = arg; + + switch (args->command) { + default: + if( vt_ioctl( args->command, (unsigned long)args->buffer ) != 0 ) + return rtems_termios_ioctl (arg); + break; + + case MW_UID_REGISTER_DEVICE: + printk( "SerialMouse: reg=%s\n", (const char*) args->buffer ); + register_kbd_msg_queue( args->buffer, 0 ); + break; + + case MW_UID_UNREGISTER_DEVICE: + unregister_kbd_msg_queue( 0 ); + break; + } + + args->ioctl_return = 0; + return RTEMS_SUCCESSFUL; + } +#endif + return rtems_termios_ioctl (arg); +} diff --git a/bsps/i386/pc386/console/console_select.c b/bsps/i386/pc386/console/console_select.c new file mode 100644 index 0000000000..1c064fb271 --- /dev/null +++ b/bsps/i386/pc386/console/console_select.c @@ -0,0 +1,250 @@ +/** + * @file + * + * @ingroup Console + * + * @brief pc386 console select + * + * This file contains a routine to select the console based upon a number + * of criteria. + */ + +/* + * COPYRIGHT (c) 2011-2012, 2016. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <limits.h> +#include <stdlib.h> +#include <termios.h> + +#include <bsp.h> +#include <libchip/serial.h> +#include <rtems/libio.h> +#include <rtems/console.h> +#include <rtems/termiostypes.h> +#include <bsp/bspimpl.h> + +#include "../../shared/dev/serial/legacy-console.h" +#ifdef RTEMS_RUNTIME_CONSOLE_SELECT + #include <crt.h> +#endif + +/* + * Method to return true if the device associated with the + * minor number probs available. + */ +static bool bsp_Is_Available( rtems_device_minor_number minor ) +{ + console_tbl *cptr = Console_Port_Tbl[minor]; + + /* + * First perform the configuration dependent probe, then the + * device dependent probe + */ + if ((!cptr->deviceProbe || cptr->deviceProbe(minor)) && + cptr->pDeviceFns->deviceProbe(minor)) { + return true; + } + return false; +} + +/* + * Method to return the first available device. + */ +static rtems_device_minor_number bsp_First_Available_Device( void ) +{ + rtems_device_minor_number minor; + + for (minor=0; minor < Console_Port_Count ; minor++) { + console_tbl *cptr = Console_Port_Tbl[minor]; + + /* + * First perform the configuration dependent probe, then the + * device dependent probe + */ + + if ((!cptr->deviceProbe || cptr->deviceProbe(minor)) && + cptr->pDeviceFns->deviceProbe(minor)) { + return minor; + } + } + + /* + * Error No devices were found. We will want to bail here. + */ + rtems_fatal_error_occurred(RTEMS_IO_ERROR); +} + +static bool parse_printk_or_console( + const char *param, + rtems_device_minor_number *minor_out +) +{ + static const char *opt; + const char *option; + const char *comma; + size_t length; + size_t index; + rtems_device_minor_number minor; + console_tbl *conscfg; + + /* + * Check the command line for the type of mode the console is. + */ + opt = bsp_cmdline_arg(param); + if ( !opt ) { + return false; + } + + /* + * Fine the length, there can be more command line visible. + */ + length = 0; + while ((opt[length] != ' ') && (opt[length] != '\0')) { + ++length; + if (length > NAME_MAX) { + printk("invalid option (%s): too long\n", param); + return false; + } + } + + /* + * Only match up to a comma or NULL + */ + index = 0; + while ((opt[index] != '=') && (index < length)) { + ++index; + } + + if (opt[index] != '=') { + printk("invalid option (%s): no equals\n", param); + return false; + } + + ++index; + option = &opt[index]; + + while ((opt[index] != ',') && (index < length)) { + ++index; + } + + if (opt[index] == ',') + comma = &opt[index]; + else + comma = NULL; + + length = &opt[index] - option; + + conscfg = console_find_console_entry( option, length, &minor ); + if ( conscfg == NULL ) { + return false; + } + + *minor_out = minor; + if (comma) { + option = comma + 1; + if (strncmp (option, "115200", sizeof ("115200") - 1) == 0) + conscfg->pDeviceParams = (void *)115200; + else if (strncmp (option, "57600", sizeof ("57600") - 1) == 0) + conscfg->pDeviceParams = (void *)57600; + else if (strncmp (option, "38400", sizeof ("38400") - 1) == 0) + conscfg->pDeviceParams = (void *)38400; + else if (strncmp (option, "19200", sizeof ("19200") - 1) == 0) + conscfg->pDeviceParams = (void *)19200; + else if (strncmp (option, "9600", sizeof ("9600") - 1) == 0) + conscfg->pDeviceParams = (void *)9600; + else if (strncmp (option, "4800", sizeof ("4800") - 1) == 0) + conscfg->pDeviceParams = (void *)4800; + } + + return true; +} + +/* + * Helper to retrieve device name + */ +static inline const char *get_name( + rtems_device_minor_number minor +) +{ + return Console_Port_Tbl[minor]->sDeviceName; +} + +/* + * Parse the arguments early so the printk and console ports are + * set appropriately. + */ +void pc386_parse_console_arguments(void) +{ + rtems_device_minor_number minor; + rtems_device_minor_number minor_console = 0; + rtems_device_minor_number minor_printk = 0; + + /* + * Assume that if only --console is specified, that printk() should + * follow that selection by default. + */ + if ( parse_printk_or_console( "--console=", &minor ) ) { + minor_console = minor; + minor_printk = minor; + } + + /* + * But if explicitly specified, attempt to honor it. + */ + if ( parse_printk_or_console( "--printk=", &minor ) ) { + minor_printk = minor; + } + + printk( "Console: %s printk: %s\n", + get_name(minor_console),get_name(minor_printk) ); + + /* + * Any output after this can cause problems until termios is initialised. + */ + Console_Port_Minor = minor_console; + BSPPrintkPort = minor_printk; +} + +/* + * This handles the selection of the console after the devices are + * initialized. + */ +void bsp_console_select(void) +{ + #ifdef RTEMS_RUNTIME_CONSOLE_SELECT + /* + * WARNING: This code is really needed any more and should be removed. + * references to COM1 and COM2 like they are wrong. + */ + if ( BSP_runtime_console_select ) + BSP_runtime_console_select(&BSPPrintkPort, &Console_Port_Minor); + + /* + * If no video card, fall back to serial port console + */ + if((Console_Port_Minor == BSP_CONSOLE_VGA) + && (*(unsigned char*) NB_MAX_ROW_ADDR == 0) + && (*(unsigned short*)NB_MAX_COL_ADDR == 0)) { + Console_Port_Minor = BSP_CONSOLE_COM2; + BSPPrintkPort = BSP_CONSOLE_COM1; + } + #endif + + /* + * If the device that was selected isn't available then + * let the user know and select the first available device. + */ + if ( !bsp_Is_Available( Console_Port_Minor ) ) { + printk( + "Error finding %s setting console to first available\n", + get_name(Console_Port_Minor) + ); + Console_Port_Minor = bsp_First_Available_Device(); + } +} diff --git a/bsps/i386/pc386/console/defkeymap.c b/bsps/i386/pc386/console/defkeymap.c new file mode 100644 index 0000000000..a6bf5103a1 --- /dev/null +++ b/bsps/i386/pc386/console/defkeymap.c @@ -0,0 +1,262 @@ +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include <sys/types.h> +#include <rtems/keyboard.h> +#include <rtems/kd.h> + +u_short plain_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, + 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c, + 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009, + 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, + 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, + 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, + 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, + 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c, + 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, + 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, + 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73, + 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76, + 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, + 0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911, + 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, + 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, + 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c, + 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809, + 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, + 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, + 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, + 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, + 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c, + 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907, + 0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901, + 0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', 'a', '\344'}, + {'O', 'A', '\305'}, {'o', 'a', '\345'}, + {'0', 'A', '\305'}, {'0', 'a', '\345'}, + {'A', 'A', '\305'}, {'a', 'a', '\345'}, + {'A', 'E', '\306'}, {'a', 'e', '\346'}, + {',', 'C', '\307'}, {',', 'c', '\347'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, +}; + +unsigned int accent_table_size = 68; diff --git a/bsps/i386/pc386/console/exar17d15x.c b/bsps/i386/pc386/console/exar17d15x.c new file mode 100644 index 0000000000..5cf615ac86 --- /dev/null +++ b/bsps/i386/pc386/console/exar17d15x.c @@ -0,0 +1,224 @@ +/** + * @file + * + * @brief Driver for Exar XR17D15x Multiport UARTs + * + * This driver supports 2, 4 or 8 port Exar parts which are NS16550 + * compatible. + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> + +#include <rtems/termiostypes.h> +#include <libchip/serial.h> +#include <libchip/ns16550.h> +#include <rtems/bspIo.h> +#include <rtems/pci.h> +#include <bsp/exar17d15x.h> +#include "../../shared/dev/serial/legacy-console.h" + +#define MAX_BOARDS 4 + +/* + * This is the rate for the clock internal to the parts. + */ +#define EXAR_CLOCK_RATE (921600*16) + +/* + * Supported PCI Ids + */ +#define PCI_VENDOR_ID_EXAR 0x13A8 +#define PCI_VENDOR_ID_EXAR_XR17D158 0x0158 +#define PCI_VENDOR_ID_EXAR_XR17D154 0x0154 +#define PCI_VENDOR_ID_EXAR_XR17D152 0x0152 + +/* + * Structure to manage each instance found. + */ +typedef struct { + uint16_t vendor; + uint16_t device; + uint8_t ports; +} exar_parts_t; + +static exar_parts_t Supported[] = { + { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D158, 8 }, + { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D154, 4 }, + { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D152, 2 }, + { 0, 0, 0 } +}; + +/* + * Information saved from PCI scan + */ +typedef struct { + bool found; + uint32_t base; + uint8_t irq; + uint8_t bus; + uint8_t slot; + uint8_t ports; +} exar17d15x_conf_t; + +/* + * Register Access Routines + */ +static uint8_t xr17d15x_get_register(uint32_t addr, uint8_t i) +{ + uint8_t val = 0; + volatile uint8_t *reg = (volatile uint8_t *)(addr + i); + + val = *reg; + // printk( "RD %p -> 0x%02x\n", reg, val ); + return val; +} + +static void xr17d15x_set_register(uint32_t addr, uint8_t i, uint8_t val) +{ + volatile uint8_t *reg = (volatile uint8_t *)(addr + i); + + // printk( "WR %p <- 0x%02x\n", reg, val ); + *reg = val; +} + +rtems_device_driver exar17d15x_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor_arg, + void *arg +) +{ + // int pbus, pdev, pfun; + exar17d15x_conf_t conf[MAX_BOARDS]; + int boards = 0; + int b = 0; + int p; + console_tbl *ports; + console_tbl *port_p; + int pbus; + int pdev; + int pfun; + int status; + int instance; + int i; + int total_ports = 0; + + for ( b=0 ; b<MAX_BOARDS ; b++ ) { + conf[b].found = false; + } + + /* + * Scan for Serial port boards + * + * NOTE: There appear to be Exar parts with 2 and 4 ports which would + * be easy to support. Just change the hard-coded 8 ports per + * board to variable and adjust. + * + * NOTE: There are likely other board vendors which could be supported + * by this. + */ + for ( instance=0 ; instance < MAX_BOARDS ; instance++ ) { + + for ( i=0 ; Supported[i].ports != 0 ; i++ ) { + status = pci_find_device( + Supported[i].vendor, + Supported[i].device, + instance, + &pbus, + &pdev, + &pfun + ); + if ( status == PCIB_ERR_SUCCESS ) { + boards++; + conf[instance].found = true; + conf[instance].ports = Supported[i].ports; + total_ports += conf[instance].ports; + break; + } + } + + if ( status != PCIB_ERR_SUCCESS ) + continue; + + pci_read_config_byte( + pbus, + pdev, + pfun, + PCI_INTERRUPT_LINE, + &conf[instance].irq + ); + pci_read_config_dword( + pbus, + pdev, + pfun, + PCI_BASE_ADDRESS_0, + &conf[instance].base + ); + printk( + "Found Exar 17D15x %d at 0x%08lx IRQ %d with %d ports\n", + instance, + conf[instance].base, + conf[instance].irq, + conf[instance].ports + ); + } + + /* + * Now allocate array of device structures and fill them in + */ + ports = calloc( total_ports, sizeof( console_tbl ) ); + port_p = ports; + for ( b=0 ; b<MAX_BOARDS ; b++ ) { + if ( conf[b].found == false ) + continue; + for ( p=0 ; p<conf[b].ports ; p++ ) { + char name[32]; + + sprintf( name, "/dev/exar17d15x_%d_%d", b, p ); + //printk("Found %s\n", name ); + port_p->sDeviceName = strdup( name ); + port_p->deviceType = SERIAL_NS16550; + #if 1 + port_p->pDeviceFns = &ns16550_fns_polled; + #else + port_p->pDeviceFns = &ns16550_fns; + #endif + + port_p->deviceProbe = NULL; + port_p->pDeviceFlow = NULL; + port_p->ulMargin = 16; + port_p->ulHysteresis = 8; + port_p->pDeviceParams = (void *) 9600; + port_p->ulCtrlPort1 = conf[b].base + (p * 0x0200); + port_p->ulCtrlPort2 = 0; /* NA */ + port_p->ulDataPort = 0; /* NA */ + port_p->getRegister = xr17d15x_get_register; + port_p->setRegister = xr17d15x_set_register; + port_p->getData = NULL; /* NA */ + port_p->setData = NULL; /* NA */ + port_p->ulClock = EXAR_CLOCK_RATE; + port_p->ulIntVector = conf[b].irq; + + port_p++; + } /* end ports */ + } /* end boards */ + + /* + * Register the devices + */ + if ( boards ) + console_register_devices( ports, total_ports ); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/i386/pc386/console/fb_cirrus.c b/bsps/i386/pc386/console/fb_cirrus.c new file mode 100644 index 0000000000..bb05b5a338 --- /dev/null +++ b/bsps/i386/pc386/console/fb_cirrus.c @@ -0,0 +1,766 @@ +/* + * FB driver for Cirrus GD5446 graphic hardware. + * Tested to be compatible with QEMU GD5446 emulation but not on real HW. + * + * Copyright (c) 2012 - Alexandru-Sever Horin (alex.sever.h@gmail.com). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * The code is based on next information sources: + * - CL-GD5446 Technical Reference Manual, 1996, Second Edition + * - RTEMS fb_vga.c - Rosimildo da Silva ( rdasilva@connecttel.com ) + * - Cirrus xf86 driver - used as VGA hardware setup sequence documentation + */ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <pthread.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/libio.h> +#include <rtems/pci.h> + +#include <rtems/fb.h> +#include <rtems/framebuffer.h> +#include <rtems/score/atomic.h> + +/* flag to limit driver to protect against multiple opens */ +static Atomic_Flag driver_mutex; + +/* screen information for the VGA driver + * standard structures + */ +static struct fb_var_screeninfo fb_var; +static struct fb_fix_screeninfo fb_fix; + +#define CIRRUS_VENDOR_ID 0x1013 +#define CIRRUS_GD5446_DEVICE_ID 0x00b8 + +typedef struct _DisplayModeRec { + struct _DisplayModeRec *prev; + struct _DisplayModeRec *next; + char *name; /* identifier for the mode */ + int type; + + /* These are the values that the user sees/provides */ + int Clock; /* pixel clock freq (kHz) */ + int HDisplay; /* horizontal timing */ + int HSyncStart; + int HSyncEnd; + int HTotal; + int HSkew; + int VDisplay; /* vertical timing */ + int VSyncStart; + int VSyncEnd; + int VTotal; + int VScan; + int Flags; + + /* These are the values the hardware uses */ + int ClockIndex; + int SynthClock; /* Actual clock freq to + * be programmed (kHz) */ + int CrtcHDisplay; + int CrtcHBlankStart; + int CrtcHSyncStart; + int CrtcHSyncEnd; + int CrtcHBlankEnd; + int CrtcHTotal; + int CrtcHSkew; + int CrtcVDisplay; + int CrtcVBlankStart; + int CrtcVSyncStart; + int CrtcVSyncEnd; + int CrtcVBlankEnd; + int CrtcVTotal; + int CrtcHAdjusted; + int CrtcVAdjusted; + int PrivSize; + int32_t *Private; + int PrivFlags; + + float HSync, VRefresh; +} DisplayModeRec, *DisplayModePtr; + +static DisplayModeRec available_modes[] = { + { + .Clock = 31500 , + .HDisplay = 640 , + .HSyncStart = 664 , + .HSyncEnd = 704 , + .HTotal = 832 , + .HSkew = 0 , + .VDisplay = 480 , /* vertical timing */ + .VSyncStart = 489 , + .VSyncEnd = 491 , + .VTotal = 520 , + .VScan = 0, + .Flags = 0 + }, + { + .Clock = 40000 , + .HDisplay = 800 , + .HSyncStart = 840 , + .HSyncEnd = 968 , + .HTotal = 1056 , + .HSkew = 0 , + .VDisplay = 600 , /* vertical timing */ + .VSyncStart = 601 , + .VSyncEnd = 605 , + .VTotal = 628 , + .VScan = 0, + .Flags = 0 + }, +}; +static DisplayModePtr active_mode; + +/* The display mode used for the board hardcoded in the following define + * Index in above structure + */ +#define CIRRUS_DISPLAY_MODE 0 + +/* The display bytes per pixel used for the board hardcoded in the following define + * Index in above structure + */ +#define CIRRUS_DEFAULT_BPP 24 + +/* cirrus board information */ +struct cirrus_board_str{ + int pci_bus; + int pci_device; + int pci_function; + void *reg_base; +}; + +static struct cirrus_board_str cirrus_board_info; + +/* + * get information from the board + */ +static int +cirrus_pci_read( struct cirrus_board_str *cirrus_board, uint32_t *mem_base, uint32_t *cirrus_register_base) +{ + int r; + + r = pci_read_config_dword( + cirrus_board->pci_bus, cirrus_board->pci_device, cirrus_board->pci_function, + PCI_BASE_ADDRESS_0, mem_base); + if( r != PCIB_ERR_SUCCESS) + return RTEMS_UNSATISFIED; + + r = pci_read_config_dword( + cirrus_board->pci_bus, cirrus_board->pci_device, cirrus_board->pci_function, + PCI_BASE_ADDRESS_1, cirrus_register_base); + if( r != PCIB_ERR_SUCCESS) + return RTEMS_UNSATISFIED; + + *mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + *cirrus_register_base &= PCI_BASE_ADDRESS_MEM_MASK; + + return RTEMS_SUCCESSFUL; +} + +static inline int +fb_cirrus_read_config_dword( + struct cirrus_board_str *fbst, + unsigned char where, + uint32_t *pval) +{ + return pci_read_config_dword( + fbst->pci_bus, fbst->pci_device, fbst->pci_function, + where, pval); +} + +static inline int +fb_cirrus_write_config_dword( + struct cirrus_board_str *fbst, + unsigned char where, + uint32_t val) +{ + return pci_write_config_dword( + fbst->pci_bus, fbst->pci_device, fbst->pci_function, + where, val); +} + +static inline void +fb_cirrus_write_reg8 ( + const struct cirrus_board_str *fbst, + unsigned int reg, + unsigned int val) +{ + *(volatile uint8_t*)((char *)fbst->reg_base + reg) = val; +} + +static inline unsigned int +fb_cirrus_read_reg8 ( + const struct cirrus_board_str *fbst, + unsigned int reg) +{ + return *(volatile uint8_t*)((char *)fbst->reg_base + reg); +} + +#define SEQ_INDEX 0x04 +#define SEQ_DATA 0x05 + +static inline void +fb_cirrus_write_seq_reg ( + const struct cirrus_board_str *fbst, + unsigned int reg, + unsigned int val) +{ + fb_cirrus_write_reg8(fbst, SEQ_INDEX, reg); + fb_cirrus_write_reg8(fbst, SEQ_DATA, val); +} + +static inline unsigned int +fb_cirrus_read_seq_reg ( + const struct cirrus_board_str *fbst, + unsigned int reg) +{ + fb_cirrus_write_reg8(fbst, SEQ_INDEX, reg); + return fb_cirrus_read_reg8(fbst, SEQ_DATA); +} + +#define CRT_INDEX 0x14 +#define CRT_DATA 0x15 + +static inline void +fb_cirrus_write_crt_reg ( + const struct cirrus_board_str *fbst, + unsigned int reg, + unsigned int val) +{ + fb_cirrus_write_reg8(fbst, CRT_INDEX, reg); + fb_cirrus_write_reg8(fbst, CRT_DATA, val); +} + +static inline unsigned int +fb_cirrus_read_crt_reg ( + const struct cirrus_board_str *fbst, + unsigned int reg) +{ + fb_cirrus_write_reg8(fbst, CRT_INDEX, reg); + return fb_cirrus_read_reg8(fbst, CRT_DATA); +} + +#define GDC_INDEX 0x0E +#define GDC_DATA 0x0F + +static inline void +fb_cirrus_write_gdc_reg ( + const struct cirrus_board_str *fbst, + unsigned int reg, + unsigned int val) +{ + fb_cirrus_write_reg8(fbst, GDC_INDEX, reg); + fb_cirrus_write_reg8(fbst, GDC_DATA, val); +} + +static inline unsigned int +fb_cirrus_read_gdc_reg ( + const struct cirrus_board_str *fbst, + unsigned int reg) +{ + fb_cirrus_write_reg8(fbst, GDC_INDEX, reg); + return fb_cirrus_read_reg8(fbst, GDC_DATA); +} + +#define VGA_DAC_MASK 0x06 + +static inline void +fb_cirrus_write_hdr_reg ( + const struct cirrus_board_str *fbst, + unsigned int val) +{ + volatile unsigned int dummy RTEMS_UNUSED; + dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK); + dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK); + dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK); + dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK); + fb_cirrus_write_reg8(fbst, VGA_DAC_MASK, val); +} + +/* Functionality to support multiple VGA frame buffers can be added easily, + * but is not supported at this moment because there is no need for two or + * more "classic" VGA adapters. Multiple frame buffer drivers may be + * implemented and If we had implement it they would be named as "/dev/fb0", + * "/dev/fb1", "/dev/fb2" and so on. + */ + +/* + * fb_cirrus device driver INITIALIZE entry point. + */ +rtems_device_driver +frame_buffer_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + int res; + + printk( "FB_CIRRUS -- driver initializing..\n" ); + + res = pci_find_device( + CIRRUS_VENDOR_ID, + CIRRUS_GD5446_DEVICE_ID, + minor, + &cirrus_board_info.pci_bus, + &cirrus_board_info.pci_device, + &cirrus_board_info.pci_function + ); + + if ( res != PCIB_ERR_SUCCESS ) { + printk( "FB_CIRRUS initialize -- device not found\n" ); + + return RTEMS_UNSATISFIED; + } + else{ + printk( "FB_CIRRUS -- driver initializing..\n" ); + /* + * Register the device + */ + status = rtems_io_register_name (FRAMEBUFFER_DEVICE_0_NAME, major, 0); + if (status != RTEMS_SUCCESSFUL) { + printk("Error registering " FRAMEBUFFER_DEVICE_0_NAME + " FB_CIRRUS framebuffer device!\n"); + rtems_fatal_error_occurred( status ); + } + + _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE); + + return RTEMS_SUCCESSFUL; + } +} + +/* + * This function is used to initialize the Start Address - the first + * displayed location in the video memory. + * Usually mandatory + */ +static void +cirrus_adjust_frame( struct cirrus_board_str *board, int x, int y) +{ + uint32_t Base; + uint8_t tmp; + + Base = ((y * fb_var.xres + x) >> 3); + if (fb_var.bits_per_pixel != 1) + Base *= (fb_var.bits_per_pixel >> 2); + + printk("FB_CIRRUS: cirrus_adjust_frame %d %d >>> %d %x\n", x, y, Base, Base); + + if ((Base & ~0x000FFFFF) != 0) { + printk("FB_CIRRUS: Internal error: cirrus_adjust_frame: cannot handle overflow\n"); + return; + } + + fb_cirrus_write_crt_reg( board, 0x0C, (Base >> 8) & 0xff); + fb_cirrus_write_crt_reg( board, 0x0D, Base & 0xff); + + tmp = fb_cirrus_read_crt_reg( board, 0x1B); + tmp &= 0xF2; + tmp |= (Base >> 16) & 0x01; + tmp |= (Base >> 15) & 0x0C; + fb_cirrus_write_crt_reg( board, 0x1B, tmp); + + tmp = fb_cirrus_read_crt_reg( board, 0x1D); + tmp &= 0x7F; + tmp |= (Base >> 12) & 0x80; + fb_cirrus_write_crt_reg( board, 0x1D, tmp); +} + +static int +cirrus_set_mode(DisplayModePtr mode) +{ + int depthcode = fb_var.bits_per_pixel;; + int width; + int HDiv2 = 0, VDiv2 = 0; + const struct cirrus_board_str *cirrus_board_ptr = &cirrus_board_info; + int temp; + int hdr = -1; + + printk("FB_CIRRUS: mode %d bpp, %d Hz %d %d %d %d %d %d %d %d\n", + fb_var.bits_per_pixel, + mode->Clock, + mode->HDisplay, + mode->HSyncStart, + mode->HSyncEnd, + mode->HTotal, + mode->VDisplay, + mode->VSyncStart, + mode->VSyncEnd, + mode->VTotal); + + if ( mode->Clock > 85500 ) { + /* The actual DAC register value is set later. */ + /* The CRTC is clocked at VCLK / 2, so we must half the */ + /* horizontal timings. */ + if (!mode->CrtcHAdjusted) { + mode->HDisplay >>= 1; + mode->HSyncStart >>= 1; + mode->HTotal >>= 1; + mode->HSyncEnd >>= 1; + mode->SynthClock >>= 1; + mode->CrtcHAdjusted = TRUE; + } + depthcode += 64; + HDiv2 = 1; + } + if (mode->VTotal >= 1024 ) { + /* For non-interlaced vertical timing >= 1024, the vertical timings */ + /* are divided by 2 and VGA CRTC 0x17 bit 2 is set. */ + if (!mode->CrtcVAdjusted) { + mode->VDisplay >>= 1; + mode->VSyncStart >>= 1; + mode->VSyncEnd >>= 1; + mode->VTotal >>= 1; + mode->CrtcVAdjusted = TRUE; + } + VDiv2 = 1; + } + + /**************************************************** + * Sequential registers + */ + fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x00, 0x00); + fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x01, 0x01); + fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x02, 0x0F); + fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x03, 0x00); + fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x04, 0x0E); + + /**************************************************** + * CRTC Controller Registers + */ + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x00, (mode->HTotal >> 3) - 5 ); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x01, (mode->HDisplay >> 3) - 1); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x02, (mode->HSyncStart >> 3) - 1); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x03, ((mode->HSyncEnd >> 3) & 0x1F) | 0x80); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x04, (mode->HSyncStart >> 3)); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x05, + (((mode->HSyncEnd >> 3) & 0x20 ) << 2 ) + | (((mode->HSyncEnd >> 3)) & 0x1F)); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x06, (mode->VTotal - 2) & 0xFF); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x07, + (((mode->VTotal -2) & 0x100) >> 8 ) + | (((mode->VDisplay -1) & 0x100) >> 7 ) + | ((mode->VSyncStart & 0x100) >> 6 ) + | (((mode->VSyncStart) & 0x100) >> 5 ) + | 0x10 + | (((mode->VTotal -2) & 0x200) >> 4 ) + | (((mode->VDisplay -1) & 0x200) >> 3 ) + | ((mode->VSyncStart & 0x200) >> 2 )); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x08, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x09, ((mode->VSyncStart & 0x200) >>4) | 0x40); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0A, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0B, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0C, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0D, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0E, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0F, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x10, mode->VSyncStart & 0xFF); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x11, (mode->VSyncEnd & 0x0F) | 0x20); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x12, (mode->VDisplay -1) & 0xFF); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x13, 0x00); /* no interlace */ + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x14, 0x00); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x15, mode->VSyncStart & 0xFF); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x16, (mode->VSyncStart +1) & 0xFF); + + temp = 0xAF; + if(VDiv2) + temp |= 0x04; + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x17, temp); + + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x18, 0xFF); + + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x1A , + (((mode->HTotal >> 3) & 0xC0 ) >> 2) + | (((mode->VTotal - 2) & 0x300 ) >> 2)); + + width = fb_fix.line_length >> 3; + if (fb_var.bits_per_pixel == 1) + width <<= 2; + if(width >= 0xFF) + printk("FB_CIRRUS: Warning line size over the limit ... reduce bpp or width resolution"); + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x13, width); + /* Offset extension (see CR13) */ + temp = fb_cirrus_read_crt_reg( cirrus_board_ptr, 0x1B); + temp &= 0xAF; + temp |= (width >> (3+4)) & 0x10; + temp |= (width >> (3+3)) & 0x40; + temp |= 0x22; + fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x1B, temp); + + /**************************************************** + * Sequential register + * Enable linear mode and high-res packed pixel mode + */ + temp = fb_cirrus_read_seq_reg( cirrus_board_ptr, 0x07); + temp &= 0xe0; + switch (depthcode) { + case 1: + case 4: + temp |= 0x10; + break; + case 8: + temp |= 0x11; + break; + case 64+8: + temp |= 0x17; + break; + case 15: + temp |= 0x17; + hdr = 0xC0; /* 5:5:5 Sierra */ + break; + case 16: + temp |= 0x17; + hdr = 0xC1; /* 5:6:5 XGA mode */ + break; + case 24: + temp |= 0x15; + hdr = 0xC5; /* 8:8:8 16M colors */ + break; + case 32: + temp |= 0x19; + hdr = 0xC5; /* 8:8:8 16M colors */ + break; + default: + printk("FB_CIRRUS: Cannot Initialize display to requested mode\n"); + printk("FB_CIRRUS: returning RTEMS_UNSATISFIED on depthcode %d\n", depthcode); + return RTEMS_UNSATISFIED; + } + fb_cirrus_write_seq_reg( cirrus_board_ptr, 0x07, temp); + /* this just set packed pixel mode with according bpp */ + + /**************************************************** + * HDR Register + */ + if(hdr > 0) + fb_cirrus_write_hdr_reg( cirrus_board_ptr, hdr); + + /**************************************************** + * Graphic Data Controller Registers + */ + temp = fb_cirrus_read_gdc_reg( cirrus_board_ptr, 0x12); + if (HDiv2) + temp |= 0x20; + else + temp &= ~0x20; + fb_cirrus_write_gdc_reg( cirrus_board_ptr, 0x12, temp); + + /* Enable high-color modes */ + fb_cirrus_write_gdc_reg(cirrus_board_ptr, 0x05, 0x40); + + /* VGA graphics mode */ + fb_cirrus_write_gdc_reg(cirrus_board_ptr, 0x06, 0x01); + + return TRUE; +} + +static void +cirrus_prepare_mode( void ) +{ + + active_mode = &available_modes[CIRRUS_DISPLAY_MODE]; + + fb_var.bits_per_pixel = CIRRUS_DEFAULT_BPP; + + fb_var.xres = active_mode->HDisplay; + fb_var.yres = active_mode->VDisplay; + + fb_fix.line_length = (fb_var.xres * fb_var.bits_per_pixel + 7) / 8; + + fb_fix.type = FB_TYPE_PACKED_PIXELS; + fb_fix.visual = FB_VISUAL_TRUECOLOR; + +} + +/* + * fb_cirrus device driver OPEN entry point + */ +rtems_device_driver +frame_buffer_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + int r; + uint32_t smem_start, regs_start; + + if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0 ) { + printk( "FB_CIRRUS could not lock driver_mutex\n" ); + + return RTEMS_UNSATISFIED; + } + + r = cirrus_pci_read(&cirrus_board_info, &smem_start, ®s_start); + if ( r == RTEMS_UNSATISFIED ) + return RTEMS_UNSATISFIED; + + fb_fix.smem_start = (volatile char *)smem_start; + fb_fix.smem_len = 0x1000000; + cirrus_board_info.reg_base = (void *)regs_start; + + cirrus_prepare_mode(); + + cirrus_set_mode( active_mode ); + + cirrus_adjust_frame( &cirrus_board_info, 0, 0); + + if (1) { + uint32_t pixmask; + int x, y; + + if(fb_var.bits_per_pixel == 32) + pixmask = 0xffffff; + else + pixmask = (1 << fb_var.bits_per_pixel) - 1; + + printk("FB_CIRRUS: mode set, test patter output\n"); + + for(y = 0; y < fb_var.yres; y++) { + for(x = 0; x < fb_var.xres; x++) { + uint32_t color; + char *addr = (char *)fb_fix.smem_start; + addr += y * fb_fix.line_length; + addr += x * fb_var.bits_per_pixel / 8; + color = x & 1 ? 0 : y & 1 ? pixmask & 0x000ff00f : pixmask; + if(y == fb_var.yres - 1) { + if((x > 0) && (x < fb_var.xres-1)) + color = pixmask & 0x00555555; + } + switch (fb_var.bits_per_pixel) { + case 8: *(volatile uint8_t*) addr = color; + break; + case 16: *(volatile uint16_t*) addr = color; + break; + case 24: *(volatile uint32_t*) addr = + (*(volatile uint32_t*) addr & 0xff000000) | color; + break; + case 32: *(volatile uint32_t*) addr = color; + break; + } + } + } + } + + return RTEMS_SUCCESSFUL; + +} + +/* + * fb_cirrus device driver CLOSE entry point + */ +rtems_device_driver +frame_buffer_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE); + + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() */ + + /* VGA text mode */ + fb_cirrus_write_gdc_reg(&cirrus_board_info, 0x06, 0x00); + + printk( "FB_CIRRUS: close called.\n" ); + return RTEMS_SUCCESSFUL; +} + +/* + * fb_cirrus device driver READ entry point. + */ +rtems_device_driver +frame_buffer_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy(rw_args->buffer, (const void *) (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; +} + +/* + * frame_buffer device driver WRITE entry point. + */ +rtems_device_driver +frame_buffer_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy( (void *) (fb_fix.smem_start + rw_args->offset), rw_args->buffer, rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; +} + +static int +get_fix_screen_info( struct fb_fix_screeninfo *info ) +{ + *info = fb_fix; + return 0; +} + +static int +get_var_screen_info( struct fb_var_screeninfo *info ) +{ + *info = fb_var; + return 0; +} + +/* + * IOCTL entry point -- This method is called to carry + * all services of this interface. + */ +rtems_device_driver +frame_buffer_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + printk( "FB_CIRRUS ioctl called, cmd=%x\n", args->command ); + + switch( args->command ) { + case FBIOGET_FSCREENINFO: + args->ioctl_return = get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer ); + break; + case FBIOGET_VSCREENINFO: + args->ioctl_return = get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer ); + break; + case FBIOPUT_VSCREENINFO: + /* not implemented yet */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOGETCMAP: + /* no palette - truecolor mode */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOPUTCMAP: + /* no palette - truecolor mode */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + default: + args->ioctl_return = 0; + break; + } + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/i386/pc386/console/fb_vesa_rm.c b/bsps/i386/pc386/console/fb_vesa_rm.c new file mode 100644 index 0000000000..1c42956fce --- /dev/null +++ b/bsps/i386/pc386/console/fb_vesa_rm.c @@ -0,0 +1,1004 @@ +/** + * @file fb_vesa_rm.c + * + * @ingroup i386_pc386 + * + * @brief FB driver for graphic hardware compatible with VESA Bios Extension + * Real mode interface utilized + * Tested on real HW. + * + * Public sources related: + * - VESA BIOS EXTENSION (VBE) Core Function Standard, Ver: 3.0, Sep 16, 1998 + * - VESA Enhanced Extended Display Identification Data (E-EDID) Standard + * Release A, Revision 2, September 25, 2006 + * + * Hardware is completely initialized upon boot of the system. + * Therefore there is no way to change graphics mode later. + * + * Interrupt 0x10 is used for entering graphics BIOS. + * + * Driver reads parameter from multiboot command line to setup video: + * "--video=<resX>x<resY>[-<bpp>]" + * "--video=auto" - try EDID to find mode that fits the display attached best + * "--video=none" / "--video=off" - do not initialize the driver + * If cmdline parameter is not specified the rtems_fb_default_mode + * variable content is tested (see doc below). + * Command line option has higher priority. rtems_fb_default_mode is probed + * only if cmdline "--video=" is not specified at all. + * + * If neither of the above options is specified the driver is not initialized. + */ + +/* + * Copyright (c) 2014 - CTU in Prague + * Jan Doležal ( dolezj21@fel.cvut.cz ) + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * The code for rtems_buffer_* functions was greatly + * inspired or coppied from: + * - RTEMS fb_cirrus.c - Alexandru-Sever Horin (alex.sever.h@gmail.com) + */ + +#include <inttypes.h> + +#include <bsp.h> + +#include <bsp/fb_default_mode.h> +#include <bsp/fb_vesa.h> +#include <bsp/realmode_int.h> + +#include <pthread.h> + +#include <rtems/libio.h> + +#include <rtems/fb.h> +#include <rtems/framebuffer.h> + +#include <rtems/score/atomic.h> + +#include <stdlib.h> + +#define FB_VESA_NAME "FB_VESA_RM" + +/** + * @brief Allows to enable initialization of VESA real mode driver from + * an application by setting the value of this variable to non null value in + * user's module. The value of this variable will be then updated + * when linked with application's object. + * + * Further the value should point to string in the following format: + * "<resX>x<resY>[-<bpp>]" - e.g. "1024x768-32" + * "auto" - try EDID to find mode that fits the display attached best + * "none" / "off" - do not initialize the driver + * the given parameters are used if applicable. + * + * Command line argument "--video=" has priority over this string. + */ +const char * const rtems_fb_default_mode; + +/** + * @brief Initializes VBE framebuffer during bootup. + * + * utilizes switches to real mode interrupts and therefore must be + * called during bootup before tick is set up and real-time + * interrupt vectors utilized + */ +void vesa_realmode_bootup_init(void); + +/* flag to limit driver to protect against multiple opens */ +static Atomic_Flag driver_mutex; + +/* screen information for the VGA driver + * standard structures - from RTEMS fb interface + */ +static struct fb_var_screeninfo fb_var; +static struct fb_fix_screeninfo fb_fix; + +static int32_t vbe_used_mode; + +uint32_t VBE_controller_information( VBE_vbe_info_block *info_block, + uint16_t queried_VBE_Version) +{ + uint16_t size; + VBE_vbe_info_block *VBE_buffer = + (VBE_vbe_info_block *)i386_get_default_rm_buffer(&size); + i386_realmode_interrupt_registers parret; + parret.reg_eax = VBE_RetVBEConInf; + uint16_t seg, off; + i386_Physical_to_real(VBE_buffer, &seg, &off); + parret.reg_edi = (uint32_t)off; + parret.reg_es = seg; + /* indicate to graphic's bios that VBE2.0 extended information is desired */ + if (queried_VBE_Version >= 0x200) + { + memcpy( + &VBE_buffer->VbeSignature, + VBE20plus_SIGNATURE, + sizeof(VBE_buffer->VbeSignature) + ); + } + if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0) + return -1; + if ((parret.reg_eax & 0xFFFF) == + (VBE_callSuccessful<<8 | VBE_functionSupported)) + { + *info_block = *VBE_buffer; + } + return (parret.reg_eax & 0xFFFF); +} + +uint32_t VBE_mode_information( VBE_mode_info_block *info_block, + uint16_t mode_number) +{ + uint16_t size; + VBE_mode_info_block *VBE_buffer = + (VBE_mode_info_block *)i386_get_default_rm_buffer(&size); + i386_realmode_interrupt_registers parret; + parret.reg_eax = VBE_RetVBEModInf; + parret.reg_ecx = mode_number; + uint16_t seg, off; + i386_Physical_to_real(VBE_buffer, &seg, &off); + parret.reg_edi = (uint32_t)off; + parret.reg_es = seg; + if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0) + return -1; + if ((parret.reg_eax & 0xFFFF) == + (VBE_callSuccessful<<8 | VBE_functionSupported)) + { + *info_block = *VBE_buffer; + } + return (parret.reg_eax & 0xFFFF); +} + +uint32_t VBE_set_mode( uint16_t mode_number, + VBE_CRTC_info_block *info_block) +{ + uint16_t size; + VBE_CRTC_info_block *VBE_buffer = + (VBE_CRTC_info_block *)i386_get_default_rm_buffer(&size); + i386_realmode_interrupt_registers parret; + /* copy CRTC */ + *VBE_buffer = *info_block; + parret.reg_eax = VBE_SetVBEMod; + parret.reg_ebx = mode_number; + uint16_t seg, off; + i386_Physical_to_real(VBE_buffer, &seg, &off); + parret.reg_edi = (uint32_t)off; + parret.reg_es = seg; + if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0) + return -1; + return (parret.reg_eax & 0xFFFF); +} + +uint32_t VBE_current_mode(uint16_t *mode_number) +{ + i386_realmode_interrupt_registers parret; + parret.reg_eax = VBE_RetCurVBEMod; + if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0) + return -1; + *mode_number = (uint16_t)parret.reg_ebx; + return (parret.reg_eax & 0xFFFF); +} + +uint32_t VBE_report_DDC_capabilities(uint16_t controller_unit_number, + uint8_t *seconds_to_transfer_EDID_block, + uint8_t *DDC_level_supported) +{ + i386_realmode_interrupt_registers parret; + parret.reg_eax = VBE_DisDatCha; + parret.reg_ebx = VBEDDC_Capabilities; + parret.reg_ecx = controller_unit_number; + parret.reg_edi = 0; + parret.reg_es = 0; + if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0) + return -1; + *seconds_to_transfer_EDID_block = (uint8_t)parret.reg_ebx >> 8; + *DDC_level_supported = (uint8_t)parret.reg_ebx; + return (parret.reg_eax & 0xFFFF); +} + +uint32_t VBE_read_EDID(uint16_t controller_unit_number, + uint16_t EDID_block_number, + EDID_edid1 *buffer) +{ + uint16_t size; + EDID_edid1 *VBE_buffer = (EDID_edid1*)i386_get_default_rm_buffer(&size); + i386_realmode_interrupt_registers parret; + parret.reg_eax = VBE_DisDatCha; + parret.reg_ebx = VBEDDC_ReadEDID; + parret.reg_ecx = controller_unit_number; + parret.reg_edx = EDID_block_number; + uint16_t seg, off; + i386_Physical_to_real(VBE_buffer, &seg, &off); + parret.reg_edi = (uint32_t)off; + parret.reg_es = seg; + if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0) + return -1; + if ((parret.reg_eax & 0xFFFF) == + (VBE_callSuccessful<<8 | VBE_functionSupported)) + { + *buffer = *VBE_buffer; + } + return (parret.reg_eax & 0xFFFF); +} + +/** + * @brief Basic graphic's mode parameters + */ +typedef struct { + /** number of the graphic's mode */ + uint16_t mode_number; + /** number of pixels in one line */ + uint16_t resX; + /** number of lines */ + uint16_t resY; + /** bits per pixel */ + uint8_t bpp; +} Mode_params; + +typedef enum { + NO_SUITABLE_MODE = -1, + BAD_FORMAT = -2, + AUTO_SELECT = -3, + DONT_INIT = -4, + NO_MODE_REQ = -5, +} mode_err_ret_val; + +/** + * @brief Find mode by resolution in the given list of modes + * + * finds mode in \p mode_list of \p list_length length according to resolution + * given in \p searched_resolution . If bpp is given in that struct as well + * mode with such color depth and resolution is searched for. Otherwise bpp + * has to be zero. Mode number found is returned and also filled into + * \p searched_resolution . bpp is also filled into \p searchedResolution if it + * was 0 before call. + * + * @param[in] mode_list list of modes to be searched + * @param[in] list_length number of modes in the list + * @param[in,out] searched_resolution element filled with searched resolution + * or/and bpp; mode_number is filled in if appropriate mode found + * @retval mode number satisfying given parameters + * @retval -1 no suitable mode found + */ +static int32_t find_mode_by_resolution(Mode_params *mode_list, + uint8_t list_length, + Mode_params *searched_resolution) +{ + uint8_t i = 0; + while (i < list_length) + { + if (searched_resolution->resX == mode_list[i].resX && + searched_resolution->resY == mode_list[i].resY) + { + if (searched_resolution->bpp==0 || + searched_resolution->bpp==mode_list[i].bpp) + { + searched_resolution->bpp = mode_list[i].bpp; + searched_resolution->mode_number = mode_list[i].mode_number; + return mode_list[i].mode_number; + } + } + i++; + } + return NO_SUITABLE_MODE; +} + +/** + * @brief Find mode given in string format. + * + * expected format + * <resX>x<resY>[-<bpp>] + * numbers <resX>, <resY> and <bpp> are decadic + * + * @param[in] mode_list list of modes to be searched + * @param[in] list_length number of modes in the list + * @param[in] video_string string to be parsed + * @retval video mode number to be set + * @retval -1 no suitable mode found + * @retval -2 bad format of the video_string + * @retval -3 automatic mode selection requested + * @retval -4 request to not initialize graphics + * @retval -5 no mode requested/empty video string + */ +static int32_t find_mode_from_string(Mode_params *mode_list, + uint8_t list_length, + const char *video_string) +{ + const char* opt; + Mode_params cmdline_mode; + char* endptr; + cmdline_mode.bpp = 16; /* default bpp */ + opt = video_string; + if (opt) + { + if (strncmp(opt, "auto", 4) == 0) + return AUTO_SELECT; + if (strncmp(opt, "none", 4) == 0 || + strncmp(opt, "off", 3) == 0) + { + return DONT_INIT; + } + cmdline_mode.resX = strtol(opt, &endptr, 10); + if (*endptr != 'x') + { + return BAD_FORMAT; + } + opt = endptr+1; + cmdline_mode.resY = strtol(opt, &endptr, 10); + switch (*endptr) + { + case '-': + opt = endptr+1; + if (strlen(opt) <= 2) + cmdline_mode.bpp = strtol(opt, &endptr, 10); + else + { + cmdline_mode.bpp = strtol(opt, &endptr, 10); + if (*endptr != ' ') + { + return BAD_FORMAT; + } + } + case ' ': + case 0: + break; + default: + return BAD_FORMAT; + } + + return find_mode_by_resolution(mode_list, list_length, &cmdline_mode); + } + return NO_MODE_REQ; +} + +/** + * @brief Find mode given within command line. + * + * Parse command line option "--video=" if available. + * expected format + * --video=<resX>x<resY>[-<bpp>] + * numbers <resX>, <resY> and <bpp> are decadic + * + * @param[in] mode_list list of modes to be searched + * @param[in] list_length number of modes in the list + * @retval video mode number to be set + * @retval -1 no suitable mode found + * @retval -2 bad format of the video_string + * @retval -3 automatic mode selection requested + * @retval -4 request to not initialize graphics + * @retval -5 no mode requested/empty video string + */ +static int32_t find_mode_using_cmdline(Mode_params *mode_list, + uint8_t list_length) +{ + const char* opt; + opt = bsp_cmdline_arg("--video="); + if (opt) + { + opt += sizeof("--video=")-1; + return find_mode_from_string(mode_list, list_length, opt); + } + return NO_MODE_REQ; +} + +/** + * @brief Find mode number best fitting to monitor attached + * + * @param[in] mode_list list of modes to be searched + * @param[in] list_length number of modes in the list + * @retval video mode number to be set + * @retval -1 on parsing error or when no suitable mode found + */ +static int32_t find_mode_using_EDID( Mode_params *mode_list, + uint8_t list_length) +{ + EDID_edid1 edid; + uint8_t checksum, iterator; + uint8_t index, j; + Mode_params EDIDmode; + checksum = 0; + iterator = 0; + EDIDmode.bpp = 0; + if (VBE_read_EDID(0, 0, &edid) != + (VBE_callSuccessful<<8 | VBE_functionSupported)) + { + printk(FB_VESA_NAME " Function 15h (read EDID) not supported.\n"); + return -1; + } +/* version of EDID structure */ + if (edid.Version == 1) + { /* EDID version 1 */ + while (iterator < sizeof(EDID_edid1)) + { + checksum += *((uint8_t *)&edid+iterator); + iterator++; + } + if (checksum) + /* not implemented: try to read EDID again */ + printk(FB_VESA_NAME " EDID v1 checksum failed\n"); + + /* try to find Detailed Timing Descriptor (defined in BASE EDID) + in controller mode list; first should be preffered mode */ + index = 0; + while (index < 4) + { + /* skip if it is monitor descriptor */ + if (edid.dtd_md[index].md.Flag0[0] == 0 && + edid.dtd_md[index].md.Flag0[1] == 0 && + edid.dtd_md[index].md.Flag1 == 0) + { + index++; + continue; + } + EDIDmode.resX = DTD_horizontal_active(&edid.dtd_md[0].dtd); + EDIDmode.resY = DTD_vertical_active(&edid.dtd_md[0].dtd); + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + + index++; + } + /* try to find Detailed Timing Descriptor (defined in optional EXTENSION + Blocks) in controller mode list */ + if (edid.ExtensionFlag > 0) + { + /* not implemented */ + } + /* try to find CVT (defined in BASE EDID) in controller mode list */ + index = 1; + while (index < 4) + { + if (edid.dtd_md[index].md.DataTypeTag == + EDID_DTT_CVT3ByteTimingCodes && + edid.dtd_md[index].md.Flag0[0] == 0 && + edid.dtd_md[index].md.Flag0[1] == 0 && + edid.dtd_md[index].md.Flag1 == 0 && + edid.dtd_md[index].md.Flag2 == 0) + { + EDID_CVT_timing_codes_3B *cvt = (EDID_CVT_timing_codes_3B *) + &edid.dtd_md[index].md.DescriptorData[0]; + j = 0; + while (j < 4) + { + EDIDmode.resY = edid1_CVT_addressable_lines_high( + &cvt->cvt[j] + ); + switch (edid1_CVT_aspect_ratio(&cvt->cvt[j])) + { + case EDID_CVT_AspectRatio_4_3: + EDIDmode.resX = (EDIDmode.resY*4)/3; + break; + case EDID_CVT_AspectRatio_16_9: + EDIDmode.resX = (EDIDmode.resY*16)/9; + break; + case EDID_CVT_AspectRatio_16_10: + EDIDmode.resX = (EDIDmode.resY*16)/10; + break; + case EDID_CVT_AspectRatio_15_9: + EDIDmode.resX = (EDIDmode.resY*15)/9; + break; + } + EDIDmode.resX = (EDIDmode.resX/8)*8; + if (find_mode_by_resolution( + mode_list, list_length, &EDIDmode) != -1) + return EDIDmode.mode_number; + + j++; + } + } + index++; + } + /* try to find CVT (defined in optional EXTENSION Blocks) + in controller mode list */ + /* not implemented */ + /* try to find Standard Timings (listed in BASE EDID) + in controller mode list */ + index = 0; + while (index < 8) + { + /* check if descriptor is unused */ + if (edid1_STI_is_unused(&edid.STI[index])) + { + index++; + continue; + } + EDIDmode.resX = (edid.STI[index].HorizontalActivePixels+31)*8; + switch (edid.STI[index].ImageAspectRatio_RefreshRate & + EDID1_STI_ImageAspectRatioMask) + { + case EDID_STI_AspectRatio_16_10: + EDIDmode.resY = (EDIDmode.resX*10)/16; + break; + case EDID_STI_AspectRatio_4_3: + EDIDmode.resY = (EDIDmode.resX*3)/4; + break; + case EDID_STI_AspectRatio_5_4: + EDIDmode.resY = (EDIDmode.resX*4)/5; + break; + case EDID_STI_AspectRatio_16_9: + EDIDmode.resY = (EDIDmode.resX*9)/16; + break; + } + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + + index++; + } + /* try to find Standard Timings (listed in optional EXTENSION Blocks) + in controller mode list */ + /* not implemented */ + /* use Established Timings */ + if (edid1_established_tim(&edid, EST_1280x1024_75Hz)) + { + EDIDmode.resX = 1280; + EDIDmode.resY = 1024; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + if (edid1_established_tim(&edid, EST_1152x870_75Hz)) + { + EDIDmode.resX = 1152; + EDIDmode.resY = 870; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + if (edid1_established_tim(&edid, EST_1024x768_75Hz) || + edid1_established_tim(&edid, EST_1024x768_70Hz) || + edid1_established_tim(&edid, EST_1024x768_60Hz) || + edid1_established_tim(&edid, EST_1024x768_87Hz)) + { + EDIDmode.resX = 1024; + EDIDmode.resY = 768; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + if (edid1_established_tim(&edid, EST_832x624_75Hz)) + { + EDIDmode.resX = 832; + EDIDmode.resY = 624; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + if (edid1_established_tim(&edid, EST_800x600_60Hz) || + edid1_established_tim(&edid, EST_800x600_56Hz) || + edid1_established_tim(&edid, EST_800x600_75Hz) || + edid1_established_tim(&edid, EST_800x600_72Hz)) + { + EDIDmode.resX = 800; + EDIDmode.resY = 600; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + if (edid1_established_tim(&edid, EST_720x400_88Hz) || + edid1_established_tim(&edid, EST_720x400_70Hz)) + { + EDIDmode.resX = 720; + EDIDmode.resY = 400; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + if (edid1_established_tim(&edid, EST_640x480_75Hz) || + edid1_established_tim(&edid, EST_640x480_72Hz) || + edid1_established_tim(&edid, EST_640x480_67Hz) || + edid1_established_tim(&edid, EST_640x480_60Hz)) + { + EDIDmode.resX = 640; + EDIDmode.resY = 480; + EDIDmode.bpp = 0; + if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) != + -1) + return EDIDmode.mode_number; + } + } + else + printk(FB_VESA_NAME " error reading EDID: unsupported version\n"); + return -1; +} + +void vesa_realmode_bootup_init(void) +{ + uint32_t vbe_ret_val; + uint16_t size; + VBE_vbe_info_block *vib = (VBE_vbe_info_block *) + i386_get_default_rm_buffer(&size); + vbe_ret_val = VBE_controller_information(vib, 0x300); + if (vbe_ret_val == -1) + { + printk(FB_VESA_NAME " error calling real mode interrupt.\n"); + return; + } + if (vbe_ret_val != (VBE_callSuccessful<<8 | VBE_functionSupported)) + { + printk(FB_VESA_NAME " Function 00h (read VBE info block)" + "not supported.\n"); + } +/* Helper array is later filled with mode numbers and their parameters + sorted from the biggest values to the smalest where priorities of + parameters are from the highest to the lowest: resolution X, + resolution Y, bits per pixel. + The array is used for search the monitor provided parameters in EDID + structure and if found we set such mode using corresponding + VESA function. */ +#define MAX_NO_OF_SORTED_MODES 100 + Mode_params sorted_mode_params[MAX_NO_OF_SORTED_MODES]; + + uint16_t *vmpSegOff = (uint16_t *)&vib->VideoModePtr; + uint16_t *modeNOPtr = (uint16_t*) + i386_Real_to_physical(*(vmpSegOff+1), *vmpSegOff); + uint16_t iterator = 0; + + if (*(uint16_t*)vib->VideoModePtr == VBE_STUB_VideoModeList) + { + printk(FB_VESA_NAME " VBE Core not implemented!\n"); + } + else + { + /* prepare list of modes */ + while (*(modeNOPtr+iterator) != VBE_END_OF_VideoModeList && + *(modeNOPtr+iterator) != 0) + { /* some bios implementations ends the list incorrectly with 0 */ + if (iterator < MAX_NO_OF_SORTED_MODES) + { + sorted_mode_params[iterator].mode_number =*(modeNOPtr+iterator); + iterator ++; + } + else + break; + } + if (iterator < MAX_NO_OF_SORTED_MODES) + sorted_mode_params[iterator].mode_number = 0; + } + + VBE_mode_info_block *mib = (VBE_mode_info_block *) + i386_get_default_rm_buffer(&size); + iterator = 0; + uint8_t nextFilteredMode = 0; + uint16_t required_mode_attributes = VBE_modSupInHWMask | + VBE_ColorModeMask | VBE_GraphicsModeMask | VBE_LinFraBufModeAvaiMask; + /* get parameters of modes and filter modes according to set + required parameters */ + while (iterator < MAX_NO_OF_SORTED_MODES && + sorted_mode_params[iterator].mode_number!=0) + { + VBE_mode_information(mib, sorted_mode_params[iterator].mode_number); + if ((mib->ModeAttributes&required_mode_attributes) == + required_mode_attributes) + { + sorted_mode_params[nextFilteredMode].mode_number = + sorted_mode_params[iterator].mode_number; + sorted_mode_params[nextFilteredMode].resX = mib->XResolution; + sorted_mode_params[nextFilteredMode].resY = mib->YResolution; + sorted_mode_params[nextFilteredMode].bpp = mib->BitsPerPixel; + nextFilteredMode ++; + } + iterator ++; + } + sorted_mode_params[nextFilteredMode].mode_number = 0; + + uint8_t number_of_modes = nextFilteredMode; + + /* first search for video argument in multiboot options */ + vbe_used_mode = find_mode_using_cmdline(sorted_mode_params, + number_of_modes); + + if (vbe_used_mode == NO_MODE_REQ) { + vbe_used_mode = find_mode_from_string(sorted_mode_params, + number_of_modes, rtems_fb_default_mode); + if (vbe_used_mode != NO_MODE_REQ) { + printk(FB_VESA_NAME " using application option to select" + " video mode\n"); + } + } + else + { + printk(FB_VESA_NAME " using command line option '--video='" + "to select video mode\n"); + } + + switch (vbe_used_mode) { + case NO_SUITABLE_MODE: + printk(FB_VESA_NAME " requested mode not found\n"); + return; + case BAD_FORMAT: + printk(FB_VESA_NAME " bad format of video requested\n"); + return; + case DONT_INIT: + printk(FB_VESA_NAME " selected not to initialize graphics\n"); + return; + case NO_MODE_REQ: + printk(FB_VESA_NAME " not initialized, no video selected\n"); + return; + } + + /* sort filtered modes */ + Mode_params modeXchgPlace; + iterator = 0; + uint8_t j; + uint8_t idxBestMode; + while (iterator < number_of_modes) + { + idxBestMode = iterator; + j = iterator+1; + while (j < number_of_modes) + { + if (sorted_mode_params[j].resX > + sorted_mode_params[idxBestMode].resX) + idxBestMode = j; + else if (sorted_mode_params[j].resX == + sorted_mode_params[idxBestMode].resX) + { + if (sorted_mode_params[j].resY > + sorted_mode_params[idxBestMode].resY) + idxBestMode = j; + else if (sorted_mode_params[j].resY == + sorted_mode_params[idxBestMode].resY) + { + if (sorted_mode_params[j].bpp > + sorted_mode_params[idxBestMode].bpp) + idxBestMode = j; + } + } + j++; + } + if (idxBestMode != iterator) + { + modeXchgPlace = sorted_mode_params[iterator]; + sorted_mode_params[iterator] = sorted_mode_params[idxBestMode]; + sorted_mode_params[idxBestMode] = modeXchgPlace; + } + iterator++; + } + + if (vbe_used_mode == AUTO_SELECT) + { + printk(FB_VESA_NAME " auto video mode selected" + "\n\ttrying EDID ...\n"); + /* second search monitor for good resolution */ + vbe_used_mode = find_mode_using_EDID(sorted_mode_params, + number_of_modes); + if (vbe_used_mode == -1) + { + printk(FB_VESA_NAME" monitor's EDID video parameters not supported" + "\n\tusing mode with highest resolution, bpp\n"); + /* third set highest values */ + vbe_used_mode = sorted_mode_params[0].mode_number; + } + } + + /* fill framebuffer structs with info about selected mode */ + vbe_ret_val = VBE_mode_information(mib, vbe_used_mode); + if ((vbe_ret_val&0xff)!=VBE_functionSupported || + (vbe_ret_val>>8)!=VBE_callSuccessful) + { + printk(FB_VESA_NAME " Cannot get mode info anymore. ax=0x%lx\n", + vbe_ret_val); + } + + fb_var.xres = mib->XResolution; + fb_var.yres = mib->YResolution; + fb_var.bits_per_pixel = mib->BitsPerPixel; + fb_var.red.offset = mib->LinRedFieldPosition; + fb_var.red.length = mib->LinRedMaskSize; + fb_var.red.msb_right = 0; + fb_var.green.offset = mib->LinGreenFieldPosition; + fb_var.green.length = mib->LinGreenMaskSize; + fb_var.green.msb_right = 0; + fb_var.blue.offset = mib->LinBlueFieldPosition; + fb_var.blue.length = mib->LinBlueMaskSize; + fb_var.blue.msb_right = 0; + fb_var.transp.offset = mib->LinRsvdFieldPosition; + fb_var.transp.length = mib->LinRsvdMaskSize; + fb_var.transp.msb_right =0; + + fb_fix.smem_start = (char *)mib->PhysBasePtr; + fb_fix.line_length = mib->LinBytesPerScanLine; + fb_fix.smem_len = fb_fix.line_length*fb_var.yres; + fb_fix.type = FB_TYPE_PACKED_PIXELS; + if (fb_var.bits_per_pixel < 24) + fb_fix.visual = FB_VISUAL_DIRECTCOLOR; + else + fb_fix.visual = FB_VISUAL_TRUECOLOR; + + /* set selected mode */ + vbe_ret_val = VBE_set_mode(vbe_used_mode | VBE_linearFlatFrameBufMask, + (VBE_CRTC_info_block *)(i386_get_default_rm_buffer(&size))); + if (vbe_ret_val>>8 == VBE_callFailed) + printk(FB_VESA_NAME " VBE: Requested mode is not available."); + + if ((vbe_ret_val&0xff)!= (VBE_functionSupported | VBE_callSuccessful<<8)) + printk(FB_VESA_NAME " Call to function 2h (set VBE mode) failed. " + "ax=0x%" PRIx32 "\n", vbe_ret_val); + + vib = (void *) 0; + mib = (void *) 0; +} + +/* + * fb_vesa device driver INITIALIZE entry point. + */ +rtems_device_driver +frame_buffer_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + + printk(FB_VESA_NAME " frame buffer -- driver initializing..\n" ); + + /* + * Register the device. + */ + status = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0); + if (status != RTEMS_SUCCESSFUL) + { + printk("Error registering " FRAMEBUFFER_DEVICE_0_NAME + " - " FB_VESA_NAME " frame buffer device!\n"); + rtems_fatal_error_occurred( status ); + } + + _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE); + + return RTEMS_SUCCESSFUL; +} + +/* + * fb_vesa device driver OPEN entry point + */ +rtems_device_driver +frame_buffer_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + printk( FB_VESA_NAME " open device\n" ); + + if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0 ) + { + printk( FB_VESA_NAME " could not lock vesa_mutex\n" ); + + return RTEMS_UNSATISFIED; + } + + return RTEMS_SUCCESSFUL; + +} + +/* + * fb_vesa device driver CLOSE entry point + */ +rtems_device_driver +frame_buffer_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + printk( FB_VESA_NAME " close device\n" ); + _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE); + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() */ + + printk(FB_VESA_NAME ": close called.\n" ); + return RTEMS_SUCCESSFUL; +} + +/* + * fb_vesa device driver READ entry point. + */ +rtems_device_driver +frame_buffer_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + printk( FB_VESA_NAME " read device\n" ); + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = + ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? + (fb_fix.smem_len - rw_args->offset) : + rw_args->count; + memcpy(rw_args->buffer, (const void *) + (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; +} + +/* + * frame_vesa device driver WRITE entry point. + */ +rtems_device_driver +frame_buffer_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + printk( FB_VESA_NAME " write device\n" ); + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = + ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? + (fb_fix.smem_len - rw_args->offset) : + rw_args->count; + memcpy( (void *) (fb_fix.smem_start + rw_args->offset), + rw_args->buffer, rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; +} + +static int get_fix_screen_info( struct fb_fix_screeninfo *info ) +{ + *info = fb_fix; + return 0; +} + +static int get_var_screen_info( struct fb_var_screeninfo *info ) +{ + *info = fb_var; + return 0; +} + +/* + * IOCTL entry point -- This method is called to carry + * all services of this interface. + */ +rtems_device_driver +frame_buffer_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + printk( FB_VESA_NAME " ioctl called, cmd=%" PRIx32 "\n", args->command ); + printk("fbxres %lu, fbyres %lu\n", fb_var.xres, fb_var.yres); + printk("fbbpp %lu\n", fb_var.bits_per_pixel); + + switch (args->command) + { + case FBIOGET_FSCREENINFO: + args->ioctl_return = + get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer ); + break; + case FBIOGET_VSCREENINFO: + args->ioctl_return = + get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer ); + break; + case FBIOPUT_VSCREENINFO: + /* not implemented yet */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOGETCMAP: + /* no palette - truecolor mode */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOPUTCMAP: + /* no palette - truecolor mode */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + default: + args->ioctl_return = 0; + break; + } + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/i386/pc386/console/fb_vga.c b/bsps/i386/pc386/console/fb_vga.c new file mode 100644 index 0000000000..75ad56eb98 --- /dev/null +++ b/bsps/i386/pc386/console/fb_vga.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2000 - Rosimildo da Silva ( rdasilva@connecttel.com ) + * + * MODULE DESCRIPTION: + * This module implements FB driver for "Bare VGA". It uses the + * routines for "bare hardware" found in vgainit.c. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <pthread.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/libio.h> + +#include <rtems/fb.h> +#include <rtems/framebuffer.h> + +#include <rtems/score/atomic.h> + +/* these routines are defined in vgainit.c.*/ +extern void ega_hwinit( void ); +extern void ega_hwterm( void ); + +/* flag to limit driver to protect against multiple opens */ +static Atomic_Flag driver_mutex; + +/* screen information for the VGA driver */ +static struct fb_var_screeninfo fb_var = +{ + .xres = 640, + .yres = 480, + .bits_per_pixel = 4 +}; + +static struct fb_fix_screeninfo fb_fix = +{ + .smem_start = (volatile char *)0xA0000, /* buffer pointer */ + .smem_len = 0x10000, /* buffer size */ + .type = FB_TYPE_VGA_PLANES, /* type of dsplay */ + .visual = FB_VISUAL_PSEUDOCOLOR, /* color scheme used */ + .line_length = 80 /* chars per line */ +}; + + +static uint16_t red16[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, + 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff +}; +static uint16_t green16[] = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa, + 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff +}; +static uint16_t blue16[] = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, + 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff +}; + +/* Functionality to support multiple VGA frame buffers can be added easily, + * but is not supported at this moment because there is no need for two or + * more "classic" VGA adapters. Multiple frame buffer drivers may be + * implemented and If we had implement it they would be named as "/dev/fb0", + * "/dev/fb1", "/dev/fb2" and so on. + */ +/* + * fbvga device driver INITIALIZE entry point. + */ +rtems_device_driver frame_buffer_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + + printk( "FBVGA -- driver initializing..\n" ); + + /* + * Register the device + */ + status = rtems_io_register_name (FRAMEBUFFER_DEVICE_0_NAME, major, 0); + if (status != RTEMS_SUCCESSFUL) { + printk("Error registering " FRAMEBUFFER_DEVICE_0_NAME + " FBVGA framebuffer device!\n"); + rtems_fatal_error_occurred( status ); + } + + _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE); + + return RTEMS_SUCCESSFUL; +} + +/* + * fbvga device driver OPEN entry point + */ +rtems_device_driver frame_buffer_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0 ) { + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() + */ + ega_hwinit(); + printk( "FBVGA open called.\n" ); + return RTEMS_SUCCESSFUL; + } + + return RTEMS_UNSATISFIED; +} + +/* + * fbvga device driver CLOSE entry point + */ +rtems_device_driver frame_buffer_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE); + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() */ + ega_hwterm(); + printk( "FBVGA close called.\n" ); + return RTEMS_SUCCESSFUL; + +/* + * fbvga device driver READ entry point. + */ +rtems_device_driver frame_buffer_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy(rw_args->buffer, (const void *) (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; +} + +/* + * frame_buffer device driver WRITE entry point. + */ +rtems_device_driver frame_buffer_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy( (void *) (fb_fix.smem_start + rw_args->offset), rw_args->buffer, rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; +} + +static int get_fix_screen_info( struct fb_fix_screeninfo *info ) +{ + *info = fb_fix; + return 0; +} + +static int get_var_screen_info( struct fb_var_screeninfo *info ) +{ + *info = fb_var; + return 0; +} + +static int get_palette( struct fb_cmap *cmap ) +{ + uint32_t i; + + if ( cmap->start + cmap->len >= 16 ) + return 1; + + for( i = 0; i < cmap->len; i++ ) { + cmap->red[ cmap->start + i ] = red16[ cmap->start + i ]; + cmap->green[ cmap->start + i ] = green16[ cmap->start + i ]; + cmap->blue[ cmap->start + i ] = blue16[ cmap->start + i ]; + } + return 0; +} + +static int set_palette( struct fb_cmap *cmap ) +{ + uint32_t i; + + if ( cmap->start + cmap->len >= 16 ) + return 1; + + for( i = 0; i < cmap->len; i++ ) { + red16[ cmap->start + i ] = cmap->red[ cmap->start + i ]; + green16[ cmap->start + i ] = cmap->green[ cmap->start + i ]; + blue16[ cmap->start + i ] = cmap->blue[ cmap->start + i ]; + } + return 0; +} + +/* + * IOCTL entry point -- This method is called to carry + * all services of this interface. + */ +rtems_device_driver frame_buffer_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + printk( "FBVGA ioctl called, cmd=%x\n", args->command ); + + switch( args->command ) { + case FBIOGET_FSCREENINFO: + args->ioctl_return = get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer ); + break; + case FBIOGET_VSCREENINFO: + args->ioctl_return = get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer ); + break; + case FBIOPUT_VSCREENINFO: + /* not implemented yet*/ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOGETCMAP: + args->ioctl_return = get_palette( ( struct fb_cmap * ) args->buffer ); + break; + case FBIOPUTCMAP: + args->ioctl_return = set_palette( ( struct fb_cmap * ) args->buffer ); + break; + + default: + args->ioctl_return = 0; + break; + } + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/i386/pc386/console/gdb_select.c b/bsps/i386/pc386/console/gdb_select.c new file mode 100644 index 0000000000..0fe3b2cdad --- /dev/null +++ b/bsps/i386/pc386/console/gdb_select.c @@ -0,0 +1,170 @@ +/** + * @file + * + * @ingroup GDB + * + * @brief pc386 gdb select + * + * This file contains a routine to enable and select the UART the gdb stub + * connects too. Currently limited to COM1 and COM2. See + * shared/comm/i386-stub-glue.c file. + */ + +/* + * COPYRIGHT (c) 2016. + * Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <stdlib.h> +#include <limits.h> + +#include <bsp.h> +#include <rtems/libio.h> +#include <rtems/console.h> +#include <rtems/termiostypes.h> +#include <libchip/serial.h> +#include <libchip/ns16550.h> +#include <bsp/bspimpl.h> + +#include "../../shared/dev/serial/legacy-console.h" + +/* + * Used in the stub to print output. + */ +int remote_debug; +/* + * Defined in the stub, used here. + */ +void set_debug_traps(void); + +/* + * Added here to get a valid baudrate. Needs to go once we + * move to the standard UART driver. + */ +int BSPBaseBaud; + +static bool gdb_port_probe(int minor) +{ + /* Return false as GDB has claimed the port */ + return false; +} + +void pc386_parse_gdb_arguments(void) +{ + static const char *opt; + + /* + * Check the command line to see if com1-com4 are disabled. + */ + opt = bsp_cmdline_arg("--gdb="); + if ( opt ) { + const char *option; + const char *comma; + size_t length; + size_t index; + rtems_device_minor_number minor; + uint32_t baudrate = 115200; + bool halt = false; + console_tbl *port; + + /* + * Fine the length, there can be more command line visible. + */ + length = 0; + while ((opt[length] != ' ') && (opt[length] != '\0')) { + ++length; + if (length > NAME_MAX) { + printk("invalid option (--gdb): too long\n"); + return; + } + } + + /* + * Only match up to a comma or NULL + */ + index = 0; + while ((opt[index] != '=') && (index < length)) { + ++index; + } + + if (opt[index] != '=') { + printk("invalid option (--gdb): no equals\n"); + return; + } + + ++index; + option = &opt[index]; + + while ((opt[index] != ',') && (index < length)) { + ++index; + } + + if (opt[index] == ',') + comma = &opt[index]; + else + comma = NULL; + + length = &opt[index] - option; + + port = console_find_console_entry( option, length, &minor ); + + if ( port == NULL ) { + printk("invalid option (--gdb): port not found\n"); + return; + } + + if (comma) { + option = comma + 1; + baudrate = strtoul(option, 0, 10); + switch (baudrate) { + case 115200: + case 57600: + case 38400: + case 19200: + case 9600: + case 4800: + port->pDeviceParams = (void*) baudrate; + BSPBaseBaud = baudrate; /* REMOVE ME */ + break; + default: + printk("invalid option (--gdb): bad baudrate\n"); + return; + } + } + + /* + * Provide a probe that fails so the device is not part of termios. All + * functions are polling. + */ + port->deviceProbe = gdb_port_probe; + port->pDeviceFns = &ns16550_fns_polled; + + opt = bsp_cmdline_arg("--gdb-remote-debug"); + if ( opt ) { + remote_debug = 1; + } + + opt = bsp_cmdline_arg("--gdb-break"); + if ( opt ) { + halt = true; + } + + printk("GDB stub: enable %s%s%s\n", + port->sDeviceName, + remote_debug ? ", remote-debug" : "", + halt ? ", halting" : ""); + + i386_stub_glue_init(minor); + set_debug_traps(); + i386_stub_glue_init_breakin(); + + if ( halt ) { + printk("GDB stub: waiting for remote connection..\n"); + breakpoint(); + } + } +} diff --git a/bsps/i386/pc386/console/i386kbd.h b/bsps/i386/pc386/console/i386kbd.h new file mode 100644 index 0000000000..627b37c750 --- /dev/null +++ b/bsps/i386/pc386/console/i386kbd.h @@ -0,0 +1,192 @@ +/** + * @file + * + * @ingroup i386_pc386 + * + * @brief I386 keyboard definitions. + */ + +/* + * linux/include/asm-i386/keyboard.h + * + * Created 3 Nov 1996 by Geert Uytterhoeven + */ + +/* + * This file contains the i386 architecture specific keyboard definitions + */ + +#ifndef _I386_KEYBOARD_H +#define _I386_KEYBOARD_H + +#include <i386_io.h> + +#define KEYBOARD_IRQ 1 +#define DISABLE_KBD_DURING_INTERRUPTS 0 + +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; + +#define kbd_setkeycode pckbd_setkeycode +#define kbd_getkeycode pckbd_getkeycode +#define kbd_translate pckbd_translate +#define kbd_unexpected_up pckbd_unexpected_up +#define kbd_leds pckbd_leds +#define kbd_init_hw pckbd_init_hw +#define kbd_sysrq_xlate pckbd_sysrq_xlate + +#define SYSRQ_KEY 0x54 + +/* resource allocation */ +#define kbd_request_region() /* request_region(0x60, 16, "keyboard") */ +#define kbd_request_irq(handler) /* request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL) */ + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do { } while(0) + +/* + * Machine specific bits for the PS/2 driver + */ + +#define AUX_IRQ 12 + +#define aux_request_irq(hand, dev_id) /* request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) */ + +#define aux_free_irq(dev_id) /* free_irq(AUX_IRQ, dev_id) */ + +/* + * include/linux/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers on normal PCs. + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define AUX_BUF_SIZE 2048 /* This might be better divisible by + three to make overruns stay in sync + but then the read function would need + a lock etc - ick */ + +#define mark_bh(x) + +#endif /* _I386_KEYBOARD_H */ diff --git a/bsps/i386/pc386/console/inch.c b/bsps/i386/pc386/console/inch.c new file mode 100644 index 0000000000..f5d5079236 --- /dev/null +++ b/bsps/i386/pc386/console/inch.c @@ -0,0 +1,300 @@ +/*-------------------------------------------------------------------------+ +| inch.c v1.1 - PC386 BSP - 1997/08/07 ++--------------------------------------------------------------------------+ +| (C) Copyright 1997 - +| - NavIST Group - Real-Time Distributed Systems and Industrial Automation +| +| http://pandora.ist.utl.pt +| +| Instituto Superior Tecnico * Lisboa * PORTUGAL ++--------------------------------------------------------------------------+ +| Disclaimer: +| +| This file is provided "AS IS" without warranty of any kind, either +| expressed or implied. ++--------------------------------------------------------------------------+ +| This code is based on: +| inch.c,v 1.3 1995/12/19 20:07:25 joel Exp - go32 BSP +| With the following copyright notice: +| With the following copyright notice: +| ************************************************************************** +| * COPYRIGHT (c) 1989-1998. +| * On-Line Applications Research Corporation (OAR). +| * +| * The license and distribution terms for this file may be +| * found in the file LICENSE in this distribution or at +| * http://www.rtems.org/license/LICENSE. +| ************************************************************************** ++--------------------------------------------------------------------------*/ + +#include <bsp.h> +#include <bsp/bootcard.h> +#include <bsp/irq.h> + +/*-------------------------------------------------------------------------+ +| Constants ++--------------------------------------------------------------------------*/ +#define KBD_CTL 0x61 /* -------------------------------- */ +#define KBD_DATA 0x60 /* Ports for PC keyboard controller */ +#define KBD_STATUS 0x64 /* -------------------------------- */ + +#define KBD_BUF_SIZE 256 + +/*-------------------------------------------------------------------------+ +| Global Variables ++--------------------------------------------------------------------------*/ +static char key_map[] = +{ + 0,033,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t', + 'q','w','e','r','t','y','u','i','o','p','[',']',015,0x80, + 'a','s','d','f','g','h','j','k','l',';',047,0140,0x80, + 0134,'z','x','c','v','b','n','m',',','.','/',0x80, + '*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,'0',0177 +}; /* Keyboard scancode -> character map with no modifiers. */ + +static char shift_map[] = +{ + 0,033,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t', + 'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0x80, + 'A','S','D','F','G','H','J','K','L',':',042,'~',0x80, + '|','Z','X','C','V','B','N','M','<','>','?',0x80, + '*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,'7','8','9',0x80,'4','5','6',0x80, + '1','2','3','0',177 +}; /* Keyboard scancode -> character map with SHIFT key modifier. */ + +static unsigned short kbd_buffer[KBD_BUF_SIZE]; +static uint16_t kbd_first = 0; +static uint16_t kbd_last = 0; +static uint16_t kbd_end = KBD_BUF_SIZE - 1; + +/*-------------------------------------------------------------------------+ +| Function: _IBMPC_scankey +| Description: This function can be called during a poll for input, or by +| an ISR. Basically any time you want to process a keypress. +| Global Variables: key_map, shift_map. +| Arguments: outChar - character read in case of a valid reading, +| otherwise unchanged. +| Returns: TRUE in case a valid character has been read, +| FALSE otherwise. ++--------------------------------------------------------------------------*/ +static bool +_IBMPC_scankey(char *outChar) +{ + unsigned char inChar; + static int alt_pressed = 0; + static int ctrl_pressed = 0; + static int shift_pressed = 0; + static int caps_pressed = 0; + static int extended = 0; + + *outChar = '\0'; /* default value if we return false */ + + /* Read keyboard controller, toggle enable */ + inport_byte(KBD_CTL, inChar); + outport_byte(KBD_CTL, inChar & ~0x80); + outport_byte(KBD_CTL, inChar | 0x80); + outport_byte(KBD_CTL, inChar & ~0x80); + + /* See if it has data */ + inport_byte(KBD_STATUS, inChar); + if ((inChar & 0x01) == 0) + return false; + + /* Read the data. Handle nonsense with shift, control, etc. */ + inport_byte(KBD_DATA, inChar); + + if (extended) + extended--; + + switch (inChar) + { + case 0xe0: + extended = 2; + return false; + break; + + case 0x38: + alt_pressed = 1; + return false; + break; + case 0xb8: + alt_pressed = 0; + return false; + break; + + case 0x1d: + ctrl_pressed = 1; + return false; + break; + case 0x9d: + ctrl_pressed = 0; + return false; + break; + + case 0x2a: + if (extended) + return false; + case 0x36: + shift_pressed = 1; + return false; + break; + case 0xaa: + if (extended) + return false; + case 0xb6: + shift_pressed = 0; + return false; + break; + + case 0x3a: + caps_pressed = 1; + return false; + break; + case 0xba: + caps_pressed = 0; + return false; + break; + + case 0x53: + if (ctrl_pressed && alt_pressed) + bsp_reset(); /* ctrl+alt+del -> reboot */ + break; + + /* + * Ignore unrecognized keys--usually arrow and such + */ + default: + if ((inChar & 0x80) || (inChar > 0x39)) + /* High-bit on means key is being released, not pressed */ + return false; + break; + } /* switch */ + + /* Strip high bit, look up in our map */ + inChar &= 0x7f; + if (ctrl_pressed) + { + *outChar = key_map[inChar]; + *outChar &= 037; + } + else + { + *outChar = shift_pressed ? shift_map[inChar] : key_map[inChar]; + if (caps_pressed) + { + if (*outChar >= 'A' && *outChar <= 'Z') + *outChar += 'a' - 'A'; + else if (*outChar >= 'a' && *outChar <= 'z') + *outChar -= 'a' - 'A'; + } + } + + return true; +} /* _IBMPC_scankey */ + +/*-------------------------------------------------------------------------+ +| Function: _IBMPC_chrdy +| Description: Check keyboard ISR buffer and return character if not empty. +| Global Variables: kbd_buffer, kbd_first, kbd_last. +| Arguments: c - character read if keyboard buffer not empty, otherwise +| unchanged. +| Returns: TRUE if keyboard buffer not empty, FALSE otherwise. ++--------------------------------------------------------------------------*/ +static bool +_IBMPC_chrdy(char *c) +{ +#if CCJ_REMOVED_NO_IDEA_ABOUT_THIS_CODE_OR_COMMENT + /* FIX ME!!! It doesn't work without something like the following line. + Find out why! */ + printk(""); +#endif + + /* Check buffer our ISR builds */ + if (kbd_first != kbd_last) + { + *c = kbd_buffer[kbd_first]; + + kbd_first = (kbd_first + 1) % KBD_BUF_SIZE; + return true; + } + else + return false; +} /* _IBMPC_chrdy */ + +/*-------------------------------------------------------------------------+ +| Function: _IBMPC_inch +| Description: Poll keyboard until a character is ready and return it. +| Global Variables: None. +| Arguments: None. +| Returns: character read from keyboard. ++--------------------------------------------------------------------------*/ +char +_IBMPC_inch(void) +{ + char c; + while (!_IBMPC_chrdy(&c)) + continue; + + return c; +} /* _IBMPC_inch */ + +/* + * Routine that can be used before interrupt management is initialized. + */ +int BSP_wait_polled_input(void) +{ + char c; + while (!_IBMPC_scankey(&c)) + continue; + + return c; +} + +/* + * Check if a key has been pressed. This is a non-destructive + * call, meaning, it keeps the key in the buffer. + */ +int rtems_kbpoll( void ) +{ + int rc; + + /* + * The locking or disable of interrupts does not help + * there because if interrupts are enabled after leave of this + * function the state can change without notice anyway. + */ + RTEMS_COMPILER_MEMORY_BARRIER(); + + rc = ( kbd_first != kbd_last ) ? TRUE : FALSE; + + RTEMS_COMPILER_MEMORY_BARRIER(); + + return rc; +} + +int getch( void ) +{ + int c; + + while( kbd_first == kbd_last ) + { + rtems_task_wake_after( 10 ); + } + c = kbd_buffer[ kbd_first ]; + kbd_first = (kbd_first + 1) % KBD_BUF_SIZE; + return c; +} + +void add_to_queue( unsigned short b ) +{ + unsigned int next; + kbd_buffer[ kbd_last ] = b; + next = (kbd_last == kbd_end) ? 0 : kbd_last + 1; + if( next != kbd_first ) + { + kbd_last = next; + } +} diff --git a/bsps/i386/pc386/console/kbd_parser.c b/bsps/i386/pc386/console/kbd_parser.c new file mode 100644 index 0000000000..f3d2f9c55a --- /dev/null +++ b/bsps/i386/pc386/console/kbd_parser.c @@ -0,0 +1,47 @@ +/* + * The contents of this file were formerly in console.c which + * had the following copyright notice: + * + * (C) Copyright 1997 + * NavIST Group - Real-Time Distributed Systems and Industrial Automation + * http://pandora.ist.utl.pt + * Instituto Superior Tecnico * Lisboa * PORTUGAL + * + * The original code and subsequent modifications are: + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems.h> +#include <rtems/keyboard.h> +#include <rtems/mw_uid.h> + +/* adds a kbd message to the queue */ +static void kbd_parser( void *ptr, unsigned short keycode, unsigned long mods ) +{ + struct MW_UID_MESSAGE m; + struct kbd_struct * kbd = (struct kbd_struct *)ptr; + + m.type = MV_UID_KBD; + m.m.kbd.code = keycode; + m.m.kbd.modifiers = kbd->ledflagstate; + m.m.kbd.mode = kbd->kbdmode; + /* printk( "kbd: msg: keycode=%X, mod=%X\n", keycode, mods ); */ + + uid_send_message( &m ); +} + +void register_kbd_msg_queue( char *q_name, int port ) +{ + kbd_set_driver_handler( kbd_parser ); +} + +void unregister_kbd_msg_queue( int port ) +{ + kbd_set_driver_handler( NULL ); +} diff --git a/bsps/i386/pc386/console/keyboard.c b/bsps/i386/pc386/console/keyboard.c new file mode 100644 index 0000000000..0c8991b829 --- /dev/null +++ b/bsps/i386/pc386/console/keyboard.c @@ -0,0 +1,881 @@ +/* + * Rosimildo da Silva: rdasilva@connecttel.com + */ + +#include <limits.h> +#include <sys/types.h> +#include <rtems/keyboard.h> +#include "i386kbd.h" +#include <rtems/kd.h> +#include <bsp.h> +#include <bsp/bootcard.h> +#include <stdatomic.h> + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +/* + * Some laptops take the 789uiojklm,. keys as number pad when NumLock + * is on. This seems a good reason to start with NumLock off. + */ +#define KBD_DEFLEDS 0 +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +static int kbd_test_and_set_bit(int nr, atomic_uint_least32_t * addr) +{ + uint_least32_t mask; + int retval; + + addr += nr >> 5; + mask = 1UL << (nr & 0x1f); + + retval = (atomic_fetch_or(addr, mask) & mask) != 0; + + return retval; +} + +static int kbd_test_and_clear_bit(int nr, atomic_uint_least32_t * addr) +{ + uint_least32_t mask; + int retval; + + addr += nr >> 5; + mask = 1UL << (nr & 0x1f); + + retval = (atomic_fetch_and(addr, ~mask) & mask) != 0; + + return retval; +} + +static int kbd_test_bit(int nr, atomic_uint_least32_t * addr) +{ + unsigned long mask; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & atomic_load(addr)) != 0); +} + +/* + * global state includes the following, and various static variables + * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. + * (last_console is now a global variable) + */ +#define KBD_BITS_PER_ELEMENT (sizeof(atomic_uint_least32_t)*CHAR_BIT) + +/* shift state counters.. */ +static unsigned char k_down[NR_SHIFT] = {0, }; +/* keyboard key bitmap */ +static atomic_uint_least32_t + key_down[(256 + KBD_BITS_PER_ELEMENT - 1) / KBD_BITS_PER_ELEMENT] = { 0, }; + +static int dead_key_next = 0; +/* + * In order to retrieve the shift_state (for the mouse server), either + * the variable must be global, or a new procedure must be created to + * return the value. I chose the former way. + */ +int shift_state = 0; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr = 0; +static char rep = 0; /* flag telling character repeat */ + +/* default console for RTEMS */ +static int fg_console = 0; + +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct kbd_struct * kbd = kbd_table; + +void compute_shiftstate(void); + +typedef void (*k_hand)(unsigned char value, char up_flag); +typedef void (k_handfn)(unsigned char value, char up_flag); + +static k_handfn + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, + do_ignore; + +static k_hand key_handler[16] = { + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, + do_ignore, do_ignore +}; + +/* Key types processed even in raw modes */ + +#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) + +typedef void (*void_fnp)(void); +typedef void (void_fn)(void); + +static void show_mem(void) +{ +} +static void show_state(void) +{ +} + +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, caps_on, compose, + SAK, decr_console, incr_console, spawn_console, bare_num; + +static void_fnp spec_fn_table[] = { + do_null, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, + bsp_reset, caps_on, compose, SAK, + decr_console, incr_console, spawn_console, bare_num +}; + +#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1, 255 +}; + +const int NR_TYPES = SIZE(max_vals); + +/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */ +static void put_queue(int); +static unsigned char handle_diacr(unsigned char); + +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; +#endif + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. + */ +static void to_utf8(ushort c) +{ + if (c < 0x80) + put_queue(c); /* 0******* */ + else if (c < 0x800) { + put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ + put_queue(0x80 | (c & 0x3f)); + } else { + put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ + put_queue(0x80 | ((c >> 6) & 0x3f)); + put_queue(0x80 | (c & 0x3f)); + } + /* UTF-8 is defined for words of up to 31 bits, + but we need only 16 bits here */ +} + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable (for machines were it makes sense). + */ + +int setkeycode(unsigned int scancode, unsigned int keycode) +{ + return kbd_setkeycode(scancode, keycode); +} + +int getkeycode(unsigned int scancode) +{ + return kbd_getkeycode(scancode); +} + +void handle_scancode(unsigned char scancode, int down) +{ + unsigned char keycode; + char up_flag = down ? 0 : 0200; + char raw_mode; + + mark_bh(CONSOLE_BH); + +#if 0 + tty = ttytab? ttytab[fg_console]: NULL; + if (tty && (!tty->driver_data)) { + /* + * We touch the tty structure via the the ttytab array + * without knowing whether or not tty is open, which + * is inherently dangerous. We currently rely on that + * fact that console_open sets tty->driver_data when + * it opens it, and clears it when it closes it. + */ + tty = NULL; + } +#endif + + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(scancode | up_flag); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * Convert scancode to keycode + */ + if (!kbd_translate(scancode, &keycode, raw_mode)) + return; + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + if (up_flag) { + rep = 0; + if(!kbd_test_and_clear_bit(keycode, key_down)) + up_flag = kbd_unexpected_up(keycode); + } else + rep = kbd_test_and_set_bit(keycode, key_down); + +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + return; + } else if (sysrq_pressed) { + if (!up_flag && sysrq_enabled) + handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); + return; + } +#endif + + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(keycode + up_flag); + raw_mode = 1; /* Most key classes will be ignored */ + } + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || vc_kbd_mode(kbd,VC_REPEAT) ) { +/* + || (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { +*/ + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) + return; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<<KG_SHIFT)]; + if (key_map) + keysym = key_map[keycode]; + } + } + + (*key_handler[type])(keysym & 0xff, up_flag); + + if (type != KT_SLOCK) + kbd->slockstate = 0; + + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +} + +static void ( *driver_input_handler_kbd )( void *, unsigned short, unsigned long ) = 0; +/* + */ +void kbd_set_driver_handler( + void ( *handler )( void *, unsigned short, unsigned long ) +) +{ + driver_input_handler_kbd = handler; +} + +static void put_queue(int ch) +{ + if ( driver_input_handler_kbd ) { + driver_input_handler_kbd( ( void *)kbd, (unsigned short)ch, 0 ); + } else { + add_to_queue( ch ); + } +} + +static void puts_queue(char *cp) +{ + while (*cp) { + put_queue( *cp ); + cp++; + } +} + +static void applkey(int key, char mode) +{ + static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; + + buf[1] = (mode ? 'O' : '['); + buf[2] = key; + puts_queue(buf); +} + +static void enter(void) +{ + if (diacr) { + put_queue(diacr); + diacr = 0; + } + put_queue(13); + + if (vc_kbd_mode(kbd,VC_CRLF)) + put_queue(10); +} + +static void caps_toggle(void) +{ + if (rep) + return; + chg_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void caps_on(void) +{ + if (rep) + return; + set_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void show_ptregs(void) +{ +} + +static void hold(void) +{ + if (rep ) + return; + chg_vc_kbd_led(kbd, VC_SCROLLOCK ); +} + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) + applkey('P', 1); + else + bare_num(); +} + +/* + * Bind this to Shift-NumLock if you work in application keypad mode + * but want to be able to change the NumLock flag. + * Bind this to NumLock if you prefer that the NumLock key always + * changes the NumLock flag. + */ +static void bare_num(void) +{ + if (!rep) + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ +} + +static void decr_console(void) +{ +} + +static void incr_console(void) +{ +} + +static void send_intr(void) +{ +} + +static void scroll_forw(void) +{ +} + +static void scroll_back(void) +{ +} + +static void compose(void) +{ + dead_key_next = 1; +} + +int spawnpid, spawnsig; + +static void spawn_console(void) +{ +} + +static void SAK(void) +{ +} + +static void do_ignore(unsigned char value, char up_flag) +{ +} + +static void do_null() +{ + compute_shiftstate(); +} + +static void do_spec(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value >= SIZE(spec_fn_table)) + return; + + if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && + !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) + return; + + spec_fn_table[value](); +} + +static void do_lowercase(unsigned char value, char up_flag) +{ +} + +static void do_self(unsigned char value, char up_flag) +{ + if (up_flag) + return; /* no action, if this is a key release */ + + if (diacr) + value = handle_diacr(value); + + if (dead_key_next) { + dead_key_next = 0; + diacr = value; + return; + } + put_queue(value); +} + +#define A_GRAVE '`' +#define A_ACUTE '\'' +#define A_CFLEX '^' +#define A_TILDE '~' +#define A_DIAER '"' +#define A_CEDIL ',' +static unsigned char ret_diacr[NR_DEAD] = + {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; + +/* Obsolete - for backwards compatibility only */ +static void do_dead(unsigned char value, char up_flag) +{ + value = ret_diacr[value]; + printk( " do_dead( %X ) ", value ); + do_dead2(value,up_flag); +} + +/* + * Handle dead key. Note that we now may have several + * dead keys modifying the same character. Very useful + * for Vietnamese. + */ +static void do_dead2(unsigned char value, char up_flag) +{ + if (up_flag) + return; + diacr = (diacr ? handle_diacr(value) : value); +} + +/* + * We have a combining character DIACR here, followed by the character CH. + * If the combination occurs in the table, return the corresponding value. + * Otherwise, if CH is a space or equals DIACR, return DIACR. + * Otherwise, conclude that DIACR was not combining after all, + * queue it and return CH. + */ +unsigned char handle_diacr(unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + if (ch == ' ' || ch == d) + return d; + + put_queue(d); + return ch; +} + +static void do_cons(unsigned char value, char up_flag) +{ + if (up_flag) + return; +} + +static void do_fn(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + if (value < SIZE(func_table)) { + if (func_table[value]) + puts_queue(func_table[value]); + } else + printk( "do_fn called with value=%d\n", value); +} + +static void do_pad(unsigned char value, char up_flag) +{ + static const char *pad_chars = "0123456789+-*/\015,.?()"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; + + if (up_flag) + return; /* no action, if this is a key release */ + + /* kludge... shift forces cursor/number keys */ + if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { + applkey(app_map[value], 1); + return; + } + if (!vc_kbd_led(kbd,VC_NUMLOCK)) + switch (value) { + case KVAL(K_PCOMMA): + case KVAL(K_PDOT): + do_fn(KVAL(K_REMOVE), 0); + return; + case KVAL(K_P0): + do_fn(KVAL(K_INSERT), 0); + return; + case KVAL(K_P1): + do_fn(KVAL(K_SELECT), 0); + return; + case KVAL(K_P2): + do_cur(KVAL(K_DOWN), 0); + return; + case KVAL(K_P3): + do_fn(KVAL(K_PGDN), 0); + return; + case KVAL(K_P4): + do_cur(KVAL(K_LEFT), 0); + return; + case KVAL(K_P6): + do_cur(KVAL(K_RIGHT), 0); + return; + case KVAL(K_P7): + do_fn(KVAL(K_FIND), 0); + return; + case KVAL(K_P8): + do_cur(KVAL(K_UP), 0); + return; + case KVAL(K_P9): + do_fn(KVAL(K_PGUP), 0); + return; + case KVAL(K_P5): + applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + return; + } + + put_queue(pad_chars[value]); + + if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) + put_queue(10); + +} + +static void do_cur(unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + if (up_flag) + return; + + applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); +} + +static void do_shift(unsigned char value, char up_flag) +{ + int old_state = shift_state; + + if (rep) + return; + + /* Mimic typewriter: + a CapsShift key acts like Shift but undoes CapsLock */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + if (!up_flag) + clr_vc_kbd_led(kbd, VC_CAPSLOCK); + } + + if (up_flag) { + /* handle the case that two shift or control + keys are depressed simultaneously */ + if (k_down[value]) + k_down[value]--; + } else + k_down[value]++; + + if (k_down[value]) + shift_state |= (1 << value); + else + shift_state &= ~ (1 << value); + + /* kludge */ + if (up_flag && shift_state != old_state && npadch != -1) { + if (kbd->kbdmode == VC_UNICODE) + to_utf8(npadch & 0xffff); + else + put_queue(npadch & 0xff); + npadch = -1; + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute k_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + for(i=0; i < SIZE(k_down); i++) + k_down[i] = 0; + + for(i=0; i < SIZE(key_down); i++) + if(atomic_load(key_down + i)) { /* skip this word if not a single bit on */ + k = i*KBD_BITS_PER_ELEMENT; + for(j=0; j<KBD_BITS_PER_ELEMENT; j++,k++) + if(kbd_test_bit(k, key_down)) { + sym = U(plain_map[k]); + if(KTYP(sym) == KT_SHIFT) { + val = KVAL(sym); + if (val == KVAL(K_CAPSSHIFT)) + val = KVAL(K_SHIFT); + k_down[val]++; + shift_state |= (1<<val); + } + } + } +} + +static void do_meta(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + if (vc_kbd_mode(kbd, VC_META)) { + put_queue('\033'); + put_queue(value); + } else + put_queue(value | 0x80); +} + +static void do_ascii(unsigned char value, char up_flag) +{ + int base; + + if (up_flag) + return; + + if (value < 10) /* decimal input of code, while Alt depressed */ + base = 10; + else { /* hexadecimal input of code, while AltGr depressed */ + value -= 10; + base = 16; + } + + if (npadch == -1) + npadch = value; + else + npadch = npadch * base + value; +} + +static void do_lock(unsigned char value, char up_flag) +{ + if (up_flag || rep) + return; + chg_vc_kbd_lock(kbd, value); +} + +static void do_slock(unsigned char value, char up_flag) +{ + if (up_flag || rep) + return; + + chg_vc_kbd_slock(kbd, value); +} + +/* + * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, + * or (ii) whatever pattern of lights people want to show using KDSETLED, + * or (iii) specified bits of specified words in kernel memory. + */ + +static unsigned char ledstate = 0xff; /* undefined */ +static unsigned char ledioctl; + +unsigned char getledstate(void) { + return ledstate; +} + +void setledstate(struct kbd_struct *kbd, unsigned int led) { + if (!(led & ~7)) { + ledioctl = led; + kbd->ledmode = LED_SHOW_IOCTL; + } else + ; + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); +} + +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; + +void register_leds( + int console, + unsigned int led, + unsigned int *addr, + unsigned int mask +) +{ + struct kbd_struct *kbd = kbd_table + console; + + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; +} + +static inline unsigned char getleds(void) +{ + + struct kbd_struct *kbd = kbd_table + fg_console; + + unsigned char leds; + + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + leds = kbd->ledflagstate; + if (kbd->ledmode == LED_SHOW_MEM) { + if (ledptrs[0].valid) { + if (*ledptrs[0].addr & ledptrs[0].mask) + leds |= 1; + else + leds &= ~1; + } + if (ledptrs[1].valid) { + if (*ledptrs[1].addr & ledptrs[1].mask) + leds |= 2; + else + leds &= ~2; + } + if (ledptrs[2].valid) { + if (*ledptrs[2].addr & ledptrs[2].mask) + leds |= 4; + else + leds &= ~4; + } + } + return leds; +} + +/* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ +static void kbd_bh(void) +{ + unsigned char leds = getleds(); + if (leds != ledstate) { + ledstate = leds; + kbd_leds(leds); + } +} + +void set_leds(void) +{ + kbd_bh(); +} + +int kbd_init(void) +{ + + int i; + struct kbd_struct kbd0; + kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; + kbd0.ledmode = LED_SHOW_MEM; + kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; + kbd0.modeflags = KBD_DEFMODE; + kbd0.kbdmode = VC_XLATE; + + for (i = 0 ; i < MAX_NR_CONSOLES ; i++) + kbd_table[i] = kbd0; + + kbd_init_hw(); + mark_bh(KEYBOARD_BH); + return 0; +} diff --git a/bsps/i386/pc386/console/outch.c b/bsps/i386/pc386/console/outch.c new file mode 100644 index 0000000000..90ffedf250 --- /dev/null +++ b/bsps/i386/pc386/console/outch.c @@ -0,0 +1,328 @@ +/* + * outch.c - This file contains code for displaying characters + * on the console uisng information that should be + * maintained by the BIOS in its data Area. + * + * Copyright (C) 1998 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * Till Straumann <strauman@slac.stanford.edu>, 2003/9: + * - added handling of basic escape sequences (cursor movement + * and erasing; just enough for the line editor 'libtecla' to + * work...) + */ + +#include <bsp.h> + +#include <stdlib.h> +#include <string.h> + +#include <crt.h> + +extern void wr_cursor(int, unsigned short); + +#define TAB_SPACE 4 +static unsigned short *bitMapBaseAddr; +static unsigned short ioCrtBaseAddr; +static unsigned short maxCol; +static unsigned short maxRow; +static unsigned char row; +static unsigned char column; +static unsigned short attribute; +static unsigned int nLines; + +static void +scroll(void) +{ + int i, j; /* Counters */ + unsigned short *pt_scroll, *pt_bitmap; /* Pointers on the bit-map */ + + pt_bitmap = bitMapBaseAddr; + j = 0; + pt_bitmap = pt_bitmap + j; + pt_scroll = pt_bitmap + maxCol; + for (i = j; i < (maxRow - 1) * maxCol; i++) { + *pt_bitmap++ = *pt_scroll++; + } + + /* + * Blank characters are displayed on the last line. + */ + for (i = 0; i < maxCol; i++) { + *pt_bitmap++ = (short) (' ' | attribute); + } +} + +static void +doCRNL(int cr, int nl) +{ + if (nl) { + if (++row == maxRow) { + scroll(); /* Scroll the screen now */ + row = maxRow - 1; + } + nLines++; + } + if (cr) + column = 0; + /* Move cursor on the next location */ + if (cr || nl) + wr_cursor(row * maxCol + column, ioCrtBaseAddr); +} + +int (*videoHook)(char, int *)=0; + +static void +advanceCursor(void) +{ + if (++column == maxCol) + doCRNL(1,1); + else + wr_cursor(row * maxCol + column, ioCrtBaseAddr); +} + +static void +gotorc(int r, int c) +{ + column = c; + row = r; + + wr_cursor(row * maxCol + column, ioCrtBaseAddr); +} + +#define ESC ((char)27) +/* erase current location without moving the cursor */ +#define BLANK ((char)0x7f) + +static void +videoPutChar(char car) +{ + unsigned short *pt_bitmap = bitMapBaseAddr + row * maxCol + column; + + switch (car) { + case '\b': { + if (column) column--; + /* Move cursor on the previous location */ + wr_cursor(row * maxCol + column, ioCrtBaseAddr); + return; + } + case '\t': { + int i; + + i = TAB_SPACE - (column & (TAB_SPACE - 1)); + column += i; + if (column >= maxCol) { + doCRNL(1,1); + return; + } + while (i--) *pt_bitmap++ = ' ' | attribute; + wr_cursor(row * maxCol + column, ioCrtBaseAddr); + return; + } + case '\n': { + doCRNL(0,1); + return; + } + case 7: { /* Bell code must be inserted here */ + return; + } + case '\r' : { + doCRNL(1,0); + return; + } + case BLANK: { + *pt_bitmap = ' ' | attribute; + /* DONT move the cursor... */ + return; + } + default: { + *pt_bitmap = (unsigned char)car | attribute; + advanceCursor(); + return; + } + } +} + +/* trivial state machine to handle escape sequences: + * + * --------------------------------- + * | | + * | | + * KEY: esc V [ DCABHKJ esc | + * STATE: 0 -----> 27 -----> '[' ----------> -1 ----- + * ^\ \ \ \ + * KEY: | \other \ other \ other \ other + * <------------------------------------- + * + * in state '-1', the DCABHKJ cases are handled + * + * (cursor motion and screen clearing) + */ + +#define DONE (-1) + +static int +handleEscape(int oldState, char car) +{ +int rval = 0; +int ro,co; + + switch ( oldState ) { + case DONE: /* means the previous char terminated an ESC sequence... */ + case 0: + if ( 27 == car ) { + rval = 27; /* START of an ESC sequence */ + } + break; + + case 27: + if ( '[' == car ) { + rval = car; /* received ESC '[', so far */ + } else { + /* dump suppressed 'ESC'; outch will append the char */ + videoPutChar(ESC); + } + break; + + case '[': + /* handle 'ESC' '[' sequences here */ + ro = row; co = column; + rval = DONE; /* done */ + + switch (car) { + case 'D': /* left */ + if ( co > 0 ) co--; + break; + case 'C': /* right */ + if ( co < maxCol ) co++; + break; + case 'A': /* up */ + if ( ro > 0 ) ro--; + break; + case 'B': /* down */ + if ( ro < maxRow ) ro++; + break; + case 'H': /* home */ + ro = co = 0; + break; + case 'K': /* clear to end of line */ + while ( column < maxCol - 1 ) + videoPutChar(' '); + videoPutChar(BLANK); + break; + case 'J': /* clear to end of screen */ + while ( ((row < maxRow-1) || (column < maxCol-1)) ) + videoPutChar(' '); + videoPutChar(BLANK); + break; + default: + videoPutChar(ESC); + videoPutChar('['); + /* DONT move the cursor */ + ro = -1; + rval = 0; + break; + } + /* reset cursor */ + if ( ro >= 0) + gotorc(ro,co); + + default: + break; + + } + + return rval; +} + +static void +clear_screen(void) +{ + int i,j; + + for (j = 0; j <= maxRow; j++) { + for (i = 0; i <= maxCol; i++) { + videoPutChar(' '); + } + } + column = 0; + row = 0; +} + +/*-------------------------------------------------------------------------+ +| Function: _IBMPC_outch +| Description: Higher level (console) interface to consPutc. +| Global Variables: None. +| Arguments: c - character to write to console. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +void +_IBMPC_outch(char c) +{ +static int escaped = 0; + + if ( ! (escaped = handleEscape(escaped, c)) ) { + if ( '\n' == c ) + videoPutChar('\r'); + videoPutChar(c); + } +} /* _IBMPC_outch */ + +/*-------------------------------------------------------------------------+ +| Function: _IBMPC_initVideo +| Description: Video system initialization. Hook for any early setup. +| Global Variables: bitMapBaseAddr, ioCrtBaseAddr, maxCol, maxRow, row +| column, attribute, nLines; +| Arguments: None. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +void +_IBMPC_initVideo(void) +{ + unsigned char* pt = (unsigned char*) (VIDEO_MODE_ADDR); + + if (*pt == VGAMODE7) { + bitMapBaseAddr = (unsigned short*) V_MONO; + } + else { + bitMapBaseAddr = (unsigned short*) V_COLOR; + } + ioCrtBaseAddr = *(unsigned short*) DISPLAY_CRT_BASE_IO_ADDR; + maxCol = * (unsigned short*) NB_MAX_COL_ADDR; + maxRow = * (unsigned char*) NB_MAX_ROW_ADDR; + column = 0; + row = 0; + attribute = ((BLACK << 4) | WHITE)<<8; + nLines = 0; + clear_screen(); +#ifdef DEBUG_EARLY_STAGE + printk("bitMapBaseAddr = %X, display controller base IO = %X\n", + (unsigned) bitMapBaseAddr, + (unsigned) ioCrtBaseAddr); + videoPrintf("maxCol = %d, maxRow = %d\n", (unsigned) maxCol, (unsigned) maxRow); +#endif +} /* _IBMPC_initVideo */ + +/* for old DOS compatibility n-curses type of applications */ +void gotoxy( int x, int y ); +int whereX( void ); +int whereY( void ); + +void gotoxy( int x, int y ) +{ + gotorc(y,x); +} + +int whereX( void ) +{ + return row; +} + +int whereY( void ) +{ + return column; +} diff --git a/bsps/i386/pc386/console/pc_keyb.c b/bsps/i386/pc386/console/pc_keyb.c new file mode 100644 index 0000000000..b6f0eb216a --- /dev/null +++ b/bsps/i386/pc386/console/pc_keyb.c @@ -0,0 +1,627 @@ +/* + * linux/drivers/char/pc_keyb.c + * + * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 + * See keyboard.c for the whole history. + * + * Major cleanup by Martin Mares, May 1997 + * + * Combined the keyboard and PS/2 mouse handling into one file, + * because they share the same hardware. + * Johan Myreen <jem@iki.fi> 1998-10-08. + * + * Code fixes to handle mouse ACKs properly. + * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. + * + * Ported to RTEMS by Rosimildo da Silva + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include <bsp.h> +#include <rtems/keyboard.h> +#include "i386kbd.h" + +static unsigned char handle_kbd_event(void); +static void kbd_write_command_w(int data); +static void kbd_write_output_w(int data); + +/* Some configuration switches are present in the include file... */ + +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char pckbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +/* used only by send_data - set by keyboard_interrupt */ +static volatile unsigned char reply_expected = 0; +static volatile unsigned char acknowledge = 0; +static volatile unsigned char resend = 0; + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable. + * The keycodes 1-88,96-111,119 are fairly standard, and + * should probably not be changed - changing might confuse X. + * X also interprets scancode 0x5d (KEY_Begin). + * + * For 1-88 keycode equals scancode. + */ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +#define E1_PAUSE 119 + +/* + * The keycodes below are randomly located in 89-95,112-118,120-127. + * They could be thrown away (and all occurrences below replaced by 0), + * but that would force many users to use the `setkeycodes' utility, where + * they needed not before. It does not matter that there are duplicates, as + * long as no duplication occurs for any single keyboard. + */ +#define SC_LIM 89 + +#define FOCUS_PF1 85 /* actual code! */ +#define FOCUS_PF2 89 +#define FOCUS_PF3 90 +#define FOCUS_PF4 91 +#define FOCUS_PF5 92 +#define FOCUS_PF6 93 +#define FOCUS_PF7 94 +#define FOCUS_PF8 95 +#define FOCUS_PF9 120 +#define FOCUS_PF10 121 +#define FOCUS_PF11 122 +#define FOCUS_PF12 123 + +#define JAP_86 124 +/* tfj@olivia.ping.dk: + * The four keys are located over the numeric keypad, and are + * labelled A1-A4. It's an rc930 keyboard, from + * Regnecentralen/RC International, Now ICL. + * Scancodes: 59, 5a, 5b, 5c. + */ +#define RGN1 124 +#define RGN2 125 +#define RGN3 126 +#define RGN4 127 + +static unsigned char high_keys[128 - SC_LIM] = { + RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ + 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ + FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ + FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ +}; + +/* BTC */ +#define E0_MACRO 112 +/* LK450 */ +#define E0_F13 113 +#define E0_F14 114 +#define E0_HELP 115 +#define E0_DO 116 +#define E0_F17 117 +#define E0_KPMINPLUS 118 +/* + * My OmniKey generates e0 4c for the "OMNI" key and the + * right alt key does nada. [kkoller@nyx10.cs.du.edu] + */ +#define E0_OK 124 +/* + * New microsoft keyboard is rumoured to have + * e0 5b (left window button), e0 5c (right window button), + * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] + * [or: Windows_L, Windows_R, TaskMan] + */ +#define E0_MSLW 125 +#define E0_MSRW 126 +#define E0_MSTM 127 + +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ + E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ + E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +static void mdelay( unsigned long t ) +{ + Wait_X_ms( t ); +} + +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode < SC_LIM || scancode > 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +int pckbd_getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < 128) ? high_keys[scancode - SC_LIM] : + e0_keys[scancode - 128]; +} + +static int do_acknowledge(unsigned char scancode) +{ + if (reply_expected) { + /* Unfortunately, we must recognise these codes only if we know they + * are known to be valid (i.e., after sending a command), because there + * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have + * keys with such codes :( + */ + if (scancode == KBD_REPLY_ACK) { + acknowledge = 1; + reply_expected = 0; + return 0; + } else if (scancode == KBD_REPLY_RESEND) { + resend = 1; + reply_expected = 0; + return 0; + } + /* Should not happen... */ + printk( "keyboard reply expected - got %02x\n", scancode); + } + return 1; +} + +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode = 0; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk("keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + /* + * The keyboard maintains its own internal caps lock and + * num lock statuses. In caps lock mode E0 AA precedes make + * code and E0 2A follows break code. In num lock mode, + * E0 2A precedes make code and E0 AA follows break code. + * We do our own book-keeping, so we will just ignore these. + */ + /* + * For my keyboard there is no caps lock mode, but there are + * both Shift-L and Shift-R modes. The former mode generates + * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. + * So, we should also ignore the latter. - aeb@cwi.nl + */ + if (scancode == 0x2a || scancode == 0x36) + return 0; + + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk( "keyboard: unknown scancode e0 %02x\n", + scancode); +#endif + return 0; + } + } + } else if (scancode >= SC_LIM) { + /* This happens with the FOCUS 9000 keyboard + Its keys PF1..PF12 are reported to generate + 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f + Moreover, unless repeated, they do not generate + key-down events, so we have to zero up_flag below */ + /* Also, Japanese 86/106 keyboards are reported to + generate 0x73 and 0x7d for \ - and \ | respectively. */ + /* Also, some Brazilian keyboard is reported to produce + 0x73 and 0x7e for \ ? and KP-dot, respectively. */ + + *keycode = high_keys[scancode - SC_LIM]; + if (!*keycode) { + if (!raw_mode) { +#ifdef KBD_REPORT_UNKN + printk( "keyboard: unrecognized scancode (%02x)" + " - ignored\n", scancode); +#endif + } + return 0; + } + } else + *keycode = scancode; + return 1; +} + +char pckbd_unexpected_up(unsigned char keycode) +{ + /* unexpected, but this can happen: maybe this was a key release for a + FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ + if (keycode >= SC_LIM || keycode == 85) + return 0; + else + return 0200; +} + +static void kb_wait(void) +{ + unsigned long timeout = KBC_TIMEOUT; + + do { + /* + * "handle_kbd_event()" will handle any incoming events + * while we wait - keypresses or mouse movement. + */ + unsigned char status = handle_kbd_event(); + + if (! (status & KBD_STAT_IBF)) + return; + mdelay(1); + timeout--; + } while (timeout); +#ifdef KBD_REPORT_TIMEOUTS + printk( "Keyboard timed out[1]\n"); +#endif +} + +/* + * This reads the keyboard status port, and does the + * appropriate action. + * + * It requires that we hold the keyboard controller + * spinlock. + */ +static unsigned char handle_kbd_event(void) +{ + unsigned char status = kbd_read_status(); + unsigned int work = 10000; + + while (status & KBD_STAT_OBF) { + unsigned char scancode; + + scancode = kbd_read_input(); + if (status & KBD_STAT_MOUSE_OBF) { +#if 0 + handle_mouse_event(scancode); +#endif + } else { + if (do_acknowledge(scancode)) + handle_scancode(scancode, !(scancode & 0x80)); + mark_bh(KEYBOARD_BH); + } + + status = kbd_read_status(); + + if(!work--) + { + printk( "pc_keyb: controller jammed (0x%02X).\n", status); + break; + } + return status; + } + + /* + * the commands to set the leds for some reason, returns 0x14, 0x16 + * and I am intepreting as an ACK, because the original code from + * Linux was timeing out here... + */ + acknowledge = 1; + reply_expected = 0; + resend = 0; + return status; +} + +void keyboard_interrupt(void *unused) +{ + handle_kbd_event(); +} + +/* + * send_data sends a character to the keyboard and waits + * for an acknowledge, possibly retrying if asked to. Returns + * the success status. + * + * Don't use 'jiffies', so that we don't depend on interrupts + */ +static int send_data(unsigned char data) +{ + int retries = 3; + + do { + unsigned long timeout = KBD_TIMEOUT; + + acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ + resend = 0; + reply_expected = 1; + kbd_write_output_w(data); + for (;;) { + if (acknowledge) + return 1; + if (resend) + break; + mdelay(1); + if (!--timeout) { +#ifdef KBD_REPORT_TIMEOUTS + printk("Keyboard timeout[2]\n"); +#endif + return 0; + } + } + } while (retries-- > 0); +#ifdef KBD_REPORT_TIMEOUTS + printk( "keyboard: Too many NACKs -- noisy kbd cable?\n"); +#endif + return 0; +} + +void pckbd_leds(unsigned char leds) +{ + if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) + send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ +} + +/* + * In case we run on a non-x86 hardware we need to initialize both the + * keyboard controller and the keyboard. On a x86, the BIOS will + * already have initialized them. + * + * Some x86 BIOSes do not correctly initialize the keyboard, so the + * "kbd-reset" command line options can be given to force a reset. + * [Ranger] + */ +#ifdef __i386__ + int kbd_startup_reset = 0; +#else + int kbd_startup_reset = 1; +#endif + +/* for "kbd-reset" cmdline param */ +void kbd_reset_setup(char *str, int *ints) +{ + kbd_startup_reset = 1; +} + +#define KBD_NO_DATA (-1) /* No data */ +#define KBD_BAD_DATA (-2) /* Parity or other error */ + +static int kbd_read_data(void) +{ + int retval = KBD_NO_DATA; + unsigned char status; + + status = kbd_read_status(); + if (status & KBD_STAT_OBF) { + unsigned char data = kbd_read_input(); + + retval = data; + if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) + retval = KBD_BAD_DATA; + } + return retval; +} + +static void kbd_clear_input(void) +{ + int maxread = 100; /* Random number */ + + do { + if (kbd_read_data() == KBD_NO_DATA) + break; + } while (--maxread); +} + +static int kbd_wait_for_input(void) +{ + long timeout = KBD_INIT_TIMEOUT; + + do { + int retval = kbd_read_data(); + if (retval >= 0) + return retval; + mdelay(1); + } while (--timeout); + return -1; +} + +static void kbd_write_command_w(int data) +{ + kb_wait(); + kbd_write_command(data); +} + +static void kbd_write_output_w(int data) +{ + kb_wait(); + kbd_write_output(data); +} + +static char * initialize_kbd(void) +{ + int status; + + /* + * Test the keyboard interface. + * This seems to be the only way to get it going. + * If the test is successful a x55 is placed in the input buffer. + */ + kbd_write_command_w(KBD_CCMD_SELF_TEST); + if (kbd_wait_for_input() != 0x55) + return "Keyboard failed self test"; + + /* + * Perform a keyboard interface test. This causes the controller + * to test the keyboard clock and data lines. The results of the + * test are placed in the input buffer. + */ + kbd_write_command_w(KBD_CCMD_KBD_TEST); + if (kbd_wait_for_input() != 0x00) + return "Keyboard interface failed self test"; + + /* + * Enable the keyboard by allowing the keyboard clock to run. + */ + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); + + /* + * Reset keyboard. If the read times out + * then the assumption is that no keyboard is + * plugged into the machine. + * This defaults the keyboard to scan-code set 2. + * + * Set up to try again if the keyboard asks for RESEND. + */ + do { + kbd_write_output_w(KBD_CMD_RESET); + status = kbd_wait_for_input(); + if (status == KBD_REPLY_ACK) + break; + if (status != KBD_REPLY_RESEND) + return "Keyboard reset failed, no ACK"; + } while (1); + + if (kbd_wait_for_input() != KBD_REPLY_POR) + return "Keyboard reset failed, no POR"; + + /* + * Set keyboard controller mode. During this, the keyboard should be + * in the disabled state. + * + * Set up to try again if the keyboard asks for RESEND. + */ + do { + kbd_write_output_w(KBD_CMD_DISABLE); + status = kbd_wait_for_input(); + if (status == KBD_REPLY_ACK) + break; + if (status != KBD_REPLY_RESEND) + return "Disable keyboard: no ACK"; + } while (1); + + kbd_write_command_w(KBD_CCMD_WRITE_MODE); + kbd_write_output_w(KBD_MODE_KBD_INT + | KBD_MODE_SYS + | KBD_MODE_DISABLE_MOUSE + | KBD_MODE_KCC); + + /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ + kbd_write_command_w(KBD_CCMD_READ_MODE); + if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { + /* + * If the controller does not support conversion, + * Set the keyboard to scan-code set 1. + */ + kbd_write_output_w(0xF0); + kbd_wait_for_input(); + kbd_write_output_w(0x01); + kbd_wait_for_input(); + } + + kbd_write_output_w(KBD_CMD_ENABLE); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Enable keyboard: no ACK"; + /* + * Finally, set the typematic rate to maximum. + */ + kbd_write_output_w(KBD_CMD_SET_RATE); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Set rate: no ACK"; + kbd_write_output_w(0x00); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Set rate: no ACK"; + return NULL; +} + +void pckbd_init_hw(void) +{ + /* kbd_request_region(); */ + + /* Flush any pending input. */ + kbd_clear_input(); + + if (kbd_startup_reset) { + char *msg = initialize_kbd(); + if (msg) + printk( "initialize_kbd: %s\n", msg); + } + +#if defined CONFIG_PSMOUSE + psaux_init(); +#endif + + /* Ok, finally allocate the IRQ, and off we go.. */ +#if 0 + kbd_request_irq( keyboard_interrupt ); +#endif + +} diff --git a/bsps/i386/pc386/console/printk_support.c b/bsps/i386/pc386/console/printk_support.c new file mode 100644 index 0000000000..d7bc329868 --- /dev/null +++ b/bsps/i386/pc386/console/printk_support.c @@ -0,0 +1,84 @@ +/* + * @file + * + * @ingroup Console + * + * @brief printk support routines + * + * This file contains the required printk support. + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems.h> +#include <rtems/bspIo.h> +#if BSP_ENABLE_VGA + #include <rtems/keyboard.h> +#endif +#include <bsp.h> +#include <libchip/serial.h> +#include <libchip/ns16550.h> +#include "../../shared/dev/serial/legacy-console.h" + +rtems_device_minor_number BSPPrintkPort = 0; + +void BSP_outch(char ch); +int BSP_inch(void); + +void BSP_outch(char ch) +{ + #if BSP_ENABLE_VGA + bool isVga = BSPPrintkPort == BSP_CONSOLE_VGA; + #else + bool isVga = false; + #endif + + if ( !isVga ) { + console_tbl *port = Console_Port_Tbl[BSPPrintkPort]; + if (port->pDeviceFns && port->pDeviceFns->deviceWritePolled) { + port->pDeviceFns->deviceWritePolled( BSPPrintkPort, ch ); + } + return; + } + + #if BSP_ENABLE_VGA + _IBMPC_outch( ch ); + #endif +} + +int BSP_inch(void) +{ + #if BSP_ENABLE_VGA + bool isVga = BSPPrintkPort == BSP_CONSOLE_VGA; + #else + bool isVga = false; + #endif + + int result = -1; + + if ( !isVga ) { + console_tbl *port = Console_Port_Tbl[BSPPrintkPort]; + if (port->pDeviceFns && port->pDeviceFns->deviceRead) { + do { + result = port->pDeviceFns->deviceRead( BSPPrintkPort ); + } while (result == -1); + return result; + } + } + + #if BSP_ENABLE_VGA + result = BSP_wait_polled_input(); + #endif + + return result; +} + +BSP_output_char_function_type BSP_output_char = BSP_outch; +BSP_polling_getchar_function_type BSP_poll_char = BSP_inch; diff --git a/bsps/i386/pc386/console/ps2_mouse.c b/bsps/i386/pc386/console/ps2_mouse.c new file mode 100644 index 0000000000..6a3f8551b4 --- /dev/null +++ b/bsps/i386/pc386/console/ps2_mouse.c @@ -0,0 +1,562 @@ +/* + * linux/drivers/char/pc_keyb.c + * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 + * See keyboard.c for the whole history. + * Major cleanup by Martin Mares, May 1997 + * Combined the keyboard and PS/2 mouse handling into one file, + * because they share the same hardware. + * Johan Myreen <jem@iki.fi> 1998-10-08. + * Code fixes to handle mouse ACKs properly. + * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. + * + * RTEMS port: by Rosimildo da Silva. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <assert.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/libio.h> +#include <termios.h> +#include <i386_io.h> +#include <rtems/mw_uid.h> +#include <rtems/mouse_parser.h> + +#define INITIALIZE_MOUSE +/* Some configuration switches are present in the include file... */ +#include <rtems/ps2_drv.h> +#include "ps2_mouse.h" + +static void kbd_write_command_w(int data); +#if 0 +static void kbd_write_output_w(int data); +#endif + +static unsigned char handle_kbd_event(void); +static void ps2_set_driver_handler(int port, mouse_parser_enqueue_handler handler); + +/* used only by send_data - set by keyboard_interrupt */ +static volatile unsigned char reply_expected = 0; +static volatile unsigned char acknowledge = 0; +static volatile unsigned char resend = 0; + +/* + * PS/2 Auxiliary Device + */ +static int psaux_init(void); + +static struct aux_queue *queue; /* Mouse data buffer. */ +static int aux_count = 0; +/* used when we send commands to the mouse that expect an ACK. */ +static unsigned char mouse_reply_expected = 0; + +#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) +#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) +#define MAX_RETRIES 60 /* some aux operations take long time*/ + +static void ps2_mouse_interrupt(void *); +static mouse_parser_enqueue_handler driver_input_handler_ps2 = NULL; + +/* + * This routine sets the handler to handle the characters received + * from the serial port. + */ +static void ps2_set_driver_handler( + int port, + mouse_parser_enqueue_handler handler +) +{ + driver_input_handler_ps2 = handler; +} + +static void mdelay( unsigned long t ) +{ + Wait_X_ms( t ); +} + +static void* termios_ttyp_paux = NULL; + +/* + * Wait for keyboard controller input buffer to drain. + * + * Don't use 'jiffies' so that we don't depend on + * interrupts.. + * + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be written only when + * the input-buffer-full bit and output-buffer-full bit in the + * Controller Status register are set 0." + */ + +static void kb_wait(void) +{ + unsigned long timeout = KBC_TIMEOUT; + + do { + /* + * "handle_kbd_event()" will handle any incoming events + * while we wait - keypresses or mouse movement. + */ + unsigned char status = handle_kbd_event(); + + if (! (status & KBD_STAT_IBF)) + return; + + mdelay(1); + timeout--; + } while (timeout); + + #ifdef KBD_REPORT_TIMEOUTS + printk( "Keyboard timed out[1]\n"); + #endif +} + +static int do_acknowledge(unsigned char scancode) +{ + if (reply_expected) { + + /* Unfortunately, we must recognise these codes only if we know they + * are known to be valid (i.e., after sending a command), because there + * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have + * keys with such codes :( + */ + if (scancode == KBD_REPLY_ACK) { + acknowledge = 1; + reply_expected = 0; + return 0; + } else if (scancode == KBD_REPLY_RESEND) { + resend = 1; + reply_expected = 0; + return 0; + } + + /* Should not happen... */ + #if 0 + printk( "keyboard reply expected - got %02x\n", scancode); + #endif + } + return 1; +} + +static inline void handle_mouse_event(unsigned char scancode) +{ + if (mouse_reply_expected) { + if (scancode == AUX_ACK) { + mouse_reply_expected--; + return; + } + mouse_reply_expected = 0; + } + + if (aux_count) { + int head = queue->head; + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + } + + /* if the input queue is active, add to it */ + if( driver_input_handler_ps2 ) { + driver_input_handler_ps2( &scancode, 1 ); + } else { + /* post this byte to termios */ + rtems_termios_enqueue_raw_characters( termios_ttyp_paux, (char *)&scancode, 1 ); + } + } +} + +/* + * This reads the keyboard status port, and does the + * appropriate action. + * + * It requires that we hold the keyboard controller + * spinlock. + */ +static unsigned char handle_kbd_event(void) +{ + unsigned char status = kbd_read_status(); + unsigned int work = 10000; + + while (status & KBD_STAT_OBF) { + unsigned char scancode; + scancode = kbd_read_input(); + if (status & KBD_STAT_MOUSE_OBF) { + handle_mouse_event(scancode); + } else { + do_acknowledge(scancode); + printk("pc_keyb: %X ", scancode ); + } + status = kbd_read_status(); + if(!work--) { + printk("pc_keyb: controller jammed (0x%02X).\n", status); + break; + } + } + return status; +} + +static void ps2_mouse_interrupt(void * unused) +{ + handle_kbd_event(); +} + +static void kbd_write_command_w(int data) +{ + kb_wait(); + kbd_write_command(data); +} + +static void kbd_write_cmd(int cmd) +{ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MODE); + kb_wait(); + kbd_write_output(cmd); +} + +/* + * Check if this is a dual port controller. + */ +static int detect_auxiliary_port(void) +{ + int loops = 10; + int retval = 0; + + /* Put the value 0x5A in the output buffer using the "Write + * Auxiliary Device Output Buffer" command (0xD3). Poll the + * Status Register for a while to see if the value really + * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF + * bit is also set to 1 in the Status Register, we assume this + * controller has an Auxiliary Port (a.k.a. Mouse Port). + */ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); + + kb_wait(); + kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ + + do { + unsigned char status = kbd_read_status(); + if (status & KBD_STAT_OBF) { + kbd_read_input(); + if (status & KBD_STAT_MOUSE_OBF) { + printk( "Detected PS/2 Mouse Port.\n"); + retval = 1; + } + break; + } + mdelay(1); + } while (--loops); + return retval; +} + +/* + * Send a byte to the mouse. + */ +static void aux_write_dev(int val) +{ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); + kb_wait(); + kbd_write_output(val); +} + +/* + * Send a byte to the mouse & handle returned ack + */ +static void aux_write_ack(int val) +{ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); + kb_wait(); + kbd_write_output(val); + /* we expect an ACK in response. */ + mouse_reply_expected++; + kb_wait(); +} + +static unsigned char get_from_queue(void) +{ + unsigned char result; + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + return result; +} + +static int queue_empty(void) +{ + return queue->head == queue->tail; +} + +/* + * Random magic cookie for the aux device + */ +#define AUX_DEV ((void *)queue) + +static int release_aux(void) +{ + rtems_status_code status; + if (--aux_count) + return 0; + kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + status = rtems_interrupt_handler_remove( + AUX_IRQ, + ps2_mouse_interrupt, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + return 0; +} + +/* + * Install interrupt handler. + * Enable auxiliary device. + */ + +static int open_aux(void) +{ + rtems_status_code status; + + if (aux_count++) { + return 0; + } + queue->head = queue->tail = 0; /* Flush input queue */ + + status = rtems_interrupt_handler_install( + AUX_IRQ, + "ps2_mouse", + RTEMS_INTERRUPT_UNIQUE, + ps2_mouse_interrupt, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on + controller. */ + aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ + return 0; +} + +/* + * Put bytes from input queue to buffer. + */ +size_t read_aux(char * buffer, size_t count ) +{ + size_t i = count; + unsigned char c; + + if (queue_empty()) { + return 0; + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + *buffer++ = c; + i--; + } + return count-i; +} + +/* + * Write to the aux device. + */ +static int write_aux( int minor, const char * buffer, int count ) +{ + int retval = 0; + + if (count) { + int written = 0; + if (count > 32) + count = 32; /* Limit to 32 bytes. */ + do { + char c; + c = *buffer++; + aux_write_dev(c); + written++; + } while (--count); + retval = -EIO; + if (written) { + retval = written; + } + } + return retval; +} + +static int psaux_init( void ) +{ + if( !detect_auxiliary_port() ) { + printk( "PS/2 - mouse not found.\n" ); + return -EIO; + } + queue = (struct aux_queue *)malloc( sizeof(*queue) ); + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + queue->proc_list = NULL; + + #ifdef INITIALIZE_MOUSE + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ + aux_write_ack(AUX_SET_SAMPLE); + aux_write_ack(100); /* 100 samples/sec */ + aux_write_ack(AUX_SET_RES); + aux_write_ack(3); /* 8 counts per mm */ + aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ + #endif /* INITIALIZE_MOUSE */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ + kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ + return 0; +} + +/* + * paux device driver INITIALIZE entry point. + */ +rtems_device_driver paux_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; + + /* + * Set up TERMIOS + */ + rtems_termios_initialize(); + + printk( "PS/2 mouse probe.\n" ); + if( psaux_init() < 0 ) { + printk("Error detecting PS/2 mouse --\n"); + /* we might want to finish the application here !!! */ + } + open_aux(); + + /* + * Register the device + */ + status = rtems_io_register_name ("/dev/mouse", major, 0); + if (status != RTEMS_SUCCESSFUL) { + printk("Error registering paux device!\n"); + rtems_fatal_error_occurred (status); + } + return RTEMS_SUCCESSFUL; +} /* tty_initialize */ + +static int paux_last_close(int major, int minor, void *arg) +{ + release_aux(); + return 0; +} + +/* + * Write to the aux device. This routine is invoked by the + * termios framework whenever the "ECHO" feature is on. + * It does nothing write now. + */ +static ssize_t write_aux_echo( int minor, const char * buffer, size_t count ) +{ + return 0; +} + +/* + * paux device driver OPEN entry point + */ +rtems_device_driver paux_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; + static rtems_termios_callbacks cb = + { + NULL, /* firstOpen */ + paux_last_close, /* lastClose */ + NULL, /* poll read */ + write_aux_echo, /* write */ + NULL, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ + }; + + status = rtems_termios_open (major, minor, arg, &cb ); + termios_ttyp_paux = ( (rtems_libio_open_close_args_t *)arg)->iop->data1; + return status; +} + +/* + * paux device driver CLOSE entry point + */ +rtems_device_driver paux_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + return (rtems_termios_close (arg)); +} + +/* + * paux device driver READ entry point. + * Read characters from the PS/2 mouse. + */ +rtems_device_driver paux_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + return rtems_termios_read (arg); +} /* tty_read */ + +/* + * paux device driver WRITE entry point. + * Write characters to the PS/2 mouse. + */ +rtems_device_driver paux_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + char *buffer = rw_args->buffer; + int maximum = rw_args->count; + rw_args->bytes_moved = write_aux( minor, buffer, maximum ); + return RTEMS_SUCCESSFUL; +} /* tty_write */ + +/* + * Handle ioctl request. + */ +rtems_device_driver paux_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + switch( args->command ) { + default: + return rtems_termios_ioctl (arg); + break; + + case MW_UID_REGISTER_DEVICE: + printk( "PS2 Mouse: registering\n" ); + mouse_parser_initialize( "ps2" ); + ps2_set_driver_handler( minor, mouse_parser_enqueue ); + break; + + case MW_UID_UNREGISTER_DEVICE: +/* + unregister_mou_msg_queue( -1 ); +*/ + ps2_set_driver_handler( minor, NULL ); + break; + } + args->ioctl_return = 0; + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/i386/pc386/console/ps2_mouse.h b/bsps/i386/pc386/console/ps2_mouse.h new file mode 100644 index 0000000000..dd61e8a367 --- /dev/null +++ b/bsps/i386/pc386/console/ps2_mouse.h @@ -0,0 +1,151 @@ +/** + * @file + * + * @ingroup i386_pc386 + * + * @brief Keyboard and mouse definitions. + */ + +/* + * include/linux/pc_keyb.h + * PC Keyboard And Keyboard Controller + * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + * + * RTEMS port: by Rosimildo da Silva. + * + * This module was ported from Linux. + * + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers on normal PCs. + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define AUX_BUF_SIZE 512 /* This might be better divisible by + three to make overruns stay in sync + but then the read function would need + a lock etc - ick */ + +struct aux_queue { + unsigned long head; + unsigned long tail; + struct wait_queue *proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) + +/* + * Machine specific bits for the PS/2 driver + */ + +#define AUX_IRQ 12 diff --git a/bsps/i386/pc386/console/rtd316.c b/bsps/i386/pc386/console/rtd316.c new file mode 100644 index 0000000000..c8f3c3a6ef --- /dev/null +++ b/bsps/i386/pc386/console/rtd316.c @@ -0,0 +1,109 @@ +/** + * @file + * + * @brief Driver for RTD316 ISA SCC Board + * + * The RTD316 has a single Z85C30. + */ + +/* + * COPYRIGHT (c) 1989-2014. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> + +#include <rtems/termiostypes.h> +#include <libchip/serial.h> +#include <libchip/z85c30.h> +#include <rtems/bspIo.h> +#include <bsp/rtd316.h> +#include <rtems/score/i386.h> +#include "../../shared/dev/serial/legacy-console.h" + +#define RTD_CLOCK_RATE (460800 * 32) + +uint8_t rtd316_com_get_register(uint32_t addr, uint8_t reg) +{ + register uint8_t val = 0; + + outport_byte( addr, reg ); + /* It appears the no delay is needed between the accesses. */ + inport_byte( addr, val ); + + return val; +} + +void rtd316_com_set_register(uint32_t addr,uint8_t reg, uint8_t val) +{ + outport_byte( addr, reg ); + /* It appears the no delay is needed between the accesses. */ + outport_byte( addr, val ); +} + +rtems_device_driver rtd316_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor_arg, + void *arg +) +{ + int p; + console_tbl *ports; + console_tbl *port_p; + + /* + * Now allocate array of device structures and fill them in + */ + ports = calloc( 2, sizeof( console_tbl ) ); + port_p = ports; + + for ( p=0 ; p<2 ; p++ ) { + char name[32]; + sprintf( name, "/dev/rtd316_1_%d", p ); + printk("Found %s\n", name ); + port_p->sDeviceName = strdup( name ); + port_p->deviceType = SERIAL_Z85C30; + #if 0 + port_p->pDeviceFns = &z85c30_fns_polled; + #else + port_p->pDeviceFns = &z85c30_fns; + #endif + + port_p->deviceProbe = NULL; + port_p->pDeviceFlow = NULL; + port_p->ulMargin = 16; + port_p->ulHysteresis = 8; + port_p->pDeviceParams = (void *) 9600; + port_p->getRegister = rtd316_com_get_register; + port_p->setRegister = rtd316_com_set_register; + port_p->getData = NULL; + port_p->setData = NULL; + port_p->ulClock = RTD_CLOCK_RATE; + port_p->ulIntVector = 9; + + if ( p==0 ) { + port_p->ulDataPort = 0; + port_p->ulCtrlPort1 = 0x340; + port_p->ulCtrlPort2 = 0x341; + } else { + port_p->ulDataPort = 1; + port_p->ulCtrlPort1 = 0x342; + port_p->ulCtrlPort2 = 0x343; + } + port_p++; + } /* end ports */ + + /* + * Register the devices + */ + console_register_devices( ports, 2 ); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/i386/pc386/console/serial_mouse_config.c b/bsps/i386/pc386/console/serial_mouse_config.c new file mode 100644 index 0000000000..a8a0313954 --- /dev/null +++ b/bsps/i386/pc386/console/serial_mouse_config.c @@ -0,0 +1,48 @@ +/* + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <bsp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <libchip/serial.h> +#include "../../shared/dev/serial/legacy-console.h" + +/* select which serial port the mouse is connected to */ +#if defined(SERIAL_MOUSE_COM2) + #define MOUSE_DEVICE "/dev/com2" +#else + #define MOUSE_DEVICE "/dev/com1" +#endif + +static const char *SerialMouseDevice = MOUSE_DEVICE; + +bool bsp_get_serial_mouse_device( + const char **name, + const char **type +) +{ + const char *consname; + + *name = SerialMouseDevice; + *type = "ms"; + + /* Check if this port is not been used as console */ + consname = Console_Port_Tbl[ Console_Port_Minor ]->sDeviceName; + if ( !strcmp(MOUSE_DEVICE, consname) ) { + printk( "SERIAL MOUSE: port selected as console.(%s)\n", *name ); + rtems_fatal_error_occurred( -1 ); + } + + printk("Mouse Device: %s\n", *name ); + return name; +} diff --git a/bsps/i386/pc386/console/uart_bus_pci.c b/bsps/i386/pc386/console/uart_bus_pci.c new file mode 100644 index 0000000000..2ad8323f05 --- /dev/null +++ b/bsps/i386/pc386/console/uart_bus_pci.c @@ -0,0 +1,477 @@ +/* + * This file was brought over from FreeBSD for the PCI device table. + * The code for using the table is RTEMS specific is also under the + * FreeBSD license. + * + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + */ + +/*- + * Copyright (c) 2006 Marcel Moolenaar + * Copyright (c) 2001 M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __rtems__ +#include <stddef.h> +#include <stdint.h> +#include <i386_io.h> +#else +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <dev/pci/pcivar.h> + +#include <dev/uart/uart.h> +#include <dev/uart/uart_bus.h> + +#endif + +#define DEFAULT_RCLK 1843200 + +#ifndef __rtems__ +static int uart_pci_probe(device_t dev); + +static device_method_t uart_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_pci_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + DEVMETHOD(device_resume, uart_bus_resume), + DEVMETHOD_END +}; + +static driver_t uart_pci_driver = { + uart_driver_name, + uart_pci_methods, + sizeof(struct uart_softc), +}; +#endif + +struct pci_id { + uint16_t vendor; + uint16_t device; + uint16_t subven; + uint16_t subdev; + const char *desc; + int rid; + int rclk; + int regshft; +}; + +static const struct pci_id pci_ns8250_ids[] = { +{ 0x1028, 0x0008, 0xffff, 0, "Dell Remote Access Card III", 0x14, + 128 * DEFAULT_RCLK }, +{ 0x1028, 0x0012, 0xffff, 0, "Dell RAC 4 Daughter Card Virtual UART", 0x14, + 128 * DEFAULT_RCLK }, +{ 0x1033, 0x0074, 0x1033, 0x8014, "NEC RCV56ACF 56k Voice Modem", 0x10 }, +{ 0x1033, 0x007d, 0x1033, 0x8012, "NEC RS232C", 0x10 }, +{ 0x103c, 0x1048, 0x103c, 0x1227, "HP Diva Serial [GSP] UART - Powerbar SP2", + 0x10 }, +{ 0x103c, 0x1048, 0x103c, 0x1301, "HP Diva RMP3", 0x14 }, +{ 0x103c, 0x1290, 0xffff, 0, "HP Auxiliary Diva Serial Port", 0x18 }, +{ 0x103c, 0x3301, 0xffff, 0, "HP iLO serial port", 0x10 }, +{ 0x11c1, 0x0480, 0xffff, 0, "Agere Systems Venus Modem (V90, 56KFlex)", 0x14 }, +{ 0x115d, 0x0103, 0xffff, 0, "Xircom Cardbus Ethernet + 56k Modem", 0x10 }, +{ 0x1282, 0x6585, 0xffff, 0, "Davicom 56PDV PCI Modem", 0x10 }, +{ 0x12b9, 0x1008, 0xffff, 0, "3Com 56K FaxModem Model 5610", 0x10 }, +{ 0x131f, 0x1000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x18 }, +{ 0x131f, 0x1001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x18 }, +{ 0x131f, 0x1002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x18 }, +{ 0x131f, 0x2000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x10 }, +{ 0x131f, 0x2001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x10 }, +{ 0x131f, 0x2002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x10 }, +{ 0x135c, 0x0190, 0xffff, 0, "Quatech SSCLP-100", 0x18 }, +{ 0x135c, 0x01c0, 0xffff, 0, "Quatech SSCLP-200/300", 0x18 }, +{ 0x135e, 0x7101, 0xffff, 0, "Sealevel Systems Single Port RS-232/422/485/530", + 0x18 }, +{ 0x1407, 0x0110, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port A", 0x10 }, +{ 0x1407, 0x0111, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port B", 0x10 }, +{ 0x1407, 0x0510, 0xffff, 0, "Lava SP Serial 550 PCI", 0x10 }, +{ 0x1409, 0x7168, 0x1409, 0x4025, "Timedia Technology Serial Port", 0x10, + 8 * DEFAULT_RCLK }, +{ 0x1409, 0x7168, 0x1409, 0x4027, "Timedia Technology Serial Port", 0x10, + 8 * DEFAULT_RCLK }, +{ 0x1409, 0x7168, 0x1409, 0x4028, "Timedia Technology Serial Port", 0x10, + 8 * DEFAULT_RCLK }, +{ 0x1409, 0x7168, 0x1409, 0x5025, "Timedia Technology Serial Port", 0x10, + 8 * DEFAULT_RCLK }, +{ 0x1409, 0x7168, 0x1409, 0x5027, "Timedia Technology Serial Port", 0x10, + 8 * DEFAULT_RCLK }, +{ 0x1415, 0x950b, 0xffff, 0, "Oxford Semiconductor OXCB950 Cardbus 16950 UART", + 0x10, 16384000 }, +{ 0x1415, 0xc120, 0xffff, 0, "Oxford Semiconductor OXPCIe952 PCIe 16950 UART", + 0x10 }, +{ 0x14e4, 0x4344, 0xffff, 0, "Sony Ericsson GC89 PC Card", 0x10}, +{ 0x151f, 0x0000, 0xffff, 0, "TOPIC Semiconductor TP560 56k modem", 0x10 }, +{ 0x1fd4, 0x1999, 0x1fd4, 0x0001, "Sunix SER5xxxx Serial Port", 0x10, + 8 * DEFAULT_RCLK }, +{ 0x8086, 0x0f0a, 0xffff, 0, "Intel ValleyView LPIO1 HSUART#1", 0x10, + 24 * DEFAULT_RCLK, 2 }, +{ 0x8086, 0x0f0c, 0xffff, 0, "Intel ValleyView LPIO1 HSUART#2", 0x10, + 24 * DEFAULT_RCLK, 2 }, +{ 0x8086, 0x1c3d, 0xffff, 0, "Intel AMT - KT Controller", 0x10 }, +{ 0x8086, 0x1d3d, 0xffff, 0, "Intel C600/X79 Series Chipset KT Controller", 0x10 }, +{ 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 }, +{ 0x8086, 0x2a47, 0xffff, 0, "Mobile 4 Series Chipset KT Controller", 0x10 }, +{ 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 }, +{ 0x8086, 0x3b67, 0xffff, 0, "5 Series/3400 Series Chipset KT Controller", + 0x10 }, +{ 0x8086, 0x8811, 0xffff, 0, "Intel EG20T Serial Port 0", 0x10 }, +{ 0x8086, 0x8812, 0xffff, 0, "Intel EG20T Serial Port 1", 0x10 }, +{ 0x8086, 0x8813, 0xffff, 0, "Intel EG20T Serial Port 2", 0x10 }, +{ 0x8086, 0x8814, 0xffff, 0, "Intel EG20T Serial Port 3", 0x10 }, +{ 0x8086, 0x8c3d, 0xffff, 0, "Intel Lynx Point KT Controller", 0x10 }, +{ 0x8086, 0x8cbd, 0xffff, 0, "Intel Wildcat Point KT Controller", 0x10 }, +{ 0x8086, 0x9c3d, 0xffff, 0, "Intel Lynx Point-LP HECI KT", 0x10 }, +{ 0x9710, 0x9820, 0x1000, 1, "NetMos NM9820 Serial Port", 0x10 }, +{ 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 Serial Port", 0x10 }, +{ 0x9710, 0x9865, 0xa000, 0x1000, "NetMos NM9865 Serial Port", 0x10 }, +{ 0x9710, 0x9900, 0xa000, 0x1000, + "MosChip MCS9900 PCIe to Peripheral Controller", 0x10 }, +{ 0x9710, 0x9901, 0xa000, 0x1000, + "MosChip MCS9901 PCIe to Peripheral Controller", 0x10 }, +{ 0x9710, 0x9904, 0xa000, 0x1000, + "MosChip MCS9904 PCIe to Peripheral Controller", 0x10 }, +{ 0x9710, 0x9922, 0xa000, 0x1000, + "MosChip MCS9922 PCIe to Peripheral Controller", 0x10 }, +{ 0xdeaf, 0x9051, 0xffff, 0, "Middle Digital PC Weasel Serial Port", 0x10 }, +{ 0xffff, 0, 0xffff, 0, NULL, 0, 0} +}; + +#ifndef __rtems__ +const static struct pci_id * +uart_pci_match(device_t dev, const struct pci_id *id) +{ + uint16_t device, subdev, subven, vendor; + + vendor = pci_get_vendor(dev); + device = pci_get_device(dev); + while (id->vendor != 0xffff && + (id->vendor != vendor || id->device != device)) + id++; + if (id->vendor == 0xffff) + return (NULL); + if (id->subven == 0xffff) + return (id); + subven = pci_get_subvendor(dev); + subdev = pci_get_subdevice(dev); + while (id->vendor == vendor && id->device == device && + (id->subven != subven || id->subdev != subdev)) + id++; + return ((id->vendor == vendor && id->device == device) ? id : NULL); +} + +static int +uart_pci_probe(device_t dev) +{ + struct uart_softc *sc; + const struct pci_id *id; + int result; + + sc = device_get_softc(dev); + + id = uart_pci_match(dev, pci_ns8250_ids); + if (id != NULL) { + sc->sc_class = &uart_ns8250_class; + goto match; + } + /* Add checks for non-ns8250 IDs here. */ + return (ENXIO); + + match: + result = uart_bus_probe(dev, id->regshft, id->rclk, id->rid, 0); + /* Bail out on error. */ + if (result > 0) + return (result); + /* Set/override the device description. */ + if (id->desc) + device_set_desc(dev, id->desc); + return (result); +} + +DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, NULL, NULL); +#endif + +#ifdef __rtems__ + +#include <bsp.h> +#include <bsp/bspimpl.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <libchip/serial.h> +#include <libchip/ns16550.h> +#include <rtems/bspIo.h> +#include <rtems/pci.h> +#include "../../shared/dev/serial/legacy-console.h" + +#define MAX_BOARDS 4 + +/* + * Information saved from PCI scan + */ +typedef struct { + bool found; + const char* desc; + uint32_t base; + uint8_t irq; + uint8_t bus; + uint8_t slot; + int ports; + uint32_t clock; +} port_instance_conf_t; + +/* + * Memory Mapped Register Access Routines + */ + +#define UART_PCI_IO (0) + +static uint8_t pci_ns16550_mem_get_register(uint32_t addr, uint8_t i) +{ + uint8_t val = 0; + volatile uint32_t *reg = (volatile uint32_t *)(addr + (i*4)); + val = *reg; + if (UART_PCI_IO) + printk( "RD(%p -> 0x%02x) ", reg, val ); + return val; +} + +static void pci_ns16550_mem_set_register(uint32_t addr, uint8_t i, uint8_t val) +{ + volatile uint32_t *reg = (volatile uint32_t *)(addr + (i*4)); + if (UART_PCI_IO) + printk( "WR(%p <- 0x%02x) ", reg, val ); + *reg = val; +} + +/* + * IO Register Access Routines + */ +static uint8_t pci_ns16550_io_get_register(uint32_t addr, uint8_t i) +{ + uint8_t val = rtems_inb(addr + i); + if (UART_PCI_IO) + printk( "RD(%p -> 0x%02x) ", (void*) addr + i, val ); + return val; +} + +static void pci_ns16550_io_set_register(uint32_t addr, uint8_t i, uint8_t val) +{ + if (UART_PCI_IO) + printk( "WR(%p <- 0x%02x) ", (void*) addr + i, val ); + rtems_outb(addr + i, val); +} + +void pci_uart_probe(void) +{ + port_instance_conf_t conf[MAX_BOARDS]; + int boards = 0; + int b = 0; + console_tbl *ports; + console_tbl *port_p; + int bus; + int dev; + int fun; + int status; + int instance; + int i; + int total_ports = 0; + + for ( b=0 ; b<MAX_BOARDS ; b++ ) { + conf[b].found = false; + } + + /* + * Scan for Serial port boards + */ + for ( instance=0 ; instance < MAX_BOARDS ; instance++ ) { + + for ( i=0 ; pci_ns8250_ids[i].vendor != 0xffff ; i++ ) { + if ( pci_ns8250_ids[i].vendor == 0xffff ) { + break; + } +/* + printk("Looking for 0x%04x:0x%04x\n", + pci_ns8250_ids[i].vendor, + pci_ns8250_ids[i].device); +*/ + status = pci_find_device( + pci_ns8250_ids[i].vendor, + pci_ns8250_ids[i].device, + instance, + &bus, + &dev, + &fun + ); + if ( status == PCIB_ERR_SUCCESS ) { + uint8_t irq; + uint32_t base; + bool io; + + pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0, &base ); + + /* + * Reject memory mapped 64-bit boards. We need 2 BAR registers and the + * driver's base field is only 32-bits any way. + */ + io = (base & 1) == 1; + if (io || (!io && (((base >> 1) & 3) != 2))) { + boards++; + conf[instance].found = true; + conf[instance].desc = pci_ns8250_ids[i].desc; + conf[instance].clock = pci_ns8250_ids[i].rclk; + conf[instance].ports = 1; + total_ports += conf[instance].ports; + + pci_read_config_byte( bus, dev, fun, PCI_INTERRUPT_LINE, &irq ); + + conf[instance].irq = irq; + conf[instance].base = base; + } + } + } + } + + /* + * Now allocate array of device structures and fill them in + */ + if (boards) { + int device_instance; + + ports = calloc( total_ports, sizeof( console_tbl ) ); + if (ports != NULL) { + port_p = ports; + device_instance = 1; + for (b = 0; b < MAX_BOARDS; b++) { + uint32_t base = 0; + bool io; + const char* locatable = ""; + const char* prefectable = locatable; + char name[32]; + if ( conf[b].found == false ) + continue; + sprintf( name, "/dev/pcicom%d", device_instance++ ); + port_p->sDeviceName = strdup( name ); + port_p->deviceType = SERIAL_NS16550; + if ( conf[b].irq <= 15 ) { + port_p->pDeviceFns = &ns16550_fns; + } else { + printk( + "%s IRQ=%d >= 16 requires APIC support, using polling\n", + name, + conf[b].irq + ); + port_p->pDeviceFns = &ns16550_fns_polled; + } + + /* + * PCI BAR (http://wiki.osdev.org/PCI#Base_Address_Registers): + * + * Bit 0: 0 = memory, 1 = IO + * + * Memory: + * Bit 2-1 : 0 = any 32bit address, + * 1 = < 1M + * 2 = any 64bit address + * Bit 3 : 0 = no, 1 = yes + * Bit 31-4 : base address (16-byte aligned) + * + * IO: + * Bit 1 : reserved + * Bit 31-2 : base address (4-byte aligned) + */ + + io = (conf[b].base & 1) == 1; + + if (io) { + base = conf[b].base & 0xfffffffc; + } else { + int loc = (conf[b].base >> 1) & 3; + if (loc == 0) { + base = conf[b].base & 0xfffffff0; + locatable = ",A32"; + } else if (loc == 1) { + base = conf[b].base & 0x0000fff0; + locatable = ",A16"; + } + prefectable = (conf[b].base & (1 << 3)) == 0 ? ",no-prefech" : ",prefetch"; + } + + port_p->deviceProbe = NULL; + port_p->pDeviceFlow = NULL; + port_p->ulMargin = 16; + port_p->ulHysteresis = 8; + port_p->pDeviceParams = (void *) 9600; + port_p->ulCtrlPort1 = base; + port_p->ulCtrlPort2 = 0; /* NA */ + port_p->ulDataPort = 0; /* NA */ + if (io) { + port_p->getRegister = pci_ns16550_io_get_register; + port_p->setRegister = pci_ns16550_io_set_register; + } else { + port_p->getRegister = pci_ns16550_mem_get_register; + port_p->setRegister = pci_ns16550_mem_set_register; + } + port_p->getData = NULL; /* NA */ + port_p->setData = NULL; /* NA */ + port_p->ulClock = conf[b].clock; + port_p->ulIntVector = conf[b].irq; + + + printk( + "%s:%d:%s,%s:0x%lx%s%s,irq:%d,clk:%lu\n", /* */ + name, b, conf[b].desc, + io ? "io" : "mem", base, locatable, prefectable, + conf[b].irq, conf[b].clock + ); + + + port_p++; + } /* end boards */ + + /* + * Register the devices + */ + console_register_devices( ports, total_ports ); + + /* + * Do not free the ports memory, the console hold this memory for-ever. + */ + } + } +} +#endif diff --git a/bsps/i386/pc386/console/vgacons.c b/bsps/i386/pc386/console/vgacons.c new file mode 100644 index 0000000000..2886496e51 --- /dev/null +++ b/bsps/i386/pc386/console/vgacons.c @@ -0,0 +1,191 @@ +/* + * This file contains the termios TTY driver for the i386 + * vga. + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems.h> +#include <rtems/libio.h> +#include <stdlib.h> +#include <libchip/serial.h> +#include <rtems/vgacons.h> +#include <rtems/keyboard.h> +#include <libchip/sersupp.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <crt.h> +#include <assert.h> +#include <rtems/keyboard.h> + +#define VGACONS_STATIC static + +/* + * vgacons_init + * + * This function initializes the VGA console to a quiecsent state. + */ +VGACONS_STATIC void vgacons_init(int minor) +{ + /* + * Note: We do not initialize the KBD interface here since + * it was initialized regardless of whether the + * vga is available or not. Therefore it is initialized + * in bsp_start. + */ +} + +/* + * vgacons_open + * + * This function opens a port for communication. + * + * Default state is 9600 baud, 8 bits, No parity, and 1 stop bit. + */ +VGACONS_STATIC int vgacons_open( + int major, + int minor, + void *arg +) +{ + return RTEMS_SUCCESSFUL; +} + +/* + * vgacons_close + * + * This function shuts down the requested port. + */ +VGACONS_STATIC int vgacons_close( + int major, + int minor, + void *arg +) +{ + return(RTEMS_SUCCESSFUL); +} + +/* + * vgacons_write_polled + * + * This routine polls out the requested character. + */ +VGACONS_STATIC void vgacons_write_polled( + int minor, + char c +) +{ + _IBMPC_outch( c ); + if( c == '\n') + _IBMPC_outch( '\r' ); /* LF = LF + CR */ +} + +/* + * vgacons_write_support_polled + * + * Console Termios output entry point when using polled output. + * + */ +VGACONS_STATIC ssize_t vgacons_write_support_polled( + int minor, + const char *buf, + size_t len +) +{ + int nwrite = 0; + + /* + * poll each byte in the string out of the port. + */ + while (nwrite < len) { + vgacons_write_polled(minor, *buf++); + nwrite++; + } + + /* + * return the number of bytes written. + */ + return nwrite; +} + +/* + * vgacons_inbyte_nonblocking_polled + * + * Console Termios polling input entry point. + */ +VGACONS_STATIC int vgacons_inbyte_nonblocking_polled( + int minor +) +{ + if( rtems_kbpoll() ) { + int c = getch(); + return c; + } + + return -1; +} + +/* + * vgacons_set_attributes + * + * This function sets the UART channel to reflect the requested termios + * port settings. + */ +VGACONS_STATIC int vgacons_set_attributes( + int minor, + const struct termios *t +) +{ + return 0; +} + +bool vgacons_probe( + int minor +) +{ + rtems_status_code status; + static bool firstTime = true; + + if ((*(unsigned char*) NB_MAX_ROW_ADDR == 0) && + (*(unsigned short*)NB_MAX_COL_ADDR == 0)) { + return false; + } + + /* + * If there is a video card, let's assume there is also a keyboard. + * The means that we need the ISR installed in case someone wants to + * use the Keyboard or PS2 Mouse. With Microwindows, the console + * can be COM1 and you can still use the mouse/VGA for graphics. + */ + if ( firstTime ) { + status = rtems_interrupt_handler_install( + BSP_KEYBOARD, + "vgacons", + RTEMS_INTERRUPT_UNIQUE, + keyboard_interrupt, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + } + firstTime = false; + + return true; +} + +const console_fns vgacons_fns = +{ + libchip_serial_default_probe, /* deviceProbe */ + vgacons_open, /* deviceFirstOpen */ + vgacons_close, /* deviceLastClose */ + vgacons_inbyte_nonblocking_polled, /* deviceRead */ + vgacons_write_support_polled, /* deviceWrite */ + vgacons_init, /* deviceInitialize */ + vgacons_write_polled, /* deviceWritePolled */ + vgacons_set_attributes, /* deviceSetAttributes */ + FALSE, /* deviceOutputUsesInterrupts */ +}; diff --git a/bsps/i386/pc386/console/vgainit.c b/bsps/i386/pc386/console/vgainit.c new file mode 100644 index 0000000000..ce83ae59b1 --- /dev/null +++ b/bsps/i386/pc386/console/vgainit.c @@ -0,0 +1,757 @@ +/* + * Copyright (c) 1999 Greg Haerr <greg@censoft.com> + * Copyright (c) 1991 David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * Alternate EGA/VGA Screen Driver Init, direct hw programming + */ +#include <i386_io.h> + +#ifdef __rtems__ +#define ROMFONT 0 /* =0 no bios rom fonts available*/ +#else +#define ROMFONT 1 /* =1 uses PC rom fonts */ +#endif + +/* defines are defined in device.h of the MicroWindows package */ +#define MODE_SET 0 /* draw pixels as given (default) */ +#define MODE_XOR 1 /* draw pixels using XOR */ +#define MODE_OR 2 /* draw pixels using OR (notimp)*/ +#define MODE_AND 3 /* draw pixels using AND (notimp)*/ +#define MODE_MAX 3 +typedef int MODE; /* drawing mode*/ + +/* Define one and only one of the following to be nonzero*/ +#define VGA_ET4000 0 /* TSENG LABS ET4000 chip 800x600*/ +#define VGA_STANDARD 1 /* standard VGA 640x480*/ +#define EGA_STANDARD 0 /* standard EGA 640x350*/ + +#define DONE 0 +#define IN 1 +#define OUT 2 + +#define RAM_SCAN_LINES 32 /* number of scan lines in fonts in RAM */ +#define FONT_CHARS 256 /* number of characters in font tables */ +#define CHAR_WIDTH 8 /* number of pixels for character width */ + +#define PALREG 0x3c0 +#define SEQREG 0x3c4 +#define SEQVAL 0x3c5 +#define GRREG 0x3ce +#define GRVAL 0x3cf +#define ATTRREG 0x3da +#define CRTCREG 0x3d4 +#define CRTCVAL 0x3d5 + +#define GENREG1 0x3c2 +#define GENREG2 0x3cc +#define GENREG3 0x3ca + +#define DATA_ROTATE 3 /* register number for data rotate */ + +typedef struct { + int action; + int port1; + int data1; + int port2; + int data2; +} REGIO; + +#if ROMFONT +extern FARADDR rom_char_addr; /* address of ROM font*/ +extern int ROM_CHAR_HEIGHT; /* ROM character height*/ +#endif + +/* local data*/ +static REGIO graphics_on[]; +static REGIO graph_off[]; + +/* entry points*/ +void ega_hwinit(void); +void ega_hwterm(void); + +/* local routines*/ +static void writeregs(REGIO *rp); +static void out_word(unsigned int p,unsigned int d); +static void setmode(MODE mode); + +void +ega_hwinit(void) +{ + writeregs(graphics_on); +} + +void +ega_hwterm(void) +{ + setmode(MODE_SET); + + /* Copy character table from ROM back into bit plane 2 before turning + * off graphics. + */ + out_word(SEQREG, 0x0100); /* syn reset */ + out_word(SEQREG, 0x0402); /* cpu writes only to map 2 */ + out_word(SEQREG, 0x0704); /* sequential addressing */ + out_word(SEQREG, 0x0300); /* clear synchronous reset */ + + out_word(GRREG, 0x0204); /* select map 2 for CPU reads */ + out_word(GRREG, 0x0005); /* disable odd-even addressing */ + +#if ROMFONT + { + FARADDR srcoffset; + FARADDR destoffset; + int data; + int ch; + int row; + + srcoffset = rom_char_addr; + destoffset = EGA_BASE; + for (ch = 0; ch < FONT_CHARS; ch++) { + for(row = 0; row < ROM_CHAR_HEIGHT; row++) { + data = GETBYTE_FP(srcoffset++); + PUTBYTE_FP(destoffset++, data); + } + destoffset += (RAM_SCAN_LINES - ROM_CHAR_HEIGHT); + } + } +#endif + + /* Finally set the registers back for text mode. */ + writeregs(graph_off); +} + +/* Set the graphics registers as indicated by the given table */ +static void +writeregs(REGIO *rp) +{ + for (; rp->action != DONE; rp++) { + switch (rp->action) { + case IN: + inp(rp->port1); + break; + case OUT: + outp(rp->port1, rp->data1); + if (rp->port2) + outp(rp->port2, rp->data2); + break; + } + } +} + +/* Output a word to an I/O port. */ +static void +out_word(unsigned int p,unsigned int d) +{ + outp(p, d & 0xff); + outp(p + 1, (d >> 8) & 0xff); +} + +/* Values for the data rotate register to implement drawing modes. */ +static unsigned char mode_table[MODE_MAX + 1] = { + 0x00, 0x18, 0x10, 0x08 +}; + +/* Set the drawing mode. + * This is either SET, OR, AND, or XOR. + */ +static void +setmode(MODE mode) +{ + if (mode > MODE_MAX) + return; + outp(GRREG, DATA_ROTATE); + outp(GRVAL, mode_table[mode]); +} + +#if VGA_ET4000 + +/* VGA 800x600 16-color graphics (BIOS mode 0x29). + */ +REGIO graphics_on[] = { + /* Reset attr F/F */ + IN, ATTRREG, 0, 0, 0, + + /* Disable palette */ + OUT, PALREG, 0, 0, 0, + + /* Reset sequencer regs */ + OUT, SEQREG, 0, SEQVAL, 0, + OUT, SEQREG, 1, SEQVAL, 1, + OUT, SEQREG, 2, SEQVAL, 0x0f, + OUT, SEQREG, 3, SEQVAL, 0, + OUT, SEQREG, 4, SEQVAL, 6, + + /* Misc out reg */ + OUT, GENREG1, 0xe3, 0, 0, + + /* Sequencer enable */ + OUT, SEQREG, 0, SEQVAL, 0x03, + + /* Unprotect crtc regs 0-7 */ + OUT, CRTCREG, 0x11, CRTCVAL, 0, + + /* Crtc */ + OUT, CRTCREG, 0, CRTCVAL, 0x7a, + OUT, CRTCREG, 1, CRTCVAL, 0x63, + OUT, CRTCREG, 2, CRTCVAL, 0x64, + OUT, CRTCREG, 3, CRTCVAL, 0x1d, + OUT, CRTCREG, 4, CRTCVAL, 0x68, + OUT, CRTCREG, 5, CRTCVAL, 0x9a, + OUT, CRTCREG, 6, CRTCVAL, 0x78, + OUT, CRTCREG, 7, CRTCVAL, 0xf0, + OUT, CRTCREG, 8, CRTCVAL, 0x00, + OUT, CRTCREG, 9, CRTCVAL, 0x60, + OUT, CRTCREG, 10, CRTCVAL, 0x00, + OUT, CRTCREG, 11, CRTCVAL, 0x00, + OUT, CRTCREG, 12, CRTCVAL, 0x00, + OUT, CRTCREG, 13, CRTCVAL, 0x00, + OUT, CRTCREG, 14, CRTCVAL, 0x00, + OUT, CRTCREG, 15, CRTCVAL, 0x00, + OUT, CRTCREG, 16, CRTCVAL, 0x5c, + OUT, CRTCREG, 17, CRTCVAL, 0x8e, + OUT, CRTCREG, 18, CRTCVAL, 0x57, + OUT, CRTCREG, 19, CRTCVAL, 0x32, + OUT, CRTCREG, 20, CRTCVAL, 0x00, + OUT, CRTCREG, 21, CRTCVAL, 0x5b, + OUT, CRTCREG, 22, CRTCVAL, 0x75, + OUT, CRTCREG, 23, CRTCVAL, 0xc3, + OUT, CRTCREG, 24, CRTCVAL, 0xff, + + /* Graphics controller */ + OUT, GENREG2, 0x00, 0, 0, + OUT, GENREG3, 0x01, 0, 0, + OUT, GRREG, 0, GRVAL, 0x00, + OUT, GRREG, 1, GRVAL, 0x00, + OUT, GRREG, 2, GRVAL, 0x00, + OUT, GRREG, 3, GRVAL, 0x00, + OUT, GRREG, 4, GRVAL, 0x00, + OUT, GRREG, 5, GRVAL, 0x00, + OUT, GRREG, 6, GRVAL, 0x05, + OUT, GRREG, 7, GRVAL, 0x0f, + OUT, GRREG, 8, GRVAL, 0xff, + + /* Reset attribute flip/flop */ + IN, ATTRREG, 0, 0, 0, + + /* Palette */ + OUT, PALREG, 0, PALREG, 0x00, + OUT, PALREG, 1, PALREG, 0x01, + OUT, PALREG, 2, PALREG, 0x02, + OUT, PALREG, 3, PALREG, 0x03, + OUT, PALREG, 4, PALREG, 0x04, + OUT, PALREG, 5, PALREG, 0x05, + OUT, PALREG, 6, PALREG, 0x06, + OUT, PALREG, 7, PALREG, 0x07, + OUT, PALREG, 8, PALREG, 0x38, + OUT, PALREG, 9, PALREG, 0x39, + OUT, PALREG, 10, PALREG, 0x3a, + OUT, PALREG, 11, PALREG, 0x3b, + OUT, PALREG, 12, PALREG, 0x3c, + OUT, PALREG, 13, PALREG, 0x3d, + OUT, PALREG, 14, PALREG, 0x3e, + OUT, PALREG, 15, PALREG, 0x3f, + OUT, PALREG, 16, PALREG, 0x01, + OUT, PALREG, 17, PALREG, 0x00, + OUT, PALREG, 18, PALREG, 0x0f, + OUT, PALREG, 19, PALREG, 0x00, + + /* Enable palette */ + OUT, PALREG, 0x20, 0, 0, + + /* End of table */ + DONE, 0, 0, 0, 0 +}; + +/* VGA 80x25 text (BIOS mode 3). + */ +static REGIO graph_off[] = { + /* Reset attr F/F */ + IN, ATTRREG, 0, 0, 0, + + /* Disable palette */ + OUT, PALREG, 0, 0, 0, + + /* Reset sequencer regs */ + OUT, SEQREG, 0, SEQVAL, 1, + OUT, SEQREG, 1, SEQVAL, 1, + OUT, SEQREG, 2, SEQVAL, 3, + OUT, SEQREG, 3, SEQVAL, 0, + OUT, SEQREG, 4, SEQVAL, 2, + + /* Misc out reg */ + OUT, GENREG1, 0x63, 0, 0, + + /* Sequencer enable */ + OUT, SEQREG, 0, SEQVAL, 3, + + /* Unprotect crtc regs 0-7 */ + OUT, CRTCREG, 0x11, CRTCVAL, 0, + + /* Crtc */ + OUT, CRTCREG, 0, CRTCVAL, 0x5f, /* horiz total */ + OUT, CRTCREG, 1, CRTCVAL, 0x4f, /* horiz end */ + OUT, CRTCREG, 2, CRTCVAL, 0x50, /* horiz blank */ + OUT, CRTCREG, 3, CRTCVAL, 0x82, /* end blank */ + OUT, CRTCREG, 4, CRTCVAL, 0x55, /* horiz retrace */ + OUT, CRTCREG, 5, CRTCVAL, 0x81, /* end retrace */ + OUT, CRTCREG, 6, CRTCVAL, 0xbf, /* vert total */ + OUT, CRTCREG, 7, CRTCVAL, 0x1f, /* overflows */ + OUT, CRTCREG, 8, CRTCVAL, 0x00, /* row scan */ + OUT, CRTCREG, 9, CRTCVAL, 0x4f, /* max scan line */ + OUT, CRTCREG, 10, CRTCVAL, 0x00, /* cursor start */ + OUT, CRTCREG, 11, CRTCVAL, 0x0f, /* cursor end */ + OUT, CRTCREG, 12, CRTCVAL, 0x0e, /* start high addr */ + OUT, CRTCREG, 13, CRTCVAL, 0xb0, /* low addr */ + OUT, CRTCREG, 14, CRTCVAL, 0x16, /* cursor high */ + OUT, CRTCREG, 15, CRTCVAL, 0x30, /* cursor low */ + OUT, CRTCREG, 16, CRTCVAL, 0x9c, /* vert retrace */ + OUT, CRTCREG, 17, CRTCVAL, 0x8e, /* retrace end */ + OUT, CRTCREG, 18, CRTCVAL, 0x8f, /* vert end */ + OUT, CRTCREG, 19, CRTCVAL, 0x28, /* offset */ + OUT, CRTCREG, 20, CRTCVAL, 0x1f, /* underline */ + OUT, CRTCREG, 21, CRTCVAL, 0x96, /* vert blank */ + OUT, CRTCREG, 22, CRTCVAL, 0xb9, /* end blank */ + OUT, CRTCREG, 23, CRTCVAL, 0xa3, /* crt mode */ + OUT, CRTCREG, 24, CRTCVAL, 0xff, /* line compare */ + + /* Graphics controller */ + OUT, GENREG2, 0x00, 0, 0, + OUT, GENREG3, 0x01, 0, 0, + OUT, GRREG, 0, GRVAL, 0x00, + OUT, GRREG, 1, GRVAL, 0x00, + OUT, GRREG, 2, GRVAL, 0x00, + OUT, GRREG, 3, GRVAL, 0x00, + OUT, GRREG, 4, GRVAL, 0x00, + OUT, GRREG, 5, GRVAL, 0x10, + OUT, GRREG, 6, GRVAL, 0x0e, + OUT, GRREG, 7, GRVAL, 0x00, + OUT, GRREG, 8, GRVAL, 0xff, + + /* Reset attribute flip/flop */ + IN, ATTRREG, 0, 0, 0, + + /* Palette */ + OUT, PALREG, 0, PALREG, 0x00, + OUT, PALREG, 1, PALREG, 0x01, + OUT, PALREG, 2, PALREG, 0x02, + OUT, PALREG, 3, PALREG, 0x03, + OUT, PALREG, 4, PALREG, 0x04, + OUT, PALREG, 5, PALREG, 0x05, + OUT, PALREG, 6, PALREG, 0x06, + OUT, PALREG, 7, PALREG, 0x07, + OUT, PALREG, 8, PALREG, 0x10, + OUT, PALREG, 9, PALREG, 0x11, + OUT, PALREG, 10, PALREG, 0x12, + OUT, PALREG, 11, PALREG, 0x13, + OUT, PALREG, 12, PALREG, 0x14, + OUT, PALREG, 13, PALREG, 0x15, + OUT, PALREG, 14, PALREG, 0x16, + OUT, PALREG, 15, PALREG, 0x17, + OUT, PALREG, 16, PALREG, 0x08, + OUT, PALREG, 17, PALREG, 0x00, + OUT, PALREG, 18, PALREG, 0x0f, + OUT, PALREG, 19, PALREG, 0x00, + + /* Enable palette */ + OUT, PALREG, 0x20, 0, 0, + + /* End of table */ + DONE, 0, 0, 0, 0 +}; + +#endif + +#if VGA_STANDARD + +/* VGA 640x480 16-color graphics (BIOS mode 0x12). + */ +static REGIO graphics_on[] = { + /* Reset attr F/F */ + { IN, ATTRREG, 0, 0, 0 }, + + /* Disable palette */ + { OUT, PALREG, 0, 0, 0 }, + + /* Reset sequencer regs */ + { OUT, SEQREG, 0, SEQVAL, 0 }, + { OUT, SEQREG, 1, SEQVAL, 1 }, + { OUT, SEQREG, 2, SEQVAL, 0x0f }, + { OUT, SEQREG, 3, SEQVAL, 0 }, + { OUT, SEQREG, 4, SEQVAL, 6 }, + + /* Misc out reg */ + { OUT, GENREG1, 0xe3, 0, 0 }, + + /* Sequencer enable */ + { OUT, SEQREG, 0, SEQVAL, 0x03 }, + + /* Unprotect crtc regs 0-7 */ + { OUT, CRTCREG, 0x11, CRTCVAL, 0 }, + + /* Crtc */ + { OUT, CRTCREG, 0, CRTCVAL, 0x5f }, + { OUT, CRTCREG, 1, CRTCVAL, 0x4f }, + { OUT, CRTCREG, 2, CRTCVAL, 0x50 }, + { OUT, CRTCREG, 3, CRTCVAL, 0x82 }, + { OUT, CRTCREG, 4, CRTCVAL, 0x54 }, + { OUT, CRTCREG, 5, CRTCVAL, 0x80 }, + { OUT, CRTCREG, 6, CRTCVAL, 0x0b }, + { OUT, CRTCREG, 7, CRTCVAL, 0x3e }, + { OUT, CRTCREG, 8, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 9, CRTCVAL, 0x40 }, + { OUT, CRTCREG, 10, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 11, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 12, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 13, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 14, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 15, CRTCVAL, 0x59 }, + { OUT, CRTCREG, 16, CRTCVAL, 0xea }, + { OUT, CRTCREG, 17, CRTCVAL, 0x8c }, + { OUT, CRTCREG, 18, CRTCVAL, 0xdf }, + { OUT, CRTCREG, 19, CRTCVAL, 0x28 }, + { OUT, CRTCREG, 20, CRTCVAL, 0x00 }, + { OUT, CRTCREG, 21, CRTCVAL, 0xe7 }, + { OUT, CRTCREG, 22, CRTCVAL, 0x04 }, + { OUT, CRTCREG, 23, CRTCVAL, 0xe3 }, + { OUT, CRTCREG, 24, CRTCVAL, 0xff }, + + /* Graphics controller */ + { OUT, GENREG2, 0x00, 0, 0 }, + { OUT, GENREG3, 0x01, 0, 0 }, + { OUT, GRREG, 0, GRVAL, 0x00 }, + { OUT, GRREG, 1, GRVAL, 0x00 }, + { OUT, GRREG, 2, GRVAL, 0x00 }, + { OUT, GRREG, 3, GRVAL, 0x00 }, + { OUT, GRREG, 4, GRVAL, 0x00 }, + { OUT, GRREG, 5, GRVAL, 0x00 }, + { OUT, GRREG, 6, GRVAL, 0x05 }, + { OUT, GRREG, 7, GRVAL, 0x0f }, + { OUT, GRREG, 8, GRVAL, 0xff }, + + /* Reset attribute flip/flop */ + { IN, ATTRREG, 0, 0, 0 }, + + /* Palette */ + { OUT, PALREG, 0, PALREG, 0x00 }, + { OUT, PALREG, 1, PALREG, 0x01 }, + { OUT, PALREG, 2, PALREG, 0x02 }, + { OUT, PALREG, 3, PALREG, 0x03 }, + { OUT, PALREG, 4, PALREG, 0x04 }, + { OUT, PALREG, 5, PALREG, 0x05 }, + { OUT, PALREG, 6, PALREG, 0x06 }, + { OUT, PALREG, 7, PALREG, 0x07 }, + { OUT, PALREG, 8, PALREG, 0x38 }, + { OUT, PALREG, 9, PALREG, 0x39 }, + { OUT, PALREG, 10, PALREG, 0x3a }, + { OUT, PALREG, 11, PALREG, 0x3b }, + { OUT, PALREG, 12, PALREG, 0x3c }, + { OUT, PALREG, 13, PALREG, 0x3d }, + { OUT, PALREG, 14, PALREG, 0x3e }, + { OUT, PALREG, 15, PALREG, 0x3f }, + { OUT, PALREG, 16, PALREG, 0x01 }, + { OUT, PALREG, 17, PALREG, 0x00 }, + { OUT, PALREG, 18, PALREG, 0x0f }, + { OUT, PALREG, 19, PALREG, 0x00 }, + + /* Enable palette */ + { OUT, PALREG, 0x20, 0, 0 }, + + /* End of table */ + { DONE, 0, 0, 0, 0 } +}; + +/* VGA 80x25 text (BIOS mode 3). + */ +static REGIO graph_off[] = { + /* Reset attr F/F */ + { IN, ATTRREG, 0, 0, 0 }, + + /* Disable palette */ + { OUT, PALREG, 0, 0, 0 }, + + /* Reset sequencer regs */ + { OUT, SEQREG, 0, SEQVAL, 1 }, + { OUT, SEQREG, 1, SEQVAL, 1 }, + { OUT, SEQREG, 2, SEQVAL, 3 }, + { OUT, SEQREG, 3, SEQVAL, 0 }, + { OUT, SEQREG, 4, SEQVAL, 2 }, + + /* Misc out reg */ + { OUT, GENREG1, 0x63, 0, 0 }, + + /* Sequencer enable */ + { OUT, SEQREG, 0, SEQVAL, 3 }, + + /* Unprotect crtc regs 0-7 */ + { OUT, CRTCREG, 0x11, CRTCVAL, 0 }, + + /* Crtc */ + { OUT, CRTCREG, 0, CRTCVAL, 0x5f }, /* horiz total */ + { OUT, CRTCREG, 1, CRTCVAL, 0x4f }, /* horiz end */ + { OUT, CRTCREG, 2, CRTCVAL, 0x50 }, /* horiz blank */ + { OUT, CRTCREG, 3, CRTCVAL, 0x82 }, /* end blank */ + { OUT, CRTCREG, 4, CRTCVAL, 0x55 }, /* horiz retrace */ + { OUT, CRTCREG, 5, CRTCVAL, 0x81 }, /* end retrace */ + { OUT, CRTCREG, 6, CRTCVAL, 0xbf }, /* vert total */ + { OUT, CRTCREG, 7, CRTCVAL, 0x1f }, /* overflows */ + { OUT, CRTCREG, 8, CRTCVAL, 0x00 }, /* row scan */ + { OUT, CRTCREG, 9, CRTCVAL, 0x4f }, /* max scan line */ + { OUT, CRTCREG, 10, CRTCVAL, 0x00 }, /* cursor start */ + { OUT, CRTCREG, 11, CRTCVAL, 0x0f }, /* cursor end */ + { OUT, CRTCREG, 12, CRTCVAL, 0x0e }, /* start high addr */ + { OUT, CRTCREG, 13, CRTCVAL, 0xb0 }, /* low addr */ + { OUT, CRTCREG, 14, CRTCVAL, 0x16 }, /* cursor high */ + { OUT, CRTCREG, 15, CRTCVAL, 0x30 }, /* cursor low */ + { OUT, CRTCREG, 16, CRTCVAL, 0x9c }, /* vert retrace */ + { OUT, CRTCREG, 17, CRTCVAL, 0x8e }, /* retrace end */ + { OUT, CRTCREG, 18, CRTCVAL, 0x8f }, /* vert end */ + { OUT, CRTCREG, 19, CRTCVAL, 0x28 }, /* offset */ + { OUT, CRTCREG, 20, CRTCVAL, 0x1f }, /* underline */ + { OUT, CRTCREG, 21, CRTCVAL, 0x96 }, /* vert blank */ + { OUT, CRTCREG, 22, CRTCVAL, 0xb9 }, /* end blank */ + { OUT, CRTCREG, 23, CRTCVAL, 0xa3 }, /* crt mode */ + { OUT, CRTCREG, 24, CRTCVAL, 0xff }, /* line compare */ + + /* Graphics controller */ + { OUT, GENREG2, 0x00, 0, 0 }, + { OUT, GENREG3, 0x01, 0, 0 }, + { OUT, GRREG, 0, GRVAL, 0x00 }, + { OUT, GRREG, 1, GRVAL, 0x00 }, + { OUT, GRREG, 2, GRVAL, 0x00 }, + { OUT, GRREG, 3, GRVAL, 0x00 }, + { OUT, GRREG, 4, GRVAL, 0x00 }, + { OUT, GRREG, 5, GRVAL, 0x10 }, + { OUT, GRREG, 6, GRVAL, 0x0e }, + { OUT, GRREG, 7, GRVAL, 0x00 }, + { OUT, GRREG, 8, GRVAL, 0xff }, + + /* Reset attribute flip/flop */ + { IN, ATTRREG, 0, 0, 0 }, + + /* Palette */ + { OUT, PALREG, 0, PALREG, 0x00 }, + { OUT, PALREG, 1, PALREG, 0x01 }, + { OUT, PALREG, 2, PALREG, 0x02 }, + { OUT, PALREG, 3, PALREG, 0x03 }, + { OUT, PALREG, 4, PALREG, 0x04 }, + { OUT, PALREG, 5, PALREG, 0x05 }, + { OUT, PALREG, 6, PALREG, 0x06 }, + { OUT, PALREG, 7, PALREG, 0x07 }, + { OUT, PALREG, 8, PALREG, 0x10 }, + { OUT, PALREG, 9, PALREG, 0x11 }, + { OUT, PALREG, 10, PALREG, 0x12 }, + { OUT, PALREG, 11, PALREG, 0x13 }, + { OUT, PALREG, 12, PALREG, 0x14 }, + { OUT, PALREG, 13, PALREG, 0x15 }, + { OUT, PALREG, 14, PALREG, 0x16 }, + { OUT, PALREG, 15, PALREG, 0x17 }, + { OUT, PALREG, 16, PALREG, 0x08 }, + { OUT, PALREG, 17, PALREG, 0x00 }, + { OUT, PALREG, 18, PALREG, 0x0f }, + { OUT, PALREG, 19, PALREG, 0x00 }, + + /* Enable palette */ + { OUT, PALREG, 0x20, 0, 0 }, + + /* End of table */ + { DONE, 0, 0, 0, 0 } +}; + +#endif + +#if EGA_STANDARD + +/* EGA 640x350 16-color graphics (BIOS mode 0x10). + */ +static REGIO graphics_on[] = { + /* Reset attr F/F */ + IN, ATTRREG, 0, 0, 0, + + /* Disable palette */ + OUT, PALREG, 0, 0, 0, + + /* Reset sequencer regs */ + OUT, SEQREG, 0, SEQVAL, 0, + OUT, SEQREG, 1, SEQVAL, 1, + OUT, SEQREG, 2, SEQVAL, 0x0f, + OUT, SEQREG, 3, SEQVAL, 0, + OUT, SEQREG, 4, SEQVAL, 6, + + /* Misc out reg */ + OUT, GENREG1, 0xa7, 0, 0, + + /* Sequencer enable */ + OUT, SEQREG, 0, SEQVAL, 0x03, + + /* Unprotect crtc regs 0-7 */ + OUT, CRTCREG, 0x11, CRTCVAL, 0, + + /* Crtc */ + OUT, CRTCREG, 0, CRTCVAL, 0x5b, + OUT, CRTCREG, 1, CRTCVAL, 0x4f, + OUT, CRTCREG, 2, CRTCVAL, 0x53, + OUT, CRTCREG, 3, CRTCVAL, 0x37, + OUT, CRTCREG, 4, CRTCVAL, 0x52, + OUT, CRTCREG, 5, CRTCVAL, 0x00, + OUT, CRTCREG, 6, CRTCVAL, 0x6c, + OUT, CRTCREG, 7, CRTCVAL, 0x1f, + OUT, CRTCREG, 8, CRTCVAL, 0x00, + OUT, CRTCREG, 9, CRTCVAL, 0x00, + OUT, CRTCREG, 10, CRTCVAL, 0x00, + OUT, CRTCREG, 11, CRTCVAL, 0x00, + OUT, CRTCREG, 12, CRTCVAL, 0x00, + OUT, CRTCREG, 13, CRTCVAL, 0x00, + OUT, CRTCREG, 14, CRTCVAL, 0x00, + OUT, CRTCREG, 15, CRTCVAL, 0x00, + OUT, CRTCREG, 16, CRTCVAL, 0x5e, + OUT, CRTCREG, 17, CRTCVAL, 0x2b, + OUT, CRTCREG, 18, CRTCVAL, 0x5d, + OUT, CRTCREG, 19, CRTCVAL, 0x28, + OUT, CRTCREG, 20, CRTCVAL, 0x0f, + OUT, CRTCREG, 21, CRTCVAL, 0x5f, + OUT, CRTCREG, 22, CRTCVAL, 0x0a, + OUT, CRTCREG, 23, CRTCVAL, 0xe3, + OUT, CRTCREG, 24, CRTCVAL, 0xff, + + /* Graphics controller */ + OUT, GENREG2, 0x00, 0, 0, + OUT, GENREG3, 0x01, 0, 0, + OUT, GRREG, 0, GRVAL, 0x00, + OUT, GRREG, 1, GRVAL, 0x00, + OUT, GRREG, 2, GRVAL, 0x00, + OUT, GRREG, 3, GRVAL, 0x00, + OUT, GRREG, 4, GRVAL, 0x00, + OUT, GRREG, 5, GRVAL, 0x00, + OUT, GRREG, 6, GRVAL, 0x05, + OUT, GRREG, 7, GRVAL, 0x0f, + OUT, GRREG, 8, GRVAL, 0xff, + + /* Reset attribute flip/flop */ + IN, ATTRREG, 0, 0, 0, + + /* Palette */ + OUT, PALREG, 0, PALREG, 0x00, + OUT, PALREG, 1, PALREG, 0x01, + OUT, PALREG, 2, PALREG, 0x02, + OUT, PALREG, 3, PALREG, 0x03, + OUT, PALREG, 4, PALREG, 0x04, + OUT, PALREG, 5, PALREG, 0x05, + OUT, PALREG, 6, PALREG, 0x06, + OUT, PALREG, 7, PALREG, 0x07, + OUT, PALREG, 8, PALREG, 0x38, + OUT, PALREG, 9, PALREG, 0x39, + OUT, PALREG, 10, PALREG, 0x3a, + OUT, PALREG, 11, PALREG, 0x3b, + OUT, PALREG, 12, PALREG, 0x3c, + OUT, PALREG, 13, PALREG, 0x3d, + OUT, PALREG, 14, PALREG, 0x3e, + OUT, PALREG, 15, PALREG, 0x3f, + OUT, PALREG, 16, PALREG, 0x01, + OUT, PALREG, 17, PALREG, 0x00, + OUT, PALREG, 18, PALREG, 0x0f, + OUT, PALREG, 19, PALREG, 0x00, + + /* Enable palette */ + OUT, PALREG, 0x20, 0, 0, + + /* End of table */ + DONE, 0, 0, 0, 0 +}; + +/* EGA 80x25 text (BIOS mode 3). + */ +static REGIO graph_off[] = { + /* Reset attr F/F */ + IN, ATTRREG, 0, 0, 0, + + /* Disable palette */ + OUT, PALREG, 0, 0, 0, + + /* Reset sequencer regs */ + OUT, SEQREG, 0, SEQVAL, 1, + OUT, SEQREG, 1, SEQVAL, 1, + OUT, SEQREG, 2, SEQVAL, 3, + OUT, SEQREG, 3, SEQVAL, 0, + OUT, SEQREG, 4, SEQVAL, 3, + + /* Misc out reg */ + OUT, GENREG1, 0xa7, 0, 0, + + /* Sequencer enable */ + OUT, SEQREG, 0, SEQVAL, 3, + + /* Crtc */ + OUT, CRTCREG, 0, CRTCVAL, 0x5b, /* horiz total */ + OUT, CRTCREG, 1, CRTCVAL, 0x4f, /* horiz end */ + OUT, CRTCREG, 2, CRTCVAL, 0x53, /* horiz blank */ + OUT, CRTCREG, 3, CRTCVAL, 0x37, /* end blank */ + OUT, CRTCREG, 4, CRTCVAL, 0x51, /* horiz retrace */ + OUT, CRTCREG, 5, CRTCVAL, 0x5b, /* end retrace */ + OUT, CRTCREG, 6, CRTCVAL, 0x6c, /* vert total */ + OUT, CRTCREG, 7, CRTCVAL, 0x1f, /* overflows */ + OUT, CRTCREG, 8, CRTCVAL, 0x00, /* row scan */ + OUT, CRTCREG, 9, CRTCVAL, 0x0d, /* max scan line */ + OUT, CRTCREG, 10, CRTCVAL, 0x00, /* cursor start */ + OUT, CRTCREG, 11, CRTCVAL, 0x0f, /* cursor end */ + OUT, CRTCREG, 12, CRTCVAL, 0x00, /* start high addr */ + OUT, CRTCREG, 13, CRTCVAL, 0x00, /* low addr */ + OUT, CRTCREG, 14, CRTCVAL, 0x00, /* cursor high */ + OUT, CRTCREG, 15, CRTCVAL, 0x00, /* cursor low */ + OUT, CRTCREG, 16, CRTCVAL, 0x5e, /* vert retrace */ + OUT, CRTCREG, 17, CRTCVAL, 0x2b, /* retrace end */ + OUT, CRTCREG, 18, CRTCVAL, 0x5d, /* vert end */ + OUT, CRTCREG, 19, CRTCVAL, 0x28, /* offset */ + OUT, CRTCREG, 20, CRTCVAL, 0x0f, /* underline */ + OUT, CRTCREG, 21, CRTCVAL, 0x5e, /* vert blank */ + OUT, CRTCREG, 22, CRTCVAL, 0x0a, /* end blank */ + OUT, CRTCREG, 23, CRTCVAL, 0xa3, /* crt mode */ + OUT, CRTCREG, 24, CRTCVAL, 0xff, /* line compare */ + + /* Graphics controller */ + OUT, GENREG2, 0x00, 0, 0, + OUT, GENREG3, 0x01, 0, 0, + OUT, GRREG, 0, GRVAL, 0x00, + OUT, GRREG, 1, GRVAL, 0x00, + OUT, GRREG, 2, GRVAL, 0x00, + OUT, GRREG, 3, GRVAL, 0x00, + OUT, GRREG, 4, GRVAL, 0x00, + OUT, GRREG, 5, GRVAL, 0x10, + OUT, GRREG, 6, GRVAL, 0x0e, + OUT, GRREG, 7, GRVAL, 0x00, + OUT, GRREG, 8, GRVAL, 0xff, + + /* Reset attribute flip/flop */ + IN, ATTRREG, 0, 0, 0, + + /* Palette */ + OUT, PALREG, 0, PALREG, 0x00, + OUT, PALREG, 1, PALREG, 0x01, + OUT, PALREG, 2, PALREG, 0x02, + OUT, PALREG, 3, PALREG, 0x03, + OUT, PALREG, 4, PALREG, 0x04, + OUT, PALREG, 5, PALREG, 0x05, + OUT, PALREG, 6, PALREG, 0x14, + OUT, PALREG, 7, PALREG, 0x07, + OUT, PALREG, 8, PALREG, 0x38, + OUT, PALREG, 9, PALREG, 0x39, + OUT, PALREG, 10, PALREG, 0x3a, + OUT, PALREG, 11, PALREG, 0x3b, + OUT, PALREG, 12, PALREG, 0x3c, + OUT, PALREG, 13, PALREG, 0x3d, + OUT, PALREG, 14, PALREG, 0x3e, + OUT, PALREG, 15, PALREG, 0x3f, + OUT, PALREG, 16, PALREG, 0x08, + OUT, PALREG, 17, PALREG, 0x00, + OUT, PALREG, 18, PALREG, 0x0f, + OUT, PALREG, 19, PALREG, 0x00, + + /* Enable palette */ + OUT, PALREG, 0x20, 0, 0, + + /* End of table */ + DONE, 0, 0, 0, 0 +}; + +#endif diff --git a/bsps/i386/pc386/console/videoAsm.S b/bsps/i386/pc386/console/videoAsm.S new file mode 100644 index 0000000000..03f31f879b --- /dev/null +++ b/bsps/i386/pc386/console/videoAsm.S @@ -0,0 +1,48 @@ +/* + * videoAsm.S - This file contains code for displaying cursor on the console + * + * Copyright (C) 1998 valette@crf.canon.fr + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + .file "videoAsm.s" + +#include <crt.h> + + .text + .align 4 + .globl wr_cursor /* Move cursor position */ + +/* + * void wr_cursor(newPosition, ioBaseAddr) + */ + +wr_cursor: pushl %ecx + movl 8(%esp), %ecx /* Get new cursor position */ + movb $CC_CURSHIGH, %al /* Cursor high location */ + movl 12(%esp), %edx /* Get IO base address */ + outb (%dx) + incw %dx /* Program Data register */ + movb %ch, %al + outb (%dx) /* Update high location cursor */ + decw %dx /* Program Index Register */ + movb $CC_CURSLOW, %al /* Cursor low location */ + outb (%dx) + incw %dx /* Program Data Register */ + movb %cl, %al + outb (%dx) /* Update low location cursor */ + popl %ecx + ret diff --git a/bsps/i386/pc386/console/vt.c b/bsps/i386/pc386/console/vt.c new file mode 100644 index 0000000000..022cb5d461 --- /dev/null +++ b/bsps/i386/pc386/console/vt.c @@ -0,0 +1,348 @@ +/* + * linux/drivers/char/vt.c + * + * Copyright (C) 1992 obz under the linux copyright + * + * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 + * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 + * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 + * Some code moved for less code duplication - Andi Kleen - Mar 1997 + * + * + * by: Rosimildo da Silva -- + * Ported to RTEMS to provide the basic interface to the console + * driver. Removed all stuff not required, such as VT_, Fonts, etc. + */ + +#include <string.h> /* memcpy */ +#include <sys/types.h> +#include <errno.h> + +#include <bsp.h> +#include <i386_io.h> +#include <rtems.h> +#include <rtems/kd.h> +#include <rtems/keyboard.h> + +/* + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by + * experimentation and study of X386 SYSV handling. + * + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will + * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to + * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing + * to the current console is done by the main ioctl code. + */ + +struct vt_struct *vt_cons[MAX_NR_CONSOLES]; + +/* Keyboard type: Default is KB_101, but can be set by machine + * specific code. + */ +unsigned char keyboard_type = KB_101; + +/* + * Generates sound of some frequency for some number of clock ticks + * + * If freq is 0, will turn off sound, else will turn it on for that time. + * If msec is 0, will return immediately, else will sleep for msec time, then + * turn sound off. + * + * We also return immediately, which is what was implied within the X + * comments - KDMKTONE doesn't put the process to sleep. + */ + +#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ + || (defined(__mips__) && !defined(CONFIG_SGI)) + +static void +kd_nosound(unsigned long ignored) +{ + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); + return; +} + +static void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ + unsigned int count = 0; + rtems_interrupt_lock_context lock_context; + + if (hz > 20 && hz < 32767) + count = 1193180 / hz; + + rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context); +/* del_timer(&sound_timer); */ + if (count) { + /* enable counter 2 */ + outb_p(inb_p(0x61)|3, 0x61); + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, TIMER_MODE); + /* select desired HZ */ + outb_p(count & 0xff, TIMER_CNTR2); + outb((count >> 8) & 0xff, TIMER_CNTR2); + +/* + if (ticks) { + sound_timer.expires = jiffies+ticks; + add_timer(&sound_timer); + } +*/ + } else + kd_nosound(0); + + rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); + return; +} + +#else + +void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ +} + +#endif + +void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; + +#define i (tmp.kb_index) +#define s (tmp.kb_table) +#define v (tmp.kb_value) +static inline int +do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) +{ + struct kbentry tmp; + ushort *key_map, val; + + tmp = *user_kbe; + if (i >= NR_KEYS) /* s cannot be >= MAX_NR_KEYMAPS */ + return -EINVAL; + + switch (cmd) { + case KDGKBENT: + key_map = key_maps[s]; + if (key_map) { + val = U(key_map[i]); + if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = (i ? K_HOLE : K_NOSUCHMAP); + user_kbe->kb_value = val; + return 0; + + case KDSKBENT: + return -EINVAL; + } + return 0; +} +#undef i +#undef s +#undef v + +#define HZ 100 + +static inline int +do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) +{ + struct kbkeycode tmp; + int kc = 0; + + tmp = *user_kbkc; + switch (cmd) { + case KDGETKEYCODE: + kc = getkeycode(tmp.scancode); + if (kc >= 0) + user_kbkc->keycode = kc; + break; + case KDSETKEYCODE: + if (!perm) + return -EPERM; + kc = setkeycode(tmp.scancode, tmp.keycode); + break; + } + return kc; +} + +static inline int +do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) +{ + return -EINVAL; +} + +/* + * We handle the console-specific ioctl's here. We allow the + * capability to modify any console, not just the fg_console. + */ +int vt_ioctl( unsigned int cmd, unsigned long arg) +{ + int perm; + unsigned int console; + unsigned char ucval; + struct kbd_struct * kbd; + + console = 0; + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or super-user. + */ + perm = 1; + kbd = kbd_table + console; + switch (cmd) { + case KIOCSOUND: + if (!perm) + return -EPERM; + if (arg) + arg = 1193180 / arg; + kd_mksound(arg, 0); + return 0; + + case KDMKTONE: + if (!perm) + return -EPERM; + { + unsigned int ticks, count; + + /* + * Generate the tone for the appropriate number of ticks. + * If the time is zero, turn off sound ourselves. + */ + ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + count = ticks ? (arg & 0xffff) : 0; + if (count) + count = 1193180 / count; + kd_mksound(count, ticks); + return 0; + } + + case KDGKBTYPE: + /* + * this is naive. + */ + ucval = keyboard_type; + goto setchar; + + case KDSETMODE: + case KDGETMODE: + return -EINVAL; + + case KDSKBMODE: + if (!perm) + return -EPERM; + switch(arg) { + case K_RAW: + kbd->kbdmode = VC_RAW; + break; + case K_MEDIUMRAW: + kbd->kbdmode = VC_MEDIUMRAW; + break; + case K_XLATE: + kbd->kbdmode = VC_XLATE; + compute_shiftstate(); + break; + case K_UNICODE: + kbd->kbdmode = VC_UNICODE; + compute_shiftstate(); + break; + default: + return -EINVAL; + } + return 0; + + case KDGKBMODE: + ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : + (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : + (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : + K_XLATE); + goto setint; + + /* this could be folded into KDSKBMODE, but for compatibility + reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ + case KDSKBMETA: + switch(arg) { + case K_METABIT: + clr_vc_kbd_mode(kbd, VC_META); + break; + case K_ESCPREFIX: + set_vc_kbd_mode(kbd, VC_META); + break; + default: + return -EINVAL; + } + return 0; + + case KDGKBMETA: + ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); + setint: + *(int *)arg = ucval; + return 0; + + case KDGETKEYCODE: + case KDSETKEYCODE: + return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); + + case KDGKBENT: + case KDSKBENT: + return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); + + case KDGKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + a->kb_cnt = accent_table_size; + memcpy( a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr) ); + return 0; + } + + case KDSKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + unsigned int ct; + + if (!perm) + return -EPERM; + ct = a->kb_cnt; + if (ct >= MAX_DIACR) + return -EINVAL; + accent_table_size = ct; + memcpy(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)); + return 0; + } + + /* the ioctls below read/set the flags usually shown in the leds */ + /* don't use them - they will go away without warning */ + case KDGKBLED: + ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + goto setchar; + + case KDSKBLED: + if (!perm) + return -EPERM; + if (arg & ~0x77) + return -EINVAL; + kbd->ledflagstate = (arg & 7); + kbd->default_ledflagstate = ((arg >> 4) & 7); + set_leds(); + return 0; + + /* the ioctls below only set the lights, not the functions */ + /* for those, see KDGKBLED and KDSKBLED above */ + case KDGETLED: + ucval = getledstate(); + setchar: + *(char*)arg = ucval; + return 0; + + case KDSETLED: + if (!perm) + return -EPERM; + setledstate(kbd, arg); + return 0; + + default: + return -EINVAL; + } +} |