Softcursor patch for vga

Pavel Machek (pavel@Elf.mj.gts.cz)
Sat, 7 Jun 1997 15:05:43 +0200


Hi!

This patch allows you to use software cursor on vga (with
CONFIG_SOFTCURSOR enabled), and allows you to change shape of hardware
cursor & workarounds trident bug (even with CONFIG_SOFTCURSOR disabled).

It is meant for everyone - as I think that it is shame for system not
no be able to change cursor size. With enabling softcursor may be very
good for notebooks, or people who can't stand blinking underlines. It
is even possible to use 'something in between' [and that's what I
prefer]: I have normal blinking underline, but character on cursor
gets bright foreground & background.

It is pretty short, really configurable (well configured by status
word given at ESC[?123c sequence :-), and it WORKS. Thanx go to Sander
van Malssen <svm@kozmix.ow.nl> and Bill Paul
<ghod@drycas.club.cc.cmu.edu> who created original noblink package
(much more complex, less configurable & failing to work under Midnight
Commander), and Martin Mares <mj@atrey.karlin.mff.cuni.cz>, who said
he would like such patch.

Look at console_struct.h for setting how default cursor should look like.

Ok, stop talking, here's the code! [diff against 2.1.42]

--
I'm really pavel@atrey.karlin.mff.cuni.cz. 	   Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel ;-).

diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/CREDITS linux/CREDITS --- clean/CREDITS Fri May 23 13:11:39 1997 +++ linux/CREDITS Sat Jun 7 14:06:36 1997 @@ -882,6 +882,13 @@ D: SLS distribution D: Initial implementation of VC's, pty's and select() +N: Pavel Machek +E: pavel@atrey.karlin.mff.cuni.cz +D: Softcursor for vga, hypertech cdrom support, vcsa bugfix +S: Volkova 1131 +S: 198 00 Praha 9 +S: Czech Republic + N: James B. MacLean E: macleajb@ednet.ns.ca W: http://www.ednet.ns.ca/~macleajb/dosemu.html diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/Documentation/Configure.help linux/Documentation/Configure.help --- clean/Documentation/Configure.help Fri May 30 20:17:13 1997 +++ linux/Documentation/Configure.help Sat Jun 7 13:10:19 1997 @@ -4020,6 +4044,13 @@ device /dev/tty which corresponds to the virtual terminal you have visible on your display. You should say Y here if you have no other console device. + +Software generated cursor +CONFIG_SOFTCURSOR + If you enable this option, you'll be able to do lots of nice things + with your cursor - for example to turn it into non-blinking one. + Use ESC[?123c to set cursor appearance, look into vga.c for + bitfield which defines what cursor will look like. Standard/generic serial support CONFIG_SERIAL diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/drivers/char/Config.in linux/drivers/char/Config.in --- clean/drivers/char/Config.in Wed May 14 19:35:15 1997 +++ linux/drivers/char/Config.in Sat Jun 7 00:15:01 1997 @@ -7,6 +7,7 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then bool 'Console on virtual terminal' CONFIG_VT_CONSOLE + bool 'Software generated cursor' CONFIG_SOFTCURSOR fi tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/drivers/char/console.c linux/drivers/char/console.c --- clean/drivers/char/console.c Wed May 14 19:35:16 1997 +++ linux/drivers/char/console.c Sat Jun 7 00:17:11 1997 @@ -60,7 +60,14 @@ * User-defined bell sound, new setterm control sequences and printk * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 * + * Added code to support change of cursor size in vga.c + * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> 7/96 + * * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> + * + * Modified code to support software cursors by Pavel Machek + * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> 6/97 + * */ #define BLANK 0x0020 @@ -175,6 +182,8 @@ unsigned long video_size_row; unsigned long video_screen_size; +extern int gpm_pid; + int can_do_color = 0; static int printable = 0; /* Is console ready for printing? */ @@ -948,7 +963,7 @@ else { p = screenpos(currcons, offset, 1); old = scr_readw(p); - scr_writew(old ^ 0x7700, p); + scr_writew(old ^ 0x6600, p); } } @@ -1250,6 +1265,8 @@ kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; set_leds(); + cursor_type = CUR_DEFAULT; + default_attr(currcons); update_attr(currcons); @@ -1608,6 +1626,10 @@ continue; case 'l': set_mode(currcons,0); + continue; + case 'c': + cursor_type = par[0]; + set_cursor(currcons); continue; case 'n': if (!ques) diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/drivers/char/console_struct.h linux/drivers/char/console_struct.h --- clean/drivers/char/console_struct.h Tue Nov 21 07:34:54 1995 +++ linux/drivers/char/console_struct.h Sat Jun 7 00:17:11 1997 @@ -4,6 +4,14 @@ * Data structure and defines shared between console.c, vga.c and tga.c */ +/* + * This is rather user servicable: + * you can choose what cursor should look like by default + * In case you set CONFIG_SOFTCURSOR, this will be really interesting. + */ +//#define CUR_DEFAULT 0x8811 +#define CUR_DEFAULT CUR_UNDERLINE + #define NPAR 16 struct vc_data { @@ -65,6 +73,9 @@ unsigned int vc_bell_pitch; /* Console bell pitch */ unsigned int vc_bell_duration; /* Console bell duration */ /* additional information is in vt_kern.h */ + + /* cursor size */ + unsigned int vc_cursor_type; }; struct vc { @@ -136,6 +147,15 @@ #define palette (vc_cons[currcons].d->vc_palette) #define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) #define bell_duration (vc_cons[currcons].d->vc_bell_duration) + +#define cursor_type (vc_cons[currcons].d->vc_cursor_type) +#define CUR_NONE 0 +#define CUR_UNDERLINE 1 +#define CUR_LOWER_HALF 2 +#define CUR_LOWER_THIRD 3 +#define CUR_BLOCK 4 +#define CUR_HWMASK 0x0f +#define CUR_SWMASK 0xfff0 #define vcmode (vt_cons[currcons]->vc_mode) #define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/drivers/char/selection.h linux/drivers/char/selection.h --- clean/drivers/char/selection.h Fri May 30 20:17:17 1997 +++ linux/drivers/char/selection.h Sat Jun 7 11:15:39 1997 @@ -169,8 +169,23 @@ return readb((unsigned long) addr); } +#ifdef CONFIG_SOFTCURSOR +/* + * Note: CONFIG_SOFTCURSOR does not need to patch scr_readb, + * as noone uses scr_readb/scr_writeb for changing attribs. + */ +extern unsigned long softcursor_pos; +extern unsigned short remove_softcursor( unsigned short i ); +extern unsigned short add_softcursor( unsigned short i ); + +#endif + static inline void scr_writew(unsigned short val, unsigned short * addr) { +#ifdef CONFIG_SOFTCURSOR + if ((unsigned long) addr == softcursor_pos) + val = add_softcursor( val ); +#endif if ((long) addr < 0) *addr = val; else @@ -179,6 +194,10 @@ static inline unsigned short scr_readw(unsigned short * addr) { +#ifdef CONFIG_SOFTCURSOR + if ((unsigned long) addr == softcursor_pos) + return remove_softcursor( readw((unsigned long) addr ) ); +#endif if ((long) addr < 0) return *addr; return readw((unsigned long) addr); diff -uNr -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkaymap.c -x uni_hash.tbl clean/drivers/char/vga.c linux/drivers/char/vga.c --- clean/drivers/char/vga.c Wed May 14 19:35:29 1997 +++ linux/drivers/char/vga.c Sat Jun 7 00:17:11 1997 @@ -37,7 +37,21 @@ * flashing on RHS of screen during heavy console scrolling . * Oct 1996, Paul Gortmaker. * + * Cursor resizing added (\E]a, \E]b, \E]c, \E?25h), + * patch for Trident glitch + * 6/96 Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> + * + * Cursor resizing moved to \E[?1c etc, software cursors added + * 6/97 Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> + */ + +/* You really do _NOT_ want to define this, unless you have buggy + * trident VGA which will resize cursor when moving it between column + * 15 & 16. If you define this and your VGA is Ok, reverse bug will + * appear. */ +#undef TRIDENT_GLITCH + #include <linux/sched.h> #include <linux/timer.h> @@ -122,16 +136,101 @@ write_vga(12, offset); } + +#ifdef CONFIG_SOFTCURSOR +unsigned long softcursor_pos; +unsigned int softcursor_type; + +/* + * softcursor_type has following form: + * + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 .9 .8 .7 .6 .5 .4 .3 .2 .1 .0 + * < attrib or mask > < attrib xor mask > VI PR EN <reserved: > + * <hw cursor > + * Warning - it is not easy to use high few bits: nasty overflows ahead! + * EN: softcursor enabled + * PR: prevent new background from being equal to old one + * VI: prevent foreground to be same as background + */ +unsigned short origval; + +unsigned short +remove_softcursor( unsigned short i ) +{ +return origval; +} + +unsigned short +add_softcursor( unsigned short i ) +{ +origval = i; +if (! (softcursor_type & 0x10)) return i; +i |= ((softcursor_type >> 8) & 0xff00 ); +i ^= ((softcursor_type) & 0xff00 ); +if ((softcursor_type & 0x20) && ((origval & 0xf000) == (i & 0xf000))) i ^= 0x7000; +if ((softcursor_type & 0x40) && ((i & 0xf00) == ((i & 0xf000) >> 4))) i ^= 0x0700; +return i; +} + +static void +move_softcursor( unsigned long to, int type ) +{ +if (softcursor_pos != to) + { + unsigned short s, t; + unsigned long oldpos; + oldpos = softcursor_pos; + s = scr_readw( (void *) oldpos ); + t = scr_readw( (void *) to ); + softcursor_pos = to; + softcursor_type = type; + scr_writew( s, (void *) oldpos ); + scr_writew( t, (void *) to ); + } +} +#endif + /* * Put the cursor just beyond the end of the display adaptor memory. */ void hide_cursor(void) { - /* This is inefficient, we could just put the cursor at 0xffff, - but perhaps the delays due to the inefficiency are useful for - some hardware... */ - write_vga(14, (video_mem_term - video_mem_base - 1)>>1); + /* write_vga already handles slow hw. */ + write_vga(14, 0xffff); +#ifdef CONFIG_SOFTCURSOR + move_softcursor( 0xffff, 0 ); +#endif +} + +void +con_set_cursor_size( int xpos, int from, int to ) +{ + unsigned long flags; + int curs, cure; + static int lastfrom, lastto; + +#ifdef TRIDENT_GLITCH + if (xpos<16) from--, to--; +#endif + + if ((from == lastfrom) && (to == lastto)) return; + lastfrom = from; lastto = to; + + save_flags(flags); cli(); + outb_p( 0x0a, video_port_reg ); /* Cursor start */ + curs = inb_p(video_port_val); + outb_p( 0x0b, video_port_reg ); /* Cursor end */ + cure = inb_p(video_port_val); + + curs = (curs & 0xc0) | from; + cure = (cure & 0xe0) | to; + + outb_p( 0x0a, video_port_reg ); /* Cursor start */ + outb_p( curs, video_port_val ); + outb_p( 0x0b, video_port_reg ); /* Cursor end */ + outb_p( cure, video_port_val ); + restore_flags(flags); } void @@ -142,7 +241,36 @@ if (__real_origin != __origin) __set_origin(__real_origin); if (deccm) { +#ifdef CONFIG_SOFTCURSOR + move_softcursor( pos, cursor_type ); +#endif write_vga(14, (pos - video_mem_base)>>1); + switch (cursor_type & 0x0f) { + case CUR_UNDERLINE: + con_set_cursor_size( x, + video_font_height - (video_font_height < 10 ? 2 : 3), + video_font_height - (video_font_height < 10 ? 1 : 2) ); + break; + case CUR_LOWER_THIRD: + con_set_cursor_size( x, + (video_font_height*2) / 3, + video_font_height - (video_font_height < 10 ? 1 : 2) ); + break; + case CUR_LOWER_HALF: + con_set_cursor_size( x, + video_font_height / 2, + video_font_height - (video_font_height < 10 ? 1 : 2) ); + break; + case CUR_BLOCK: + con_set_cursor_size( x, 2, + video_font_height - (video_font_height < 10 ? 1 : 2) ); + break; + case CUR_NONE: + con_set_cursor_size( x, 31, 30 ); + break; + default: + printk( "Trouble: unknown cursor size" ); + } } else hide_cursor(); } @@ -492,7 +620,7 @@ con_adjust_height(unsigned long fontheight) { int rows, maxscan; - unsigned char ovr, vde, fsr, curs, cure; + unsigned char ovr, vde, fsr; if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC && video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)) @@ -521,10 +649,6 @@ ovr = inb_p(video_port_val); outb_p( 0x09, video_port_reg ); /* Font size register */ fsr = inb_p(video_port_val); - outb_p( 0x0a, video_port_reg ); /* Cursor start */ - curs = inb_p(video_port_val); - outb_p( 0x0b, video_port_reg ); /* Cursor end */ - cure = inb_p(video_port_val); sti(); vde = maxscan & 0xff; /* Vertical display end reg */ @@ -532,18 +656,13 @@ ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3); fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */ - curs = (curs & 0xc0) + fontheight - (fontheight < 10 ? 2 : 3); - cure = (cure & 0xe0) + fontheight - (fontheight < 10 ? 1 : 2); cli(); outb_p( 0x07, video_port_reg ); /* CRTC overflow register */ outb_p( ovr, video_port_val ); outb_p( 0x09, video_port_reg ); /* Font size */ outb_p( fsr, video_port_val ); - outb_p( 0x0a, video_port_reg ); /* Cursor start */ - outb_p( curs, video_port_val ); - outb_p( 0x0b, video_port_reg ); /* Cursor end */ - outb_p( cure, video_port_val ); + outb_p( 0x12, video_port_reg ); /* Vertical display limit */ outb_p( vde, video_port_val ); sti();