// // XIO -- extended motherboard I/O package // // All optional; basically an implementation of a dumb terminal using // the PS2 keyboard and video drivers. // // Video: // // Keyboard: // Heavily changed from "linux/drivers/char/pc_keyb.c", but probably // somewhat recognizable. Had to minimize size and eliminate interrupt // handling related calls. #include #include "dink.h" #include "errors.h" #include "atkey.h" extern unsigned long IO_Base; extern long strtol(); extern void delay(); extern UCHAR DoInput(); extern void DoOutput(); extern unsigned long IO_Base; // Special modifier sequences: // // LSHIFT: 0x2A down, 0xAA up // LCTL: 0x1D down, 0x9D up // LALT: 0x38 down, 0xb8 up // RSHIFT: 0x36 down, 0xB6 up // RCTL: 0xE0 0x1D down, 0xE0 0x9D up // RALT: 0xE0 0x38 down, 0xE0 0xb8 up #define KSCAN_LCTL 0x1D // left control #define KSCAN_LSHIFT 0x2A // left shift #define KSCAN_LALT 0x38 // left alt #define KSCAN_CAPS 0x3A // caps lock #define KSCAN_RCTL 0x1D // E0 + right control #define KSCAN_RSHIFT 0x36 // right shift #define KSCAN_RALT 0x38 // E0 + left alt #define KSCAN_E0 0xe0 // E0 lead in #define BS 0x08 #define ESC 0x1B //--------------------------------------------------------------------------- // Scancode->ASCII conversion map. static unsigned char kbd_map[ 256 ] = { 0x00, ESC, '1', '2', '3', '4', '5', '6', // 00 - 07 '7', '8', '9', '0', '-', '=', BS, '\t', // 08 - 0F 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 10 - 17 'o', 'p', '[', ']', '\r', 0x00, 'a', 's', // 18 - 1F 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 20 - 27 '\'', '`', 0x00, '\\', 'z', 'x', 'c', 'v', // 28 - 2F 'b', 'n', 'm', ',', '.', '/', 0x00, 0x00, // 30 - 37 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 38 - 3F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '9', // 40 - 47 '8', '9', 0x00, '4', '5', '6', 0x00, '1', // 48 - 4F '2', '3', '0', '.', 0x00, 0x00, 0x00, 0x00, // 50 - 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58 - 5F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 60 - 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 68 - 6F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 70 - 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 78 - 7F // Rest zeroes... }; // Same, but when SHIFT is active. static unsigned char shift_kbd_map[ 256 ] = { 0x00, ESC, '!', '@', '#', '$', '%', '^', // 00 - 07 '&', '*', '(', ')', '_', '+', BS, '\t', // 08 - 0F 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 10 - 17 'O', 'P', '{', '}', '\r', 0x00, 'A', 'S', // 18 - 1F 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 20 - 27 '"', '~', 0x00, '|', 'Z', 'X', 'C', 'V', // 28 - 2F 'b', 'N', 'M', '<', '>', '?', 0x00, 0x00, // 30 - 37 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 38 - 3F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '9', // 40 - 47 '8', '9', 0x00, '4', '5', '6', 0x00, '1', // 48 - 4F '2', '3', '0', '.', 0x00, 0x00, 0x00, 0x00, // 50 - 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58 - 5F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 60 - 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 68 - 6F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 70 - 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 78 - 7F // Rest zeroes... }; static unsigned char kbd_raw; static unsigned char prev_scancode; static unsigned char LED_status; static unsigned char prev_LED_status; // LED definitions. #define SCROLL_LED 0x01 #define NUM_LED 0x02 #define CAPS_LED 0x04 // "Modify" tracks (independently) the status of each modifier key. static unsigned char Modify = 0; #define M_LALT 0x01 #define M_RALT 0x02 #define M_LSHIFT 0x04 #define M_RSHIFT 0x08 #define M_LCTL 0x10 #define M_RCTL 0x20 #define M_CAPS 0x80 //--------------------------------------------------------------------------- // kbd_translate -- translate a scancode into ASCII characters. //--------------------------------------------------------------------------- int kbd_translate( unsigned char scancode, unsigned char *keycode, char raw_mode ) { unsigned char maskcode; int down; // Look for SHIFT, ALT, CAPS and CTL modifiers. *keycode = 0; down = (scancode & 0x80) ? 0 : 1; maskcode = scancode & 0x7F; // PRINT("scan %02x mask %02x\n", scancode, maskcode); if (prev_scancode == KSCAN_E0) { if (maskcode == KSCAN_RALT) Modify = (down) ? (Modify | M_RALT) : (Modify & ~M_RALT); else if (maskcode == KSCAN_RCTL) Modify = (down) ? (Modify | M_RCTL) : (Modify & ~M_RCTL); prev_scancode = 0; return( 0 ); } else if (scancode == KSCAN_E0) { prev_scancode = scancode; return( 0 ); } else if (maskcode == KSCAN_LALT) { Modify = (down) ? (Modify | M_LALT) : (Modify & ~M_LALT); return( 0 ); } else if (maskcode == KSCAN_LSHIFT) { Modify = (down) ? (Modify | M_LSHIFT) : (Modify & ~M_LSHIFT); return( 0 ); } else if (maskcode == KSCAN_RSHIFT) { Modify = (down) ? (Modify | M_RSHIFT) : (Modify & ~M_RSHIFT); return( 0 ); } else if (maskcode == KSCAN_LCTL) { Modify = (down) ? (Modify | M_LCTL) : (Modify & ~M_LCTL); return( 0 ); } // Unlike the others, CAPS LOCK is sticky and toggles, so we ignore // up transitions completely. In addition, CAPs triggers changing the LEDs. else if (maskcode == KSCAN_CAPS) { if (down) { Modify = (Modify & M_CAPS) ? (Modify & ~M_CAPS) : (Modify | M_CAPS); if (Modify & M_CAPS) LED_status |= CAPS_LED; else LED_status &= ~CAPS_LED; } return( 0 ); } // If this is not a modifier, we aren't interested in up transitions. if (!down) return( 0 ); // PRINT("Modify: %d\n", Modify ); // Map scancode to basic characters. Nothing fancy. if (Modify & (M_LSHIFT | M_RSHIFT)) *keycode = shift_kbd_map[ scancode ]; else *keycode = kbd_map[ scancode ]; if (*keycode == 0) { // PRINT("\?\?-%02x\n", scancode); return( 0 ); } // Apply transformations to ASCII. if (Modify & M_CAPS) if ('a' <= *keycode && *keycode <= 'z') *keycode -= 0x20; if (Modify & (M_LCTL | M_RCTL)) if ('a' <= *keycode && *keycode <= 'z') *keycode &= 0x1F; if (Modify & (M_LALT | M_RALT)) *keycode |= 0x80; return( 1 ); } //--------------------------------------------------------------------------- void mdelay( int m ) { while (m-- > 0) delay( 0x2000 ); } //--------------------------------------------------------------------------- // pck_wait_empty -- Wait until keyboard controller input buffer is empty. //--------------------------------------------------------------------------- void pck_wait_empty( void ) { UCHAR status; while (1) { status = DoInput( IO_Base + KBD_STATUS_REG ); if (!(status & KBD_STAT_IBF) ) return; } } //--------------------------------------------------------------------------- // kbd_stat -- return key scancode, or NO/BAD data. Does not wait. //--------------------------------------------------------------------------- int kbd_stat(void) { UCHAR status; status = DoInput( IO_Base + KBD_STATUS_REG ); return( (status & KBD_STAT_OBF) ? 1 : 0 ); } #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ //--------------------------------------------------------------------------- // kbd_read_input -- return key scancode, or NO/BAD data. Does not wait. //--------------------------------------------------------------------------- int kbd_read_input(void) { UCHAR status; int retval = KBD_NO_DATA; status = DoInput( IO_Base + KBD_STATUS_REG ); if (status & KBD_STAT_OBF) { retval = (int) DoInput( IO_Base + KBD_DATA_REG ); if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) retval = KBD_BAD_DATA; } return( retval ); } //--------------------------------------------------------------------------- // kbd_clear_input -- clear up input buffer. //--------------------------------------------------------------------------- static void kbd_clear_input(void) { int maxread = 100; /* Random number */ do { if (kbd_read_input() == KBD_NO_DATA) break; } while (--maxread); } //--------------------------------------------------------------------------- // kbd_write -- send commands/ack's to the keyboard. //--------------------------------------------------------------------------- static void kbd_write(int address, int data) { pck_wait_empty(); DoOutput( IO_Base + address, data ); } //--------------------------------------------------------------------------- // kbd_send_data -- sends a character to the keyboard and waits // for an acknowledge, possibly retrying if asked to. // Returns the success status. //--------------------------------------------------------------------------- static int kbd_send_data( unsigned char data ) { int keycode, retries = 3; do { unsigned long timeout = KBD_TIMEOUT; kbd_write( KBD_DATA_REG, data ); mdelay( 7 ); keycode = KBD_NO_DATA; while (keycode == KBD_NO_DATA) keycode = kbd_read_input(); if (keycode == KBD_REPLY_ACK) return( 1 ); else if (keycode == KBD_REPLY_RESEND) break; else PRINT("What? %02x\n", keycode); mdelay(1); if (!--timeout) return 0; } while (retries-- > 0); return 0; } //--------------------------------------------------------------------------- // kbd_pckbd_leds -- Write to LEDs on keyboard. //--------------------------------------------------------------------------- static void kbd_pckbd_leds(unsigned char leds) { if (!kbd_send_data(KBD_CMD_SET_LEDS) || !kbd_send_data(leds)) kbd_send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ } //--------------------------------------------------------------------------- // kbd_wait_for_input -- wait until input is detected, then return it. //--------------------------------------------------------------------------- static int kbd_wait_for_input(void) { unsigned char keycode; int retval; while (1) { retval = KBD_NO_DATA; while (retval == KBD_NO_DATA) retval = kbd_read_input(); // Translate the key (maybe). if (kbd_raw) keycode = retval; else kbd_translate( retval, &keycode, kbd_raw ); // Update LEDs, if needed. if (prev_LED_status != LED_status) { prev_LED_status = LED_status; kbd_pckbd_leds( LED_status ); } if (keycode) break; } return( keycode ); } //--------------------------------------------------------------------------- // initialize_kbd -- get the keyboard started. //--------------------------------------------------------------------------- static int initialize_kbd(void) { int status; kbd_raw = 1; prev_scancode = 0; LED_status = 0; prev_LED_status = 0; // 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( KBD_CNTL_REG, KBD_CCMD_SELF_TEST ); if (kbd_wait_for_input() != 0x55) return( 1 ); // Enable the keyboard by allowing the keyboard clock to run. kbd_write( KBD_CNTL_REG, 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(KBD_DATA_REG, KBD_CMD_RESET); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status != KBD_REPLY_RESEND) return( 3 ); } while (1); if (kbd_wait_for_input() != KBD_REPLY_POR) return( 4 ); // 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(KBD_DATA_REG, KBD_CMD_DISABLE); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status != KBD_REPLY_RESEND) return( 5 ); } while (1); kbd_write( KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); kbd_write( KBD_DATA_REG, KBD_MODE_KBD_INT | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC); // If the controller does not support conversion, // Set the keyboard to scan-code set 1. kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE); if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { kbd_write(KBD_DATA_REG, 0xF0); kbd_wait_for_input(); kbd_write(KBD_DATA_REG, 0x01); kbd_wait_for_input(); } kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return( 6 ); // Finally, set the typematic rate to maximum. kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return( 7 ); kbd_write(KBD_DATA_REG, 0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) return( 8 ); return( 0 ); } //--------------------------------------------------------------------------- // KeyMode -- set keyboard modes. //--------------------------------------------------------------------------- void KeyMode( int mode, int arg ) { switch (mode) { case KEYMODE_RAW: kbd_raw = 1; break; case KEYMODE_COOKED: kbd_raw = 0; break; case KEYMODE_LEDS: kbd_pckbd_leds( (unsigned char) arg ); break; } } //--------------------------------------------------------------------------- // KeyInit -- initialize keyboard. //--------------------------------------------------------------------------- void KeyInit(void) { int status; /* Flush any pending input. */ kbd_clear_input(); status = initialize_kbd(); if (status) PRINT("Keyboard initialize error: %d\n", status); KeyMode( KEYMODE_COOKED, 0 ); } //--------------------------------------------------------------------------- // KeyGet -- get a key from the keyboard. //--------------------------------------------------------------------------- unsigned char KeyGet( void ) { return( kbd_wait_for_input() ); } //=========================================================================== #include "pciLib.h" extern int FindPCIDeviceClass( int WantClass, unsigned long *cfa ); #include "iso_font.h" char *vidmem = (unsigned char *) 0xfd0b8000; static int VGA_init_done = 0; static const int lines = 25; static const int cols = 80; int cur_col = 0; int cur_line = 0; /* * VGA Register */ struct VgaRegs { unsigned short io_port; unsigned char io_index; unsigned char io_value; }; /* * Default console text mode registers used to reset * graphics adapter. */ #define NREGS 54 #define ENDMK 0xFFFF /* End marker */ #define S3Vendor 0x5333 #define CirrusVendor 0x1013 #define DiamondVendor 0x100E #define MatroxVendor 0x102B #define MediaVision 0x10C7 #define ParadiseVendor 0x101C struct VgaRegs GenVgaTextRegs[NREGS+1] = { /* port index value */ /* SR Regs */ 0x3c4, 0x1, 0x0, 0x3c4, 0x2, 0x3, 0x3c4, 0x3, 0x0, 0x3c4, 0x4, 0x2, /* CR Regs */ 0x3d4, 0x0, 0x5f, 0x3d4, 0x1, 0x4f, 0x3d4, 0x2, 0x50, 0x3d4, 0x3, 0x82, 0x3d4, 0x4, 0x55, 0x3d4, 0x5, 0x81, 0x3d4, 0x6, 0xbf, 0x3d4, 0x7, 0x1f, 0x3d4, 0x8, 0x00, 0x3d4, 0x9, 0x4f, 0x3d4, 0xa, 0x0d, 0x3d4, 0xb, 0x0e, 0x3d4, 0xc, 0x00, 0x3d4, 0xd, 0x00, 0x3d4, 0xe, 0x00, 0x3d4, 0xf, 0x00, 0x3d4, 0x10, 0x9c, 0x3d4, 0x11, 0x8e, 0x3d4, 0x12, 0x8f, 0x3d4, 0x13, 0x28, 0x3d4, 0x14, 0x1f, 0x3d4, 0x15, 0x96, 0x3d4, 0x16, 0xb9, 0x3d4, 0x17, 0xa3, /* GR Regs */ 0x3ce, 0x0, 0x0, 0x3ce, 0x1, 0x0, 0x3ce, 0x2, 0x0, 0x3ce, 0x3, 0x0, 0x3ce, 0x4, 0x0, 0x3ce, 0x5, 0x10, 0x3ce, 0x6, 0xe, 0x3ce, 0x7, 0x0, 0x3ce, 0x8, 0xff, ENDMK }; struct VgaRegs S3TextRegs[NREGS+1] = { /* port index value */ /* SR Regs */ 0x3c4, 0x1, 0x0, 0x3c4, 0x2, 0x3, 0x3c4, 0x3, 0x0, 0x3c4, 0x4, 0x2, /* CR Regs */ 0x3d4, 0x0, 0x5f, 0x3d4, 0x1, 0x4f, 0x3d4, 0x2, 0x50, 0x3d4, 0x3, 0x82, 0x3d4, 0x4, 0x55, 0x3d4, 0x5, 0x81, 0x3d4, 0x6, 0xbf, 0x3d4, 0x7, 0x1f, 0x3d4, 0x8, 0x00, 0x3d4, 0x9, 0x4f, 0x3d4, 0xa, 0x0d, 0x3d4, 0xb, 0x0e, 0x3d4, 0xc, 0x00, 0x3d4, 0xd, 0x00, 0x3d4, 0xe, 0x00, 0x3d4, 0xf, 0x00, 0x3d4, 0x10, 0x9c, 0x3d4, 0x11, 0x8e, 0x3d4, 0x12, 0x8f, 0x3d4, 0x13, 0x28, 0x3d4, 0x14, 0x1f, 0x3d4, 0x15, 0x96, 0x3d4, 0x16, 0xb9, 0x3d4, 0x17, 0xa3, /* GR Regs */ 0x3ce, 0x0, 0x0, 0x3ce, 0x1, 0x0, 0x3ce, 0x2, 0x0, 0x3ce, 0x3, 0x0, 0x3ce, 0x4, 0x0, 0x3ce, 0x5, 0x10, 0x3ce, 0x6, 0xe, 0x3ce, 0x7, 0x0, 0x3ce, 0x8, 0xff, ENDMK }; struct RGBColors { unsigned char r, g, b; }; /* * Default console text mode color table. * These values were obtained by booting Linux with * text mode firmware & then dumping the registers. */ struct RGBColors TextCLUT[256] = { /* red green blue */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x2a, 0x0, 0x0, 0x2a, 0x2a, 0x2a, 0x0, 0x0, 0x2a, 0x0, 0x2a, 0x2a, 0x2a, 0x0, 0x2a, 0x2a, 0x2a, 0x0, 0x0, 0x15, 0x0, 0x0, 0x3f, 0x0, 0x2a, 0x15, 0x0, 0x2a, 0x3f, 0x2a, 0x0, 0x15, 0x2a, 0x0, 0x3f, 0x2a, 0x2a, 0x15, 0x2a, 0x2a, 0x3f, 0x0, 0x15, 0x0, 0x0, 0x15, 0x2a, 0x0, 0x3f, 0x0, 0x0, 0x3f, 0x2a, 0x2a, 0x15, 0x0, 0x2a, 0x15, 0x2a, 0x2a, 0x3f, 0x0, 0x2a, 0x3f, 0x2a, 0x0, 0x15, 0x15, 0x0, 0x15, 0x3f, 0x0, 0x3f, 0x15, 0x0, 0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x2a, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x2a, 0x3f, 0x3f, 0x15, 0x0, 0x0, 0x15, 0x0, 0x2a, 0x15, 0x2a, 0x0, 0x15, 0x2a, 0x2a, 0x3f, 0x0, 0x0, 0x3f, 0x0, 0x2a, 0x3f, 0x2a, 0x0, 0x3f, 0x2a, 0x2a, 0x15, 0x0, 0x15, 0x15, 0x0, 0x3f, 0x15, 0x2a, 0x15, 0x15, 0x2a, 0x3f, 0x3f, 0x0, 0x15, 0x3f, 0x0, 0x3f, 0x3f, 0x2a, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x15, 0x0, 0x15, 0x15, 0x2a, 0x15, 0x3f, 0x0, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x0, 0x3f, 0x15, 0x2a, 0x3f, 0x3f, 0x0, 0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x15, 0x3f, 0x15, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x15, 0x3f, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x3f, 0x3f, 0x3f, 0x39, 0xc, 0x5, 0x15, 0x2c, 0xf, 0x26, 0x10, 0x3d, 0x29, 0x29, 0x38, 0x4, 0x1a, 0xe, 0x2, 0x1e, 0x3a, 0x3c, 0x25, 0x33, 0x3c, 0xc, 0x2c, 0x3f, 0x3, 0x2b, 0x1c, 0x9, 0x13, 0x25, 0x2a, 0x35, 0x1e, 0xa, 0x38, 0x24, 0x8, 0x3, 0x3, 0xe, 0x36, 0xc, 0x6, 0x2a, 0x26, 0x3, 0x32, 0x5, 0x2f, 0x33, 0x3c, 0x35, 0x2f, 0x2d, 0x26, 0x3e, 0xd, 0xa, 0x10, 0x25, 0x3c, 0x11, 0xd, 0x4, 0x2e, 0x5, 0x19, 0x3e, 0xc, 0x13, 0x34, 0x2b, 0x6, 0x24, 0x4, 0x3, 0xd, 0x2f, 0x3c, 0xc, 0x2a, 0x37, 0x1f, 0xf, 0x12, 0x38, 0x38, 0xe, 0x2a, 0x12, 0x2f, 0x19, 0x29, 0x2e, 0x31, 0x25, 0x13, 0x3e, 0x33, 0x3e, 0x33, 0x1d, 0x2c, 0x25, 0x15, 0x15, 0x5, 0x32, 0x25, 0x39, 0x1a, 0x7, 0x1f, 0x13, 0xe, 0x1d, 0x36, 0x17, 0x34, 0xf, 0x15, 0x23, 0x2, 0x35, 0xd, 0x15, 0x3f, 0xc, 0x14, 0x2f, 0xf, 0x19, 0x21, 0x3e, 0x27, 0x11, 0x2f, 0x38, 0x3f, 0x3c, 0x36, 0x2d, 0x15, 0x16, 0x17, 0x2, 0x1, 0xa, 0x3d, 0x1b, 0x11, 0x3f, 0x21, 0x3c, 0xd, 0x1a, 0x39, 0x3d, 0x8, 0xe, 0xe, 0x22, 0x21, 0x23, 0x1e, 0x30, 0x5, 0x1f, 0x22, 0x3d, 0x1e, 0x2f, 0xa, 0x0, 0x1c, 0xe, 0x0, 0x1c, 0x15, 0x0, 0x1c, 0x1c, 0x0, 0x15, 0x1c, 0x0, 0xe, 0x1c, 0x0, 0x7, 0x1c, 0xe, 0xe, 0x1c, 0x11, 0xe, 0x1c, 0x15, 0xe, 0x1c, 0x18, 0xe, 0x1c, 0x1c, 0xe, 0x1c, 0x1c, 0xe, 0x18, 0x1c, 0xe, 0x15, 0x1c, 0xe, 0x11, 0x1c, 0xe, 0xe, 0x1c, 0x11, 0xe, 0x1c, 0x15, 0xe, 0x1c, 0x18, 0xe, 0x1c, 0x1c, 0xe, 0x18, 0x1c, 0xe, 0x15, 0x1c, 0xe, 0x11, 0x1c, 0xe, 0xe, 0x1c, 0xe, 0xe, 0x1c, 0x11, 0xe, 0x1c, 0x15, 0xe, 0x1c, 0x18, 0xe, 0x1c, 0x1c, 0xe, 0x18, 0x1c, 0xe, 0x15, 0x1c, 0xe, 0x11, 0x1c, 0x14, 0x14, 0x1c, 0x16, 0x14, 0x1c, 0x18, 0x14, 0x1c, 0x1a, 0x14, 0x1c, 0x1c, 0x14, 0x1c, 0x1c, 0x14, 0x1a, 0x1c, 0x14, 0x18, 0x1c, 0x14, 0x16, 0x1c, 0x14, 0x14, 0x1c, 0x16, 0x14, 0x1c, 0x18, 0x14, 0x1c, 0x1a, 0x14, 0x1c, 0x1c, 0x14, 0x1a, 0x1c, 0x14, 0x18, 0x1c, 0x14, 0x16, 0x1c, 0x14, 0x14, 0x1c, 0x14, 0x14, 0x1c, 0x16, 0x14, 0x1c, 0x18, 0x14, 0x1c, 0x1a, 0x14, 0x1c, 0x1c, 0x14, 0x1a, 0x1c, 0x14, 0x18, 0x1c, 0x14, 0x16, 0x1c, 0x0, 0x0, 0x10, 0x4, 0x0, 0x10, 0x8, 0x0, 0x10, 0xc, 0x0, 0x10, 0x10, 0x0, 0x10, 0x10, 0x0, 0xc, 0x10, 0x0, 0x8, 0x10, 0x0, 0x4, 0x10, 0x0, 0x0, 0x10, 0x4, 0x0, 0x10, 0x8, 0x0, 0x10, 0xc, 0x0, 0x10, 0x10, 0x0, 0xc, 0x10, 0x0, 0x8, 0x10, 0x0, 0x4, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x10, 0x4, 0x0, 0x10, 0x8, 0x0, 0x10, 0xc, 0x0, 0x10, 0x10, 0x0, 0xc, 0x10, 0x0, 0x8, 0x10, 0x0, 0x4, 0x10, 0x8, 0x8, 0x10, 0xa, 0x8, 0x10, 0xc, 0x8, 0x10, 0xe, 0x8, 0x10, 0x10, 0x8, 0x10, 0x10, 0x8, 0xe, 0x10, 0x8, 0xc, 0x10, 0x8, 0xa, 0x10, 0x8, 0x8, 0x10, 0xa, 0x8, 0x10, 0xc, 0x8, 0x10, 0xe, 0x8, 0x10, 0x10, 0x8, 0xe, 0x10, 0x8, 0xc, 0x10, 0x8, 0xa, 0x10, 0x8, 0x8, 0x10, 0x8, 0x8, 0x10, 0xa, 0x8, 0x10, 0xc, 0x8, 0x10, 0xe, 0x8, 0x10, 0x10, 0x8, 0xe, 0x10, 0x8, 0xc, 0x10, 0x8, 0xa, 0x10, 0xb, 0xb, 0x10, 0xc, 0xb, 0x10, 0xd, 0xb, 0x10, 0xf, 0xb, 0x10, 0x10, 0xb, 0x10, 0x10, 0xb, 0xf, 0x10, 0xb, 0xd, 0x10, 0xb, 0xc, 0x10, 0xb, 0xb, 0x10, 0xc, 0xb, 0x10, 0xd, 0xb, 0x10, 0xf, 0xb, 0x10, 0x10, 0xb, 0xf, 0x10, 0xb, 0xd, 0x10, 0xb, 0xc, 0x10, 0xb, 0xb, 0x10, 0xb, 0xb, 0x10, 0xc, 0xb, 0x10, 0xd, 0xb, 0x10, 0xf, 0xb, 0x10, 0x10, 0xb, 0xf, 0x10, 0xb, 0xd, 0x10, 0xb, 0xc, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; unsigned char AC[21] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}; static void unlockS3(void); //--------------------------------------------------------------------------- void outb_p( char b, unsigned long addr ) { unsigned char *a; a = addr + (unsigned char *) IO_Base; *a = b; } //--------------------------------------------------------------------------- void outb( unsigned long addr, char b ) { outb_p( b, addr ); } //--------------------------------------------------------------------------- char inb_p( unsigned long addr ) { unsigned char *a; a = addr + (unsigned char *) IO_Base; return( *a ); } //--------------------------------------------------------------------------- char inb( unsigned long addr ) { return( inb_p( addr ) ); } //--------------------------------------------------------------------------- static outw(int port, unsigned short val) { outb(port, val >> 8); outb(port+1, val); } //--------------------------------------------------------------------------- int vga_init(unsigned char *ISA_mem, int force_slot ) { int slot; unsigned long cfa, Vendor; struct VgaRegs *VgaTextRegs; // See if VGA already in TEXT mode - exit if so! outb(0x3CE, 0x06); if ((inb(0x3CF) & 0x01) == 0) return( 1 ); // If no VGA responding in text mode, then we have some work to do... // // Scan the slots for a PCI graphics adapter. slot = FindPCIDeviceClass( PCI_CLASS_DISPLAY, &cfa ); if (slot == 0) { if (force_slot) slot = force_slot; else return( 0 ); } unlockVideo(slot); /* enable I/O to card */ VgaTextRegs = GenVgaTextRegs; Vendor = pReadAReg( slot, 0 ); switch (Vendor) { case S3Vendor: unlockS3(); VgaTextRegs = S3TextRegs; break; case MatroxVendor: outb(0x3c2, 0x67); /* unlock ext regs */ break; case DiamondVendor: case CirrusVendor: outw(0x3C4, 0x0612); /* unlock ext regs */ outw(0x3C4, 0x0700); /* reset ext sequence mode */ outb(0x3c2, 0x67); /* unlock ext regs */ break; case ParadiseVendor: /* IBM Portable 850 */ outw(0x3ce, 0x0f05); /* unlock pardise registers */ outw(0x3c4, 0x0648); outw(0x3d4, 0x2985); outw(0x3d4, 0x34a6); outb(0x3ce, 0x0b); /* disable linear addressing */ outb(0x3cf, inb(0x3cf) & ~0x30); outw(0x3c4, 0x1400); outb(0x3ce, 0x0e); /* disable 256 color mode */ outb(0x3cf, inb(0x3cf) & ~0x01); outb(0xd00, 0xff); /* enable auto-centering */ if (!(inb(0xd01) & 0x03)) { outb(0x3d4, 0x33); outb(0x3d5, inb(0x3d5) & ~0x90); outb(0x3d4, 0x32); outb(0x3d5, inb(0x3d5) | 0x04); outw(0x3d4, 0x0250); outw(0x3d4, 0x07ba); outw(0x3d4, 0x0900); outw(0x3d4, 0x15e7); outw(0x3d4, 0x2a95); } outw(0x3d4, 0x34a0); break; case 0xFFFF: // No VGA (if we were 'force'd) return( 0 ); default: break; } outw(0x3C4, 0x0120); // disable video setTextRegs(VgaTextRegs); // initial register setup setTextCLUT(0); // load color lookup table loadFont(ISA_mem); // load font setTextRegs(VgaTextRegs); // reload registers outw(0x3C4, 0x0100); // re-enable video if (Vendor == S3Vendor) { outb(0x3c2, 0x63); // MISC } clearVideoMemory(); mdelay(1000); // give time for the video monitor to come up return (1); // 'CRT' I/O supported } //--------------------------------------------------------------------------- // writeAttr -- Write to VGA Attribute registers. //--------------------------------------------------------------------------- writeAttr(index, data, videoOn) unsigned char index; unsigned char data; unsigned char videoOn; /* video on flag */ { unsigned char v; v = inb(0x3da); /* reset attr. address toggle */ if (videoOn) outb(0x3c0, (index & 0x1F) | 0x20); else outb(0x3c0, (index & 0x1F)); outb(0x3c0, data); } //--------------------------------------------------------------------------- setTextRegs(struct VgaRegs *svp) { int i; while( svp->io_port != ENDMK ) { outb(svp->io_port, svp->io_index); outb(svp->io_port+1, svp->io_value); svp++; } outb(0x3c2, 0x67); /* MISC */ outb(0x3c6, 0xff); /* MASK */ for ( i = 0; i < 0x10; i++) writeAttr(i, AC[i], 0); /* pallete */ writeAttr(0x10, 0x0c, 0); /* text mode */ writeAttr(0x11, 0x00, 0); /* overscan color (border) */ writeAttr(0x12, 0x0f, 0); /* plane enable */ writeAttr(0x13, 0x08, 0); /* pixel panning */ writeAttr(0x14, 0x00, 1); /* color select; video on */ } //--------------------------------------------------------------------------- setTextCLUT(int shift) { int i; outb(0x3C6, 0xFF); i = inb(0x3C7); outb(0x3C8, 0); i = inb(0x3C7); for ( i = 0; i < 256; i++) { outb(0x3C9, TextCLUT[i].r << shift); outb(0x3C9, TextCLUT[i].g << shift); outb(0x3C9, TextCLUT[i].b << shift); } } //--------------------------------------------------------------------------- loadFont(unsigned char *ISA_mem) { int i, j; unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; outb(0x3C2, 0x67); /* * Load font */ i = inb(0x3DA); /* Reset Attr toggle */ outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */ outw(0x3C4, 0x0001); /* reset sequencer */ outw(0x3C4, 0x0204); /* write to plane 2 */ outw(0x3C4, 0x0406); /* enable plane graphics */ outw(0x3C4, 0x0003); /* reset sequencer */ outw(0x3CE, 0x0402); /* read plane 2 */ outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ outw(0x3CE, 0x0605); /* set graphics mode */ for (i = 0; i < sizeof(font); i += 16) { for (j = 0; j < 16; j++) { font_page[(2*i)+j] = font[i+j]; } } } //--------------------------------------------------------------------------- static void unlockS3(void) { int s3_device_id; outw(0x3d4, 0x3848); outw(0x3d4, 0x39a5); outb(0x3d4, 0x2d); s3_device_id = inb(0x3d5) << 8; outb(0x3d4, 0x2e); s3_device_id |= inb(0x3d5); if (s3_device_id != 0x8812) { /* From the S3 manual */ outb(0x46E8, 0x10); /* Put into setup mode */ outb(0x3C3, 0x10); outb(0x102, 0x01); /* Enable registers */ outb(0x46E8, 0x08); /* Enable video */ outb(0x3C3, 0x08); outb(0x4AE8, 0x00); outb(0x42E8, 0x80); /* Reset graphics engine? */ #if 0 #endif outb(0x3D4, 0x38); /* Unlock all registers */ outb(0x3D5, 0x48); outb(0x3D4, 0x39); outb(0x3D5, 0xA5); outb(0x3D4, 0x40); outb(0x3D5, inb(0x3D5)|0x01); outb(0x3D4, 0x33); outb(0x3D5, inb(0x3D5)&~0x52); outb(0x3D4, 0x35); outb(0x3D5, inb(0x3D5)&~0x30); outb(0x3D4, 0x3A); outb(0x3D5, 0x00); outb(0x3D4, 0x53); outb(0x3D5, 0x00); outb(0x3D4, 0x31); outb(0x3D5, inb(0x3D5)&~0x4B); outb(0x3D4, 0x58); outb(0x3D5, 0); outb(0x3D4, 0x54); outb(0x3D5, 0x38); outb(0x3D4, 0x60); outb(0x3D5, 0x07); outb(0x3D4, 0x61); outb(0x3D5, 0x80); outb(0x3D4, 0x62); outb(0x3D5, 0xA1); outb(0x3D4, 0x69); /* High order bits for cursor address */ outb(0x3D5, 0); outb(0x3D4, 0x32); outb(0x3D5, inb(0x3D5)&~0x10); } else { outw(0x3c4, 0x0806); /* IBM Portable 860 */ outw(0x3c4, 0x1041); outw(0x3c4, 0x1128); outw(0x3d4, 0x4000); outw(0x3d4, 0x3100); outw(0x3d4, 0x3a05); outw(0x3d4, 0x6688); outw(0x3d4, 0x5800); /* disable linear addressing */ outw(0x3d4, 0x4500); /* disable H/W cursor */ outw(0x3c4, 0x5410); /* enable auto-centering */ outw(0x3c4, 0x561f); outw(0x3c4, 0x1b80); /* lock DCLK selection */ outw(0x3d4, 0x3900); /* lock S3 registers */ outw(0x3d4, 0x3800); } } //--------------------------------------------------------------------------- // cursor -- set the cursor to the given row/col. //--------------------------------------------------------------------------- void cursor(int col, int row) { int pos = (row*cols)+col; outb(0x3D4, 14); outb(0x3D5, pos >> 8); outb(0x3D4, 15); outb(0x3D5, pos); } //--------------------------------------------------------------------------- clearVideoMemory() { int i, j; for (i = 0; i < lines; i++) { for (j = 0; j < cols; j++) { vidmem[((i*cols)+j)*2] = 0x20; // fill with space character vidmem[((i*cols)+j)*2+1] = 0x07; // set bg & fg attributes } } } //--------------------------------------------------------------------------- // unlockVideo -- modify the PCI Command register to enable memory and // I/O accesses. //--------------------------------------------------------------------------- unlockVideo( slot ) { unsigned long val; val = pReadAReg( slot, 2 ); val |= 0x03; // Enable IO and MEM pWriteAReg( slot, 2, val ); val = 0x000A0000; pWriteAReg( slot, 12, val ); val = 0x00000000; pWriteAReg( slot, 13, val ); pWriteAReg( slot, 14, val ); pWriteAReg( slot, 15, val ); // unlock CR0-CR7 outb( 0x3d4, 0x11 ); outb( 0x3d5, 0x0e ); } //--------------------------------------------------------------------------- // ScrollVGA -- scroll the display area. //--------------------------------------------------------------------------- void ScrollVGA() { int c, sl, dl; // Move everything up one line, including attributes. for (sl = 1, dl = 0; sl <= cur_line; sl++, dl++) { for (c = 0; c < cols; c++) { vidmem[(( dl * cols)+c)*2 ] = vidmem[(( sl * cols)+c)*2 ]; vidmem[(( dl * cols)+c)*2+1 ] = vidmem[(( sl * cols)+c)*2+1 ]; } } // Erase the last line. for (c = 0; c < cols; c++) { vidmem[((cur_line*cols)+c)*2 ] = 0x20; vidmem[((cur_line*cols)+c)*2+1 ] = 0x07; } } //--------------------------------------------------------------------------- // VGAOutput -- print character to VGA. //--------------------------------------------------------------------------- void VGAOutput( char c ) { if (!VGA_init_done) return; if (c == '\n') // Newline cur_line++; else if (c == '\r') // Return cur_col = 0; else if (c == '\b') { // Backspace cur_col--; if (cur_col < 0) cur_col = 0; } else if (c == '\t') // Tab while ((cur_col % 8) && (cur_col < cols)) { vidmem[((cur_line*cols)+cur_col)*2 ] = ' '; cur_col++; } else { vidmem[((cur_line*cols)+cur_col)*2 ] = c; vidmem[((cur_line*cols)+cur_col)*2+1] = 0x07; if (cur_col == 0) { vidmem[((cur_line*cols)+cur_col)*2 ] = c; vidmem[((cur_line*cols)+cur_col)*2+1] = 0x07; } cur_col++; } // Need to scroll? if (cur_col >= cols) { cur_col = 0; cur_line++; } if (cur_line >= lines) { cur_line = lines-1; ScrollVGA(); } cursor( cur_col, cur_line ); } //--------------------------------------------------------------------------- // VGAInit -- initialize video. //--------------------------------------------------------------------------- int VGAInit( char *arg ) { unsigned char *ISA_mem; int Force_slot; if (*arg == ':') arg++; // One possible argument to "XIO:" is "USE=nn", where nn is the slot // where an VGA card is found. This is needed when the PCI device // does not implement class codes. Force_slot = 0; if (*arg && (strncmp( arg, "USE=", 4 ) == 0)) { arg += 4; Force_slot = strtol( arg, &arg, 10 ); } // All ready, try to activate the VGA card. ISA_mem = (unsigned char *) 0xFD000000; if (!vga_init( ISA_mem, Force_slot )) return( 0 ); clearVideoMemory(); VGA_init_done++; return( 1 ); }