URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [console.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * linux/drivers/char/console.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * console.c * * This module exports the console io functions: * * 'void do_keyboard_interrupt(void)' * * 'int vc_allocate(unsigned int console)' * 'int vc_cons_allocated(unsigned int console)' * 'int vc_resize(unsigned long lines, unsigned long cols)' * 'void vc_disallocate(unsigned int currcons)' * * 'unsigned long con_init(unsigned long)' * 'int con_open(struct tty_struct *tty, struct file * filp)' * 'void con_write(struct tty_struct * tty)' * 'void console_print(const char * b)' * 'void update_screen(int new_console)' * * 'void do_blank_screen(int)' * 'void do_unblank_screen(void)' * 'void poke_blanked_console(void)' * * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)' * 'void complement_pos(int currcons, int offset)' * 'void invert_screen(int currcons, int offset, int count, int shift)' * * 'void scrollback(int lines)' * 'void scrollfront(int lines)' * * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)' * 'int mouse_reporting(void)' * * Hopefully this will be a rather complete VT102 implementation. * * Beeping thanks to John T Kohl. * * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics * Chars, and VT100 enhancements by Peter MacDonald. * * Copy and paste function by Andrew Haylett, * some enhancements by Alessandro Rubini. * * Code to check for different video-cards mostly by Galen Hunt, * <g-hunt@ee.utah.edu> * * Rudimentary ISO 10646/Unicode/UTF-8 character set support by * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. * * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 * Resizing of consoles, aeb, 940926 * * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 * <poe@daimi.aau.dk> * * User-defined bell sound, new setterm control sequences and printk * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 * * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> * Backported to 2.0.31 by Adam Bradley <artdodge@cs.bu.edu> */ #define BLANK 0x0020 /* A bitmap for codes <32. A bit of 1 indicates that the code * corresponding to that bit number invokes some special action * (such as cursor movement) and should not be displayed as a * glyph unless the disp_ctrl mode is explicitly enabled. */ #define CTRL_ACTION 0x0d00ff81 #define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ /* * Here is the default bell parameters: 750HZ, 1/8th of a second */ #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) /* * NOTE!!! We sometimes disable and enable interrupts for a short while * (to put a word in video IO), but this will work even for keyboard * interrupts. We know interrupts aren't enabled when getting a keyboard * interrupt, as we use trap-gates. Hopefully all is well. */ #include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/kd.h> #include <linux/malloc.h> #include <linux/major.h> #include <linux/mm.h> #include <linux/ioport.h> #ifdef CONFIG_APM #include <linux/apm_bios.h> #endif #include <asm/io.h> #include <asm/system.h> #include <asm/segment.h> #include <asm/bitops.h> #include "kbd_kern.h" #include "vt_kern.h" #include "consolemap.h" #include "selection.h" #include "console_struct.h" #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif struct tty_driver console_driver; static int console_refcount; static struct tty_struct *console_table[MAX_NR_CONSOLES]; static struct termios *console_termios[MAX_NR_CONSOLES]; static struct termios *console_termios_locked[MAX_NR_CONSOLES]; unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; struct vc vc_cons [MAX_NR_CONSOLES]; static void con_setsize(unsigned long rows, unsigned long cols); static void vc_init(unsigned int console, unsigned long rows, unsigned long cols, int do_clear); extern void get_scrmem(int currcons); extern void set_scrmem(int currcons, long offset); static void set_origin(int currcons); static void blank_screen(void); static void unblank_screen(void); extern void change_console(unsigned int); extern void poke_blanked_console(void); static void gotoxy(int currcons, int new_x, int new_y); static void save_cur(int currcons); extern void set_cursor(int currcons); extern void hide_cursor(void); static void reset_terminal(int currcons, int do_clear); extern void reset_vc(unsigned int new_console); extern void vt_init(void); extern void register_console(void (*proc)(const char *)); extern void vesa_blank(void); extern void vesa_unblank(void); extern void vesa_powerdown(void); extern void compute_shiftstate(void); extern void reset_palette(int currcons); extern void set_palette(void); extern unsigned long con_type_init(unsigned long, const char **); extern int set_get_cmap(unsigned char *, int); extern int set_get_font(unsigned char *, int, int); /* Description of the hardware situation */ unsigned char video_type; /* Type of display being used */ unsigned long video_mem_base; /* Base of video memory */ unsigned long video_mem_term; /* End of video memory */ unsigned short video_port_reg; /* Video register select port */ unsigned short video_port_val; /* Video register value port */ unsigned long video_num_columns; /* Number of text columns */ unsigned long video_num_lines; /* Number of text lines */ unsigned long video_size_row; unsigned long video_screen_size; int can_do_color = 0; static int printable = 0; /* Is console ready for printing? */ int video_mode_512ch = 0; /* 512-character mode */ unsigned long video_font_height; /* Height of current screen font */ unsigned long video_scan_lines; /* Number of scan lines on screen */ unsigned long default_font_height; /* Height of default screen font */ int video_font_is_default = 1; static unsigned short console_charmask = 0x0ff; /* used by kbd_bh - set by keyboard_interrupt */ int do_poke_blanked_console = 0; int console_blanked = 0; static int blankinterval = 10*60*HZ; static int vesa_off_interval = 0; static long blank_origin, blank__origin, unblank_origin; #ifdef CONFIG_SERIAL_ECHO #include <linux/serial_reg.h> extern int serial_echo_init (int base); extern int serial_echo_print (const char *s); /* * this defines the address for the port to which printk echoing is done * when CONFIG_SERIAL_ECHO is defined */ #define SERIAL_ECHO_PORT 0x3f8 /* COM1 */ static int serial_echo_port = 0; #define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port) #define serial_echo_inb(a) inb((a)+serial_echo_port) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) /* Wait for transmitter & holding register to empty */ #define WAIT_FOR_XMITR \ do { \ lsr = serial_echo_inb(UART_LSR); \ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY) /* These two functions abstract the actual communications with the * debug port. This is so we can change the underlying communications * mechanism without modifying the rest of the code. */ int serial_echo_print(const char *s) { int lsr, ier; int i; if (!serial_echo_port) return (0); /* * First save the IER then disable the interrupts */ ier = serial_echo_inb(UART_IER); serial_echo_outb(0x00, UART_IER); /* * Now, do each character */ for (i = 0; *s; i++, s++) { WAIT_FOR_XMITR; /* Send the character out. */ serial_echo_outb(*s, UART_TX); /* if a LF, also do CR... */ if (*s == 10) { WAIT_FOR_XMITR; serial_echo_outb(13, UART_TX); } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ do { lsr = serial_echo_inb(UART_LSR); } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); serial_echo_outb(ier, UART_IER); return (0); } int serial_echo_init(int base) { int comstat, hi, lo; if (base != 0x2f8 && base != 0x3f8) { serial_echo_port = 0; return (0); } else serial_echo_port = base; /* * read the Divisor Latch */ comstat = serial_echo_inb(UART_LCR); serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR); hi = serial_echo_inb(UART_DLM); lo = serial_echo_inb(UART_DLL); serial_echo_outb(comstat, UART_LCR); /* * now do hardwired init */ serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */ serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */ serial_echo_outb(0x00, UART_DLM); /* 9600 baud */ serial_echo_outb(0x0c, UART_DLL); serial_echo_outb(0x03, UART_LCR); /* Done with divisor */ /* Prior to disabling interrupts, read the LSR and RBR * registers */ comstat = serial_echo_inb(UART_LSR); /* COM? LSR */ comstat = serial_echo_inb(UART_RX); /* COM? RBR */ serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */ return(0); } #endif /* CONFIG_SERIAL_ECHO */ int vc_cons_allocated(unsigned int i) { return (i < MAX_NR_CONSOLES && vc_cons[i].d); } int vc_allocate(unsigned int i) /* return 0 on success */ { if (i >= MAX_NR_CONSOLES) return -ENXIO; if (!vc_cons[i].d) { long p, q; /* prevent users from taking too much memory */ if (i >= MAX_NR_USER_CONSOLES && !suser()) return -EPERM; /* due to the granularity of kmalloc, we waste some memory here */ /* the alloc is done in two steps, to optimize the common situation of a 25x80 console (structsize=216, video_screen_size=4000) */ q = (long) kmalloc(video_screen_size, GFP_KERNEL); if (!q) return -ENOMEM; p = (long) kmalloc(structsize, GFP_KERNEL); if (!p) { kfree_s((char *) q, video_screen_size); return -ENOMEM; } vc_cons[i].d = (struct vc_data *) p; p += sizeof(struct vc_data); vt_cons[i] = (struct vt_struct *) p; vc_scrbuf[i] = (unsigned short *) q; vc_cons[i].d->vc_kmalloced = 1; vc_cons[i].d->vc_screenbuf_size = video_screen_size; vc_init (i, video_num_lines, video_num_columns, 1); } return 0; } /* * Change # of rows and columns (0 means unchanged) * [this is to be used together with some user program * like resize that changes the hardware videomode] */ int vc_resize(unsigned long lines, unsigned long cols) { unsigned long cc, ll, ss, sr; unsigned long occ, oll, oss, osr; unsigned short *p; unsigned int currcons, i; unsigned short *newscreens[MAX_NR_CONSOLES]; long ol, nl, rlth, rrem; cc = (cols ? cols : video_num_columns); ll = (lines ? lines : video_num_lines); sr = cc << 1; ss = sr * ll; if (ss > video_mem_term - video_mem_base) return -ENOMEM; /* * Some earlier version had all consoles of potentially * different sizes, but that was really messy. * So now we only change if there is room for all consoles * of the same size. */ for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { if (!vc_cons_allocated(currcons)) newscreens[currcons] = 0; else { p = (unsigned short *) kmalloc(ss, GFP_USER); if (!p) { for (i = 0; i< currcons; i++) if (newscreens[i]) kfree_s(newscreens[i], ss); return -ENOMEM; } newscreens[currcons] = p; } } get_scrmem(fg_console); oll = video_num_lines; occ = video_num_columns; osr = video_size_row; oss = video_screen_size; video_num_lines = ll; video_num_columns = cc; video_size_row = sr; video_screen_size = ss; for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { if (!vc_cons_allocated(currcons)) continue; rlth = MIN(osr, sr); rrem = sr - rlth; ol = origin; nl = (long) newscreens[currcons]; if (ll < oll) ol += (oll - ll) * osr; while (ol < scr_end) { memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); if (rrem) memsetw((void *)(nl + rlth), video_erase_char, rrem); ol += osr; nl += sr; } if (kmalloced) kfree_s(vc_scrbuf[currcons], screenbuf_size); vc_scrbuf[currcons] = newscreens[currcons]; kmalloced = 1; screenbuf_size = ss; origin = video_mem_start = (long) vc_scrbuf[currcons]; scr_end = video_mem_end = video_mem_start + ss; if (scr_end > nl) memsetw((void *) nl, video_erase_char, scr_end - nl); /* do part of a reset_terminal() */ top = 0; bottom = video_num_lines; gotoxy(currcons, x, y); save_cur(currcons); } set_scrmem(fg_console, 0); set_origin(fg_console); set_cursor(fg_console); return 0; } void vc_disallocate(unsigned int currcons) { if (vc_cons_allocated(currcons)) { if (kmalloced) kfree_s(vc_scrbuf[currcons], screenbuf_size); if (currcons >= MIN_NR_CONSOLES) kfree_s(vc_cons[currcons].d, structsize); vc_cons[currcons].d = 0; } } #define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) #define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) #define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) #define decarm VC_REPEAT #define decckm VC_CKMODE #define kbdapplic VC_APPLIC #define lnm VC_CRLF /* * this is what the terminal answers to a ESC-Z or csi0c query. */ #define VT100ID "\033[?1;2c" #define VT102ID "\033[?6c" unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; /* the default colour table, for VGA+ colour systems */ int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; /* * gotoxy() must verify all boundaries, because the arguments * might also be negative. If the given position is out of * bounds, the cursor is placed at the nearest margin. */ static void gotoxy(int currcons, int new_x, int new_y) { int min_y, max_y; if (new_x < 0) x = 0; else if (new_x >= video_num_columns) x = video_num_columns - 1; else x = new_x; if (decom) { min_y = top; max_y = bottom; } else { min_y = 0; max_y = video_num_lines; } if (new_y < min_y) y = min_y; else if (new_y >= max_y) y = max_y - 1; else y = new_y; pos = origin + y*video_size_row + (x<<1); need_wrap = 0; } /* for absolute user moves, when decom is set */ static void gotoxay(int currcons, int new_x, int new_y) { gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); } /* * Hardware scrollback support */ extern void __set_origin(unsigned short); unsigned short __real_origin; /* offset of non-scrolled screen */ unsigned short __origin; /* offset of currently displayed screen */ unsigned char has_wrapped; /* all of videomem is data of fg_console */ static unsigned char hardscroll_enabled; static unsigned char hardscroll_disabled_by_init = 0; void no_scroll(char *str, int *ints) { /* * Disabling scrollback is required for the Braillex ib80-piezo * Braille reader made by F.H. Papenmeier (Germany). * Use the "no-scroll" bootflag. */ hardscroll_disabled_by_init = 1; hardscroll_enabled = 0; } static void scrolldelta(int lines) { int new_origin; int last_origin_rel = (((video_mem_term - video_mem_base) / video_num_columns / 2) - (video_num_lines - 1)) * video_num_columns; new_origin = __origin + lines * video_num_columns; if (__origin > __real_origin) new_origin -= last_origin_rel; if (new_origin < 0) { int s_top = __real_origin + video_num_lines*video_num_columns; new_origin += last_origin_rel; if (new_origin < s_top) new_origin = s_top; if (new_origin > last_origin_rel - video_num_columns || has_wrapped == 0) new_origin = 0; else { unsigned short * d = (unsigned short *) video_mem_base; unsigned short * s = d + last_origin_rel; int count = (video_num_lines-1)*video_num_columns; while (count) { count--; scr_writew(scr_readw(d++),s++); } } } else if (new_origin > __real_origin) new_origin = __real_origin; __set_origin(new_origin); } void scrollback(int lines) { if (!lines) lines = video_num_lines/2; scrolldelta(-lines); } void scrollfront(int lines) { if (!lines) lines = video_num_lines/2; scrolldelta(lines); } static void set_origin(int currcons) { if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC && video_type != VIDEO_TYPE_EGAM) return; if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) return; __real_origin = (origin-video_mem_base) >> 1; __set_origin(__real_origin); } static void scrup(int currcons, unsigned int t, unsigned int b, unsigned int nr) { int hardscroll = hardscroll_enabled; if (t+nr >= b) nr = b - t - 1; if (b > video_num_lines || t >= b || nr < 1) return; if (t || b != video_num_lines || nr > 1) hardscroll = 0; if (hardscroll) { origin += video_size_row; pos += video_size_row; scr_end += video_size_row; if (scr_end > video_mem_end) { unsigned short * d = (unsigned short *) video_mem_start; unsigned short * s = (unsigned short *) origin; unsigned int count; count = (video_num_lines-1)*video_num_columns; while (count) { count--; scr_writew(scr_readw(s++),d++); } count = video_num_columns; while (count) { count--; scr_writew(video_erase_char, d++); } scr_end -= origin-video_mem_start; pos -= origin-video_mem_start; origin = video_mem_start; has_scrolled = 1; if (currcons == fg_console) has_wrapped = 1; } else { unsigned short * d; unsigned int count; d = (unsigned short *) (scr_end - video_size_row); count = video_num_columns; while (count) { count--; scr_writew(video_erase_char, d++); } } set_origin(currcons); } else { unsigned short * d = (unsigned short *) (origin+video_size_row*t); unsigned short * s = (unsigned short *) (origin+video_size_row*(t+nr)); memcpyw(d, s, (b-t-nr) * video_size_row); memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); } } static void scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr) { unsigned short *s; unsigned int count; unsigned int step; if (t+nr >= b) nr = b - t - 1; if (b > video_num_lines || t >= b || nr < 1) return; s = (unsigned short *) (origin+video_size_row*(b-nr-1)); step = video_num_columns * nr; count = b - t - nr; while (count--) { memcpyw(s + step, s, video_size_row); s -= video_num_columns; } while (nr--) { s += video_num_columns; memsetw(s, video_erase_char, video_size_row); } has_scrolled = 1; } static void lf(int currcons) { /* don't scroll if above bottom of scrolling region, or * if below scrolling region */ if (y+1 == bottom) scrup(currcons,top,bottom, 1); else if (y < video_num_lines-1) { y++; pos += video_size_row; } need_wrap = 0; } static void ri(int currcons) { /* don't scroll if below top of scrolling region, or * if above scrolling region */ if (y == top) scrdown(currcons,top,bottom, 1); else if (y > 0) { y--; pos -= video_size_row; } need_wrap = 0; } static inline void cr(int currcons) { pos -= x<<1; need_wrap = x = 0; } static inline void bs(int currcons) { if (x) { pos -= 2; x--; need_wrap = 0; } } static inline void del(int currcons) { /* ignored */ } static void csi_J(int currcons, int vpar) { unsigned long count; unsigned short * start; switch (vpar) { case 0: /* erase from cursor to end of display */ count = (scr_end-pos)>>1; start = (unsigned short *) pos; break; case 1: /* erase from start to cursor */ count = ((pos-origin)>>1)+1; start = (unsigned short *) origin; break; case 2: /* erase whole display */ count = video_num_columns * video_num_lines; start = (unsigned short *) origin; break; default: return; } while (count) { count--; scr_writew(video_erase_char, start++); } need_wrap = 0; } static void csi_K(int currcons, int vpar) { unsigned long count; unsigned short * start; switch (vpar) { case 0: /* erase from cursor to end of line */ count = video_num_columns-x; start = (unsigned short *) pos; break; case 1: /* erase from start of line to cursor */ start = (unsigned short *) (pos - (x<<1)); count = x+1; break; case 2: /* erase whole line */ start = (unsigned short *) (pos - (x<<1)); count = video_num_columns; break; default: return; } while (count) { count--; scr_writew(video_erase_char, start++); } need_wrap = 0; } static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ { /* not vt100? */ unsigned long count; unsigned short * start; if (!vpar) vpar++; start = (unsigned short *) pos; count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; while (count) { count--; scr_writew(video_erase_char, start++); } need_wrap = 0; } static void update_attr(int currcons) { attr = color; if (can_do_color) { if (underline) attr = (attr & 0xf0) | ulcolor; else if (intensity == 0) attr = (attr & 0xf0) | halfcolor; } if (reverse ^ decscnm) attr = reverse_video_char(attr); if (blink) attr ^= 0x80; if (intensity == 2) attr ^= 0x08; if (!can_do_color) { if (underline) attr = (attr & 0xf8) | 0x01; else if (intensity == 0) attr = (attr & 0xf0) | 0x08; } if (decscnm) video_erase_char = (reverse_video_char(color) << 8) | ' '; else video_erase_char = (color << 8) | ' '; } static void default_attr(int currcons) { intensity = 1; underline = 0; reverse = 0; blink = 0; color = def_color; } static void csi_m(int currcons) { int i; for (i=0;i<=npar;i++) switch (par[i]) { case 0: /* all attributes off */ default_attr(currcons); break; case 1: intensity = 2; break; case 2: intensity = 0; break; case 4: underline = 1; break; case 5: blink = 1; break; case 7: reverse = 1; break; case 10: /* ANSI X3.64-1979 (SCO-ish?) * Select primary font, don't display * control chars if defined, don't set * bit 8 on output. */ translate = set_translate(charset == 0 ? G0_charset : G1_charset); disp_ctrl = 0; toggle_meta = 0; break; case 11: /* ANSI X3.64-1979 (SCO-ish?) * Select first alternate font, lets * chars < 32 be displayed as ROM chars. */ translate = set_translate(IBMPC_MAP); disp_ctrl = 1; toggle_meta = 0; break; case 12: /* ANSI X3.64-1979 (SCO-ish?) * Select second alternate font, toggle * high bit before displaying as ROM char. */ translate = set_translate(IBMPC_MAP); disp_ctrl = 1; toggle_meta = 1; break; case 21: case 22: intensity = 1; break; case 24: underline = 0; break; case 25: blink = 0; break; case 27: reverse = 0; break; case 38: /* ANSI X3.64-1979 (SCO-ish?) * Enables underscore, white foreground * with white underscore (Linux - use * default foreground). */ color = (def_color & 0x0f) | background; underline = 1; break; case 39: /* ANSI X3.64-1979 (SCO-ish?) * Disable underline option. * Reset colour to default? It did this * before... */ color = (def_color & 0x0f) | background; underline = 0; break; case 49: color = (def_color & 0xf0) | foreground; break; default: if (par[i] >= 30 && par[i] <= 37) color = color_table[par[i]-30] | background; else if (par[i] >= 40 && par[i] <= 47) color = (color_table[par[i]-40]<<4) | foreground; break; } update_attr(currcons); } static void respond_string(const char * p, struct tty_struct * tty) { while (*p) { tty_insert_flip_char(tty, *p, 0); p++; } tty_schedule_flip(tty); } static void cursor_report(int currcons, struct tty_struct * tty) { char buf[40]; sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1); respond_string(buf, tty); } static inline void status_report(struct tty_struct * tty) { respond_string("\033[0n", tty); /* Terminal ok */ } static inline void respond_ID(struct tty_struct * tty) { respond_string(VT102ID, tty); } void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) { char buf[8]; sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), (char)('!' + mry)); respond_string(buf, tty); } /* invoked via ioctl(TIOCLINUX) */ int mouse_reporting(void) { int currcons = fg_console; return report_mouse; } static inline unsigned short *screenpos(int currcons, int offset, int viewed) { unsigned short *p = (unsigned short *)(origin + offset); if (viewed && currcons == fg_console) p -= (__real_origin - __origin); return p; } /* Note: inverting the screen twice should revert to the original state */ void invert_screen(int currcons, int offset, int count, int viewed) { unsigned short *p; count /= 2; p = screenpos(currcons, offset, viewed); if (can_do_color) while (count--) { unsigned short old = scr_readw(p); scr_writew(reverse_video_short(old), p); p++; } else while (count--) { unsigned short old = scr_readw(p); scr_writew(old ^ (((old & 0x0700) == 0x0100) ? 0x7000 : 0x7700), p); p++; } } /* used by selection: complement pointer position */ void complement_pos(int currcons, int offset) { static unsigned short *p = NULL; static unsigned short old = 0; if (p) scr_writew(old, p); if (offset == -1) p = NULL; else { p = screenpos(currcons, offset, 1); old = scr_readw(p); scr_writew(old ^ 0x7700, p); } } /* used by selection */ unsigned short screen_word(int currcons, int offset, int viewed) { return scr_readw(screenpos(currcons, offset, viewed)); } /* used by selection - convert a screen word to a glyph number */ int scrw2glyph(unsigned short scr_word) { return ( video_mode_512ch ) ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff) : scr_word & 0x00ff; } /* used by vcs - note the word offset */ unsigned short *screen_pos(int currcons, int w_offset, int viewed) { return screenpos(currcons, 2 * w_offset, viewed); } void getconsxy(int currcons, char *p) { p[0] = x; p[1] = y; } void putconsxy(int currcons, char *p) { gotoxy(currcons, p[0], p[1]); set_cursor(currcons); } static void set_mode(int currcons, int on_off) { int i; for (i=0; i<=npar; i++) if (ques) switch(par[i]) { /* DEC private modes set/reset */ case 1: /* Cursor keys send ^[Ox/^[[x */ if (on_off) set_kbd(decckm); else clr_kbd(decckm); break; case 3: /* 80/132 mode switch unimplemented */ deccolm = on_off; #if 0 (void) vc_resize(video_num_lines, deccolm ? 132 : 80); /* this alone does not suffice; some user mode utility has to change the hardware regs */ #endif break; case 5: /* Inverted screen on/off */ if (decscnm != on_off) { decscnm = on_off; invert_screen(currcons, 0, video_screen_size, 0); update_attr(currcons); } break; case 6: /* Origin relative/absolute */ decom = on_off; gotoxay(currcons,0,0); break; case 7: /* Autowrap on/off */ decawm = on_off; break; case 8: /* Autorepeat on/off */ if (on_off) set_kbd(decarm); else clr_kbd(decarm); break; case 9: report_mouse = on_off ? 1 : 0; break; case 25: /* Cursor on/off */ deccm = on_off; set_cursor(currcons); break; case 1000: report_mouse = on_off ? 2 : 0; break; } else switch(par[i]) { /* ANSI modes set/reset */ case 3: /* Monitor (display ctrls) */ disp_ctrl = on_off; break; case 4: /* Insert Mode on/off */ decim = on_off; break; case 20: /* Lf, Enter == CrLf/Lf */ if (on_off) set_kbd(lnm); else clr_kbd(lnm); break; } } static void setterm_command(int currcons) { switch(par[0]) { case 1: /* set color for underline mode */ if (can_do_color && par[1] < 16) { ulcolor = color_table[par[1]]; if (underline) update_attr(currcons); } break; case 2: /* set color for half intensity mode */ if (can_do_color && par[1] < 16) { halfcolor = color_table[par[1]]; if (intensity == 0) update_attr(currcons); } break; case 8: /* store colors as defaults */ def_color = attr; default_attr(currcons); update_attr(currcons); break; case 9: /* set blanking interval */ blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; poke_blanked_console(); break; case 10: /* set bell frequency in Hz */ if (npar >= 1) bell_pitch = par[1]; else bell_pitch = DEFAULT_BELL_PITCH; break; case 11: /* set bell duration in msec */ if (npar >= 1) bell_duration = (par[1] < 2000) ? par[1]*HZ/1000 : 0; else bell_duration = DEFAULT_BELL_DURATION; break; case 12: /* bring specified console to the front */ if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) update_screen(par[1]-1); break; case 13: /* unblank the screen */ unblank_screen(); break; case 14: /* set vesa powerdown interval */ vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; break; } } static void insert_char(int currcons) { unsigned int i = x; unsigned short tmp, old = video_erase_char; unsigned short * p = (unsigned short *) pos; while (i++ < video_num_columns) { tmp = scr_readw(p); scr_writew(old, p); old = tmp; p++; } need_wrap = 0; } static void insert_line(int currcons, unsigned int nr) { scrdown(currcons, y, bottom, nr); need_wrap = 0; } static void delete_char(int currcons) { unsigned int i = x; unsigned short * p = (unsigned short *) pos; while (++i < video_num_columns) { scr_writew(scr_readw(p+1), p); p++; } scr_writew(video_erase_char, p); need_wrap = 0; } static void delete_line(int currcons, unsigned int nr) { scrup(currcons, y, bottom, nr); need_wrap = 0; } static void csi_at(int currcons, unsigned int nr) { if (nr > video_num_columns) nr = video_num_columns; else if (!nr) nr = 1; while (nr--) insert_char(currcons); } static void csi_L(int currcons, unsigned int nr) { if (nr > video_num_lines) nr = video_num_lines; else if (!nr) nr = 1; insert_line(currcons, nr); } static void csi_P(int currcons, unsigned int nr) { if (nr > video_num_columns) nr = video_num_columns; else if (!nr) nr = 1; while (nr--) delete_char(currcons); } static void csi_M(int currcons, unsigned int nr) { if (nr > video_num_lines) nr = video_num_lines; else if (!nr) nr=1; delete_line(currcons, nr); } static void save_cur(int currcons) { saved_x = x; saved_y = y; s_intensity = intensity; s_underline = underline; s_blink = blink; s_reverse = reverse; s_charset = charset; s_color = color; saved_G0 = G0_charset; saved_G1 = G1_charset; } static void restore_cur(int currcons) { gotoxy(currcons,saved_x,saved_y); intensity = s_intensity; underline = s_underline; blink = s_blink; reverse = s_reverse; charset = s_charset; color = s_color; G0_charset = saved_G0; G1_charset = saved_G1; translate = set_translate(charset ? G1_charset : G0_charset); update_attr(currcons); need_wrap = 0; } enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, ESpalette }; static void reset_terminal(int currcons, int do_clear) { top = 0; bottom = video_num_lines; vc_state = ESnormal; ques = 0; translate = set_translate(LAT1_MAP); G0_charset = LAT1_MAP; G1_charset = GRAF_MAP; charset = 0; need_wrap = 0; report_mouse = 0; utf = 0; utf_count = 0; disp_ctrl = 0; toggle_meta = 0; decscnm = 0; decom = 0; decawm = 1; deccm = 1; decim = 0; set_kbd(decarm); clr_kbd(decckm); clr_kbd(kbdapplic); clr_kbd(lnm); kbd_table[currcons].lockstate = 0; kbd_table[currcons].slockstate = 0; kbd_table[currcons].ledmode = LED_SHOW_FLAGS; kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; set_leds(); default_attr(currcons); update_attr(currcons); tab_stop[0] = 0x01010100; tab_stop[1] = tab_stop[2] = tab_stop[3] = tab_stop[4] = 0x01010101; bell_pitch = DEFAULT_BELL_PITCH; bell_duration = DEFAULT_BELL_DURATION; gotoxy(currcons,0,0); save_cur(currcons); if (do_clear) csi_J(currcons,2); } /* * Turn the Scroll-Lock LED on when the tty is stopped */ static void con_stop(struct tty_struct *tty) { int console_num; if (!tty) return; console_num = MINOR(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); set_leds(); } /* * Turn the Scroll-Lock LED off when the console is started */ static void con_start(struct tty_struct *tty) { int console_num; if (!tty) return; console_num = MINOR(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); set_leds(); } static int con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { int c, tc, ok, n = 0; unsigned int currcons; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; currcons = vt->vc_num; if (!vc_cons_allocated(currcons)) { /* could this happen? */ static int error = 0; if (!error) { error = 1; printk("con_write: tty %d not allocated\n", currcons+1); } return 0; } if (currcons == sel_cons) clear_selection(); disable_bh(CONSOLE_BH); while (!tty->stopped && count) { enable_bh(CONSOLE_BH); c = from_user ? get_user(buf) : *buf; buf++; n++; count--; disable_bh(CONSOLE_BH); if (utf) { /* Combine UTF-8 into Unicode */ /* Incomplete characters silently ignored */ if(c > 0x7f) { if (utf_count > 0 && (c & 0xc0) == 0x80) { utf_char = (utf_char << 6) | (c & 0x3f); utf_count--; if (utf_count == 0) tc = c = utf_char; else continue; } else { if ((c & 0xe0) == 0xc0) { utf_count = 1; utf_char = (c & 0x1f); } else if ((c & 0xf0) == 0xe0) { utf_count = 2; utf_char = (c & 0x0f); } else if ((c & 0xf8) == 0xf0) { utf_count = 3; utf_char = (c & 0x07); } else if ((c & 0xfc) == 0xf8) { utf_count = 4; utf_char = (c & 0x03); } else if ((c & 0xfe) == 0xfc) { utf_count = 5; utf_char = (c & 0x01); } else utf_count = 0; continue; } } else { tc = c; utf_count = 0; } } else { /* no utf */ tc = translate[toggle_meta ? (c|0x80) : c]; } /* If the original code was a control character we * only allow a glyph to be displayed if the code is * not normally used (such as for cursor movement) or * if the disp_ctrl mode has been explicitly enabled. * Certain characters (as given by the CTRL_ALWAYS * bitmap) are always displayed as control characters, * as the console would be pretty useless without * them; to display an arbitrary font position use the * direct-to-font zone in UTF-8 mode. */ ok = tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS : CTRL_ACTION) >> c) & 1))) && (c != 127 || disp_ctrl) && (c != 128+27); if (vc_state == ESnormal && ok) { /* Now try to find out how to display it */ tc = conv_uni_to_pc(tc); if ( tc == -4 ) { /* If we got -4 (not found) then see if we have defined a replacement character (U+FFFD) */ tc = conv_uni_to_pc(0xfffd); } else if ( tc == -3 ) { /* Bad hash table -- hope for the best */ tc = c; } if (tc & ~console_charmask) continue; /* Conversion failed */ if (need_wrap) { cr(currcons); lf(currcons); } if (decim) insert_char(currcons); scr_writew( video_mode_512ch ? ((attr & 0xf7) << 8) + ((tc & 0x100) << 3) + (tc & 0x0ff) : (attr << 8) + tc, (unsigned short *) pos); if (x == video_num_columns - 1) need_wrap = decawm; else { x++; pos+=2; } continue; } /* * Control characters can be used in the _middle_ * of an escape sequence. */ switch (c) { case 0: continue; case 7: if (bell_duration) kd_mksound(bell_pitch, bell_duration); continue; case 8: bs(currcons); continue; case 9: pos -= (x << 1); while (x < video_num_columns - 1) { x++; if (tab_stop[x >> 5] & (1 << (x & 31))) break; } pos += (x << 1); continue; case 10: case 11: case 12: lf(currcons); if (!is_kbd(lnm)) continue; case 13: cr(currcons); continue; case 14: charset = 1; translate = set_translate(G1_charset); disp_ctrl = 1; continue; case 15: charset = 0; translate = set_translate(G0_charset); disp_ctrl = 0; continue; case 24: case 26: vc_state = ESnormal; continue; case 27: vc_state = ESesc; continue; case 127: del(currcons); continue; case 128+27: vc_state = ESsquare; continue; } switch(vc_state) { case ESesc: vc_state = ESnormal; switch (c) { case '[': vc_state = ESsquare; continue; case ']': vc_state = ESnonstd; continue; case '%': vc_state = ESpercent; continue; case 'E': cr(currcons); lf(currcons); continue; case 'M': ri(currcons); continue; case 'D': lf(currcons); continue; case 'H': tab_stop[x >> 5] |= (1 << (x & 31)); continue; case 'Z': respond_ID(tty); continue; case '7': save_cur(currcons); continue; case '8': restore_cur(currcons); continue; case '(': vc_state = ESsetG0; continue; case ')': vc_state = ESsetG1; continue; case '#': vc_state = EShash; continue; case 'c': reset_terminal(currcons,1); continue; case '>': /* Numeric keypad */ clr_kbd(kbdapplic); continue; case '=': /* Appl. keypad */ set_kbd(kbdapplic); continue; } continue; case ESnonstd: if (c=='P') { /* palette escape sequence */ for (npar=0; npar<NPAR; npar++) par[npar] = 0 ; npar = 0 ; vc_state = ESpalette; continue; } else if (c=='R') { /* reset palette */ reset_palette (currcons); vc_state = ESnormal; } else vc_state = ESnormal; continue; case ESpalette: if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; if (npar==7) { int i = par[0]*3, j = 1; palette[i] = 16*par[j++]; palette[i++] += par[j++]; palette[i] = 16*par[j++]; palette[i++] += par[j++]; palette[i] = 16*par[j++]; palette[i] += par[j]; set_palette() ; vc_state = ESnormal; } } else vc_state = ESnormal; continue; case ESsquare: for(npar = 0 ; npar < NPAR ; npar++) par[npar] = 0; npar = 0; vc_state = ESgetpars; if (c == '[') { /* Function key */ vc_state=ESfunckey; continue; } ques = (c=='?'); if (ques) continue; case ESgetpars: if (c==';' && npar<NPAR-1) { npar++; continue; } else if (c>='0' && c<='9') { par[npar] *= 10; par[npar] += c-'0'; continue; } else vc_state=ESgotpars; case ESgotpars: vc_state = ESnormal; switch(c) { case 'h': set_mode(currcons,1); continue; case 'l': set_mode(currcons,0); continue; case 'n': if (!ques) if (par[0] == 5) status_report(tty); else if (par[0] == 6) cursor_report(currcons,tty); continue; } if (ques) { ques = 0; continue; } switch(c) { case 'G': case '`': if (par[0]) par[0]--; gotoxy(currcons,par[0],y); continue; case 'A': if (!par[0]) par[0]++; gotoxy(currcons,x,y-par[0]); continue; case 'B': case 'e': if (!par[0]) par[0]++; gotoxy(currcons,x,y+par[0]); continue; case 'C': case 'a': if (!par[0]) par[0]++; gotoxy(currcons,x+par[0],y); continue; case 'D': if (!par[0]) par[0]++; gotoxy(currcons,x-par[0],y); continue; case 'E': if (!par[0]) par[0]++; gotoxy(currcons,0,y+par[0]); continue; case 'F': if (!par[0]) par[0]++; gotoxy(currcons,0,y-par[0]); continue; case 'd': if (par[0]) par[0]--; gotoxay(currcons,x,par[0]); continue; case 'H': case 'f': if (par[0]) par[0]--; if (par[1]) par[1]--; gotoxay(currcons,par[1],par[0]); continue; case 'J': csi_J(currcons,par[0]); continue; case 'K': csi_K(currcons,par[0]); continue; case 'L': csi_L(currcons,par[0]); continue; case 'M': csi_M(currcons,par[0]); continue; case 'P': csi_P(currcons,par[0]); continue; case 'c': if (!par[0]) respond_ID(tty); continue; case 'g': if (!par[0]) tab_stop[x >> 5] &= ~(1 << (x & 31)); else if (par[0] == 3) { tab_stop[0] = tab_stop[1] = tab_stop[2] = tab_stop[3] = tab_stop[4] = 0; } continue; case 'm': csi_m(currcons); continue; case 'q': /* DECLL - but only 3 leds */ /* map 0,1,2,3 to 0,1,2,4 */ if (par[0] < 4) setledstate(kbd_table + currcons, (par[0] < 3) ? par[0] : 4); continue; case 'r': if (!par[0]) par[0]++; if (!par[1]) par[1] = video_num_lines; /* Minimum allowed region is 2 lines */ if (par[0] < par[1] && par[1] <= video_num_lines) { top=par[0]-1; bottom=par[1]; gotoxay(currcons,0,0); } continue; case 's': save_cur(currcons); continue; case 'u': restore_cur(currcons); continue; case 'X': csi_X(currcons, par[0]); continue; case '@': csi_at(currcons,par[0]); continue; case ']': /* setterm functions */ setterm_command(currcons); continue; } continue; case ESpercent: vc_state = ESnormal; switch (c) { case '@': /* defined in ISO 2022 */ utf = 0; continue; case 'G': /* prelim official escape code */ case '8': /* retained for compatibility */ utf = 1; continue; } continue; case ESfunckey: vc_state = ESnormal; continue; case EShash: vc_state = ESnormal; if (c == '8') { /* DEC screen alignment test. kludge :-) */ video_erase_char = (video_erase_char & 0xff00) | 'E'; csi_J(currcons, 2); video_erase_char = (video_erase_char & 0xff00) | ' '; } continue; case ESsetG0: if (c == '0') G0_charset = GRAF_MAP; else if (c == 'B') G0_charset = LAT1_MAP; else if (c == 'U') G0_charset = IBMPC_MAP; else if (c == 'K') G0_charset = USER_MAP; if (charset == 0) translate = set_translate(G0_charset); vc_state = ESnormal; continue; case ESsetG1: if (c == '0') G1_charset = GRAF_MAP; else if (c == 'B') G1_charset = LAT1_MAP; else if (c == 'U') G1_charset = IBMPC_MAP; else if (c == 'K') G1_charset = USER_MAP; if (charset == 1) translate = set_translate(G1_charset); vc_state = ESnormal; continue; default: vc_state = ESnormal; } } if (vcmode != KD_GRAPHICS) set_cursor(currcons); enable_bh(CONSOLE_BH); return n; } static int con_write_room(struct tty_struct *tty) { if (tty->stopped) return 0; return 4096; /* No limit, really; we're not buffering */ } static int con_chars_in_buffer(struct tty_struct *tty) { return 0; /* we're not buffering */ } void poke_blanked_console(void) { timer_active &= ~(1<<BLANK_TIMER); if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; if (console_blanked) { timer_table[BLANK_TIMER].fn = unblank_screen; timer_table[BLANK_TIMER].expires = 0; timer_active |= 1<<BLANK_TIMER; } else if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_active |= 1<<BLANK_TIMER; } } void console_print(const char * b) { int currcons = fg_console; unsigned char c; static int printing = 0; if (!printable || printing) return; /* console not yet initialized */ printing = 1; if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) currcons = kmsg_redirect - 1; if (!vc_cons_allocated(currcons)) { /* impossible */ printk("console_print: tty %d not allocated ??\n", currcons+1); return; } #ifdef CONFIG_SERIAL_ECHO serial_echo_print(b); #endif /* CONFIG_SERIAL_ECHO */ while ((c = *(b++)) != 0) { if (c == 10 || c == 13 || need_wrap) { if (c != 13) lf(currcons); cr(currcons); if (c == 10 || c == 13) continue; } if (c == 8) { /* backspace */ bs(currcons); continue; } scr_writew((attr << 8) + c, (unsigned short *) pos); if (x == video_num_columns - 1) { need_wrap = 1; continue; } x++; pos+=2; } set_cursor(currcons); poke_blanked_console(); printing = 0; } /* * con_throttle and con_unthrottle are only used for * paste_selection(), which has to stuff in a large number of * characters... */ static void con_throttle(struct tty_struct *tty) { } static void con_unthrottle(struct tty_struct *tty) { struct vt_struct *vt = (struct vt_struct *) tty->driver_data; wake_up_interruptible(&vt->paste_wait); } static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear) { long base = (long) vc_scrbuf[currcons]; int j, k ; video_num_columns = cols; video_num_lines = rows; video_size_row = cols<<1; video_screen_size = video_num_lines * video_size_row; pos = origin = video_mem_start = base; scr_end = base + video_screen_size; video_mem_end = base + video_screen_size; reset_vc(currcons); for (j=k=0; j<16; j++) { vc_cons[currcons].d->vc_palette[k++] = default_red[j] ; vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ; vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ; } def_color = 0x07; /* white */ ulcolor = 0x0f; /* bold white */ halfcolor = 0x08; /* grey */ vt_cons[currcons]->paste_wait = 0; reset_terminal(currcons, do_clear); } static void con_setsize(unsigned long rows, unsigned long cols) { video_num_lines = rows; video_num_columns = cols; video_size_row = 2 * cols; video_screen_size = video_num_lines * video_size_row; } /* * This is the console switching bottom half handler. * * Doing console switching in a bottom half handler allows * us to do the switches asynchronously (needed when we want * to switch due to a keyboard interrupt), while still giving * us the option to easily disable it to avoid races when we * need to write to the console. */ static void console_bh(void) { if (want_console >= 0) { if (want_console != fg_console) { change_console(want_console); /* we only changed when the console had already been allocated - a new console is not created in an interrupt routine */ } want_console = -1; } if (do_poke_blanked_console) { /* do not unblank for a LED change */ do_poke_blanked_console = 0; poke_blanked_console(); } } /* * unsigned long con_init(unsigned long); * * This routine initializes console interrupts, and does nothing * else. If you want the screen to clear, call tty_write with * the appropriate escape-sequence. * * Reads the information preserved by setup.s to determine the current display * type and sets everything accordingly. */ unsigned long con_init(unsigned long kmem_start) { const char *display_desc = "????"; int currcons = 0; int orig_x = ORIG_X; int orig_y = ORIG_Y; memset(&console_driver, 0, sizeof(struct tty_driver)); console_driver.magic = TTY_DRIVER_MAGIC; console_driver.name = "tty"; console_driver.name_base = 1; console_driver.major = TTY_MAJOR; console_driver.minor_start = 1; console_driver.num = MAX_NR_CONSOLES; console_driver.type = TTY_DRIVER_TYPE_CONSOLE; console_driver.init_termios = tty_std_termios; console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; console_driver.refcount = &console_refcount; console_driver.table = console_table; console_driver.termios = console_termios; console_driver.termios_locked = console_termios_locked; console_driver.open = con_open; console_driver.write = con_write; console_driver.write_room = con_write_room; console_driver.chars_in_buffer = con_chars_in_buffer; console_driver.ioctl = vt_ioctl; console_driver.stop = con_stop; console_driver.start = con_start; console_driver.throttle = con_throttle; console_driver.unthrottle = con_unthrottle; if (tty_register_driver(&console_driver)) panic("Couldn't register console driver\n"); con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS); timer_table[BLANK_TIMER].fn = blank_screen; timer_table[BLANK_TIMER].expires = 0; if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_active |= 1<<BLANK_TIMER; } kmem_start = con_type_init(kmem_start, &display_desc); hardscroll_enabled = (hardscroll_disabled_by_init ? 0 : (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAM)); has_wrapped = 0 ; /* Due to kmalloc roundup allocating statically is more efficient - so provide MIN_NR_CONSOLES for people with very little memory */ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { int j, k ; vc_cons[currcons].d = (struct vc_data *) kmem_start; kmem_start += sizeof(struct vc_data); vt_cons[currcons] = (struct vt_struct *) kmem_start; kmem_start += sizeof(struct vt_struct); vc_scrbuf[currcons] = (unsigned short *) kmem_start; kmem_start += video_screen_size; kmalloced = 0; screenbuf_size = video_screen_size; vc_init(currcons, video_num_lines, video_num_columns, currcons); for (j=k=0; j<16; j++) { vc_cons[currcons].d->vc_palette[k++] = default_red[j] ; vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ; vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ; } } currcons = fg_console = 0; video_mem_start = video_mem_base; video_mem_end = video_mem_term; origin = video_mem_start; scr_end = video_mem_start + video_num_lines * video_size_row; gotoxy(currcons,orig_x,orig_y); set_origin(currcons); csi_J(currcons, 0); /* Figure out the size of the screen and screen font so we can figure out the appropriate screen size should we load a different font */ printable = 1; if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC ) { default_font_height = video_font_height = ORIG_VIDEO_POINTS; /* This may be suboptimal but is a safe bet - go with it */ video_scan_lines = video_font_height * video_num_lines; #ifdef CONFIG_SERIAL_ECHO serial_echo_init(SERIAL_ECHO_PORT); #endif /* CONFIG_SERIAL_ECHO */ printk("Console: %ld point font, %ld scans\n", video_font_height, video_scan_lines); } printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n", can_do_color ? "colour" : "mono", display_desc, video_num_columns, video_num_lines, MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); /* * can't register TGA yet, because PCI bus probe has *not* taken * place before con_init() gets called. Trigger the real TGA hw * initialization and register_console() event from * within the bus probing code... :-( */ if (video_type != VIDEO_TYPE_TGAC) register_console(console_print); init_bh(CONSOLE_BH, console_bh); return kmem_start; } void vesa_powerdown_screen(void) { timer_active &= ~(1<<BLANK_TIMER); timer_table[BLANK_TIMER].fn = unblank_screen; vesa_powerdown(); } void do_blank_screen(int nopowersave) { int currcons; if (console_blanked) return; if(vesa_off_interval && !nopowersave) { timer_table[BLANK_TIMER].fn = vesa_powerdown_screen; timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval; timer_active |= (1<<BLANK_TIMER); } else { timer_active &= ~(1<<BLANK_TIMER); timer_table[BLANK_TIMER].fn = unblank_screen; } /* try not to lose information by blanking, and not to waste memory */ currcons = fg_console; has_scrolled = 0; blank__origin = __origin; blank_origin = origin; set_origin(fg_console); get_scrmem(fg_console); unblank_origin = origin; memsetw((void *)blank_origin, BLANK, 2*video_num_lines*video_num_columns); hide_cursor(); console_blanked = fg_console + 1; if(!nopowersave) { #ifdef CONFIG_APM if (apm_display_blank()) return; #endif vesa_blank(); } } void do_unblank_screen(void) { int currcons; int resetorg; long offset; if (!console_blanked) return; if (!vc_cons_allocated(fg_console)) { /* impossible */ printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); return; } timer_table[BLANK_TIMER].fn = blank_screen; if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_active |= 1<<BLANK_TIMER; } currcons = fg_console; offset = 0; resetorg = 0; if (console_blanked == fg_console + 1 && origin == unblank_origin && !has_scrolled) { /* try to restore the exact situation before blanking */ resetorg = 1; offset = (blank_origin - video_mem_base) - (unblank_origin - video_mem_start); } console_blanked = 0; set_scrmem(fg_console, offset); set_origin(fg_console); set_cursor(fg_console); if (resetorg) __set_origin(blank__origin); vesa_unblank(); #ifdef CONFIG_APM if (apm_display_unblank()) return; #endif } /* * If a blank_screen is due to a timer, then a power save is allowed. * If it is related to console_switching, then avoid vesa_blank(). */ static void blank_screen(void) { do_blank_screen(0); } static void unblank_screen(void) { do_unblank_screen(); } void update_screen(int new_console) { static int lock = 0; if (new_console == fg_console || lock) return; if (!vc_cons_allocated(new_console)) { /* strange ... */ printk("update_screen: tty %d not allocated ??\n", new_console+1); return; } lock = 1; clear_selection(); if (!console_blanked) get_scrmem(fg_console); else console_blanked = -1; /* no longer of the form console+1 */ fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */ /* consequently, fg_console will always be allocated */ set_scrmem(fg_console, 0); set_origin(fg_console); set_cursor(fg_console); set_leds(); compute_shiftstate(); lock = 0; } /* * Allocate the console screen memory. */ int con_open(struct tty_struct *tty, struct file * filp) { unsigned int idx; int i; idx = MINOR(tty->device) - tty->driver.minor_start; i = vc_allocate(idx); if (i) return i; vt_cons[idx]->vc_num = idx; tty->driver_data = vt_cons[idx]; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = video_num_lines; tty->winsize.ws_col = video_num_columns; } return 0; } /* * Load palette into the EGA/VGA DAC registers. arg points to a colour * map, 3 bytes per colour, 16 colours, range from 0 to 255. */ int con_set_cmap (unsigned char *arg) { return set_get_cmap (arg,1); } int con_get_cmap (unsigned char *arg) { return set_get_cmap (arg,0); } void reset_palette (int currcons) { int j, k ; for (j=k=0; j<16; j++) { palette[k++] = default_red[j]; palette[k++] = default_grn[j]; palette[k++] = default_blu[j]; } set_palette() ; } /* * Load font into the EGA/VGA character generator. arg points to a 8192 * byte map, 32 bytes per character. Only first H of them are used for * 8xH fonts (0 < H <= 32). */ int con_set_font (char *arg, int ch512) { int i; i = set_get_font (arg,1,ch512); if ( !i ) { hashtable_contents_valid = 0; video_mode_512ch = ch512; console_charmask = ch512 ? 0x1ff : 0x0ff; } return i; } int con_get_font (char *arg) { return set_get_font (arg,0,video_mode_512ch); } /* * Report the current status of the vc. This is exported to modules (ARub) */ int con_get_info(int *mode, int *shift, int *col, int *row, struct tty_struct **tty) { extern int shift_state; extern struct tty_driver console_driver; struct tty_struct **console_table=console_driver.table; if (mode) *mode = vt_cons[fg_console]->vc_mode; if (shift) *shift = shift_state; if (col) *col = video_num_columns; if (row) *row = video_num_lines; if (tty) *tty = console_table[fg_console]; return fg_console; }