Subject: Linux-Development Digest #971
From: Digestifier <Linux-Development-Request@senator-bedfellow.MIT.EDU>
To: Linux-Development@senator-bedfellow.MIT.EDU
Reply-To: Linux-Development@senator-bedfellow.MIT.EDU
Date:     Mon, 1 Aug 94 07:13:07 EDT

Linux-Development Digest #971, Volume #1          Mon, 1 Aug 94 07:13:07 EDT

Contents:
  dual monitor patches for 1.1.37 (Todd J. Derr)

----------------------------------------------------------------------------

From: tjd@neurocog.lrdc.pitt.edu (Todd J. Derr)
Subject: dual monitor patches for 1.1.37
Date: 1 Aug 1994 11:03:46 GMT

well, it took me long enough to get my hands on a mono monitor, but i finally
got one and tested the patches, which worked fine (argh, coulda released
them weeks ago :-)

anyways, these work against 1.1.37 and probably some earlier versions with
some shoehorning-- there have been some changes lately to the affected files
but they might still go in ok.

if you emailed me showing interest in these and didn't get a copy mailed
to you, it's because I lost access to my other account and thus can't get
to your mail (grumble).  mail me again if you want to be on the updates
list.   

included is a copy of the README, and then the actual patch.  Have fun,
and mail me with problems/comments/suggestions/etc...

todd.

--- snip (README) ---

These are the linux dual-monitor patches, version 1.1.37 alpha 1, 1 Aug 94.

These patches allow you to simultaneously use both color (EGA or VGA) and
monochrome video cards for VC's.  They have not been tested with X and
may not work properly (please email me and tell me what happens if you
try this).

========================================================================
News:

        Jeff Grills is no longer the maintainer of these patches.  They
are now maintained by myself, Todd J. Derr.  If you need to get in touch
with me about them, email me at:

                tjd@cs.pitt.edu -or- tjd@neurocog.lrdc.pitt.edu

        I'm planning on starting a mailing list for those of you who want
to keep up with the latest updates, etc.  I typically get and build new
kernels within a few hours of release, so if you want to stay on top of
things, get on the list.  Email me and I'll add you.

        I'd appreciate it if you browse over the 'To Do' section and
send me comments on what I'm planning to do with these patches.  Also
send me any other feedback/comments/suggestions/problems.

========================================================================
Installation:

        The patch file (dualmon.patch) should be applied to the 1.1.37
kernel sources in the drivers/char/ directory.  cd there and do:

        patch < patchfile

Look for any abnormal output from patch, and do an 'ls *.rej' to check
for any reject files.  If anything goes wrong, let me know.  I also have
patches against several earlier versions of the kernel if you need them.

        There are a few things you can configure:

in the Makefile, CONFIG_DUALMON is defined here.  if you want to build
a kernel without the dualmon support, edit the Makefile and uncomment the
appropriate line.

Alternatively, you may want to let linux's normal configuration
script handle this.  If so, replace the patched Makefile with the
original one, and edit 'config.in' in the top kernel directory.
Add a line to config.in that says:

bool 'Dual monitor (VGA/EGA + mono) support' CONFIG_DUALMON y

The proper place for this is in the 'Character Devices' section,
I put it under the CONFIG_SELECTION line, but it's up to you.  If
you do this, you will have to 'make config' before you make the new
kernel.

in console.c, search for the line #define MONO_CONSOLE 7.  This is the
default tty for the mono screen at boot time.  Add 1 for the real tty
number, so the default is tty8.  Change this if you want.

in keyboard.c, there are defines for LEFT_ADAPTER and RIGHT_ADAPTER.
LEFT and RIGHT refer to the ALT keys on your keyboard, which is how you
select which monitor the VC should go on.  The default is that the left
ALT key selects the mono screen and the right ALT selects the color screen.
It's probably most logical to make these reflect the placement of your
monitors, so swap them if need be.  Just make sure one of them has the
value 0 and one of them has the value 1 or bad things will happen.

NOTE: you should have NR_CONSOLES set to no more than 12 in linux/tty.h.
Read the 'To Do' section for why...   

Once you're all set up and ready, make the kernel, install it, and pray.

========================================================================
Using the dualmon patches:

On bootup, you should see a message from the console driver indicating
that the dualmon driver is installed.  If not, go back to 'installation'
and try again.

Basically, the patches modify the action of the ALT keys so that one of
them selects the mono screen and one of them selects the color screen.
Which is which is determined in keyboard.c,  feel free to change it.
The default is left-alt is mono and right-alt is color.

So, you just press the function keys to switch VC's as usual, but if you
press left ALT, the console goes to the mono screen, and right alt obviously
puts it on the color screen.

There are a couple problems with this scheme, and I'm working on ways to
fix them... read the 'To Do' section.

========================================================================
To Do:

please send me comments about the ideas below, i'd like as much feedback
as possible about them! 

there are some nasty things that I don't like about these patches.  First
is the way that VC switching is implemented in the keyboard driver.  It's
a bit of ugliness in do_cons() in keyboard.c, combined with the default
keymap.  do_cons() simply subtracts 12 from console numbers over 12 and
determines based on this which monitor things should go to.  This works
since ALT (left) F1-F12 are defined in defkeymap.map as Console_1 to
Console_12 and ALTGR (right) F1-F2 are 13-24.  This prevents you from
having more than 12 consoles, though that's pretty easily fixed if you
know what you're doing and want to change the keymaps.  I think I'd like
to eventually modify the keymaps so you can have entries like
Console_1_color or Console_1_mono, etc.   This would make a few things
easier, remove the need for the LEFT_CONSOLE and RIGHT_CONSOLE defines in
keyboard.c (and in fact make them easily dynamically assignable), and
remove the 12-console restriction (if you figure out key sequences to
do it).  However, I'm a bit leary about modifying the default keymap
or requiring that one be loaded at boot time... perhaps it's not that
big of a deal.

If I make the plunge and modify the keymaps though, I'd like to add a
function that was in my original version of these patches (jeff and i
were working on them together and some things never got folded into
each others versions, plus the keyboard driver was a lot different
[dare i say simpler] back then).  Something like focus_mono and
focus_color, which I had implemented as Left/Right-Alt and the
spacebar.  This can't be (easily) done now because left ALT-space
is defined as Meta_Space but right ALT-space is not defined.  The other
problem is that some applications use META-space... but of course putting
it in a keymap allows you to easily and dynamically change it.  It was
a nice feature... I miss it, since I was used to it.  Now, you have to
remember _which_ VC is on the "other" console before you can focus it,
which is kind of a pain.

related to this is that you can't tell which console is focused by
looking.  the abilty to single-key focus somewhat obviates the need
for this, but it would still be nice to do.  I played around with
turning the cursor off on the non-focused screen, but it looks weird
to have no cursor... so maybe I'll play around with changing it's shape
or something similar... look for this in future versions, and please
supply feedback if you think of a good way to deal with this.

this is painfully obvious, you can't swap a visible console
to the other screen.  This should be easy to change, I think, but the
question is this, what goes on the original console to fill the void?
My best guess would be to 'swap' the screen contents if you perform this,
so I'll probably try it... it might be annoying/disorienting though, I'll
see.  Look for this soon.

finally, I'm working on generally cleaning things up, resolving the
above issues, and trying to get the patches incorporated into the
main kernel so that I don't have to keep sending out updates.  I've
talked with linus about this and he seems to think it would be OK...
but there's a lot of work to be done and little time for me to do it
before this happens....

========================================================================

todd j. derr

tjd@cs.pitt.edu
tjd@neurocog.lrdc.pitt.edu

--- snip (dualmon.patch) ---
diff -u ../char_orig/Makefile ./Makefile
--- ../char_orig/Makefile       Mon Jul 25 16:51:09 1994
+++ ./Makefile  Mon Aug  1 03:21:57 1994
@@ -9,12 +9,19 @@
 # parent makes..
 #
 
+# Uncomment this for dual-mon support.  Eventually, I'll move it to
+# config.in.  You can put it there now if you like, and restore your
+# original Makefile here.
+# bool 'Dual monitor (VGA/EGA + mono) support' CONFIG_DUALMON y
+
+DUALMON=-DCONFIG_DUALMON
+
 .c.s:
        $(CC) $(CFLAGS) -S $<
 .s.o:
        $(AS) -c -o $*.o $<
 .c.o:
-       $(CC) $(CFLAGS) -c $<
+       $(CC) $(CFLAGS) $(DUALMON) -c $<
 
 OBJS  = tty_io.o n_tty.o console.o keyboard.o serial.o \
        tty_ioctl.o pty.o vt.o mem.o \
diff -u ../char_orig/console.c ./console.c
--- ../char_orig/console.c      Tue Jul 26 11:39:02 1994
+++ ./console.c Mon Aug  1 06:31:48 1994
@@ -14,6 +14,8 @@
  *     'void update_screen(int new_console)'
  *     'void blank_screen(void)'
  *     'void unblank_screen(void)'
+ *     'int con_get_num_lines(int console)'
+ *     'int con_get_num_columns(int console)'
  *
  *      'int  con_get_font(char *)' 
  *      'int  con_set_font(char *)' 
@@ -40,6 +42,15 @@
  *
  */
 
+/*
+ * original multi-adapter mods by Tuomas J. Lukka (lukka@kruuna.helsinki.fi)
+ * version updating done by Cory West (corywest@rice.edu)
+ * dynamic assignment done by Jeff Grills (jefftep@cs.utexas.edu)
+ *
+ * The dual-mon patches are now maintained by todd j. derr (tjd@cs.pitt.edu).
+ * please mail me comments, questions, etc...
+ */
+
 #define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
 
 /*
@@ -98,24 +109,42 @@
 
 #define NPAR 16
 
+#ifdef CONFIG_DUALMON
+#define DUALMON_VERSION "1.1.37 alpha1 (1 Aug 94)"
+#define NR_ADAPTERS 2
+#define MONO_CONSOLE 7
+#else
+#define NR_ADAPTERS 1
+#endif
+
 extern void vt_init(void);
 extern void register_console(void (*proc)(const char *));
 extern void compute_shiftstate(void);
 
-unsigned long  video_num_columns;              /* Number of text columns       */
-unsigned long  video_num_lines;                /* Number of text lines         */
-
-static unsigned char   video_type;             /* Type of display being used   */
-static unsigned long   video_mem_base;         /* Base of video memory         */
-static unsigned long   video_mem_term;         /* End of video memory          */
-static unsigned long   video_size_row;         /* Bytes per row                */
-static unsigned char   video_page;             /* Initial video page           */
-static unsigned short  video_port_reg;         /* Video register select port   */
-static unsigned short  video_port_val;         /* Video register value port    */
-static int can_do_color = 0;
-static int printable = 0;
+struct {
+       unsigned long   ad_video_num_columns;   /* Number of text columns */
+       unsigned long   ad_video_num_lines;     /* Number of text lines */
+       unsigned char   ad_video_type;          /* Type of display being used */
+       unsigned long   ad_video_mem_base;      /* Base of video memory */
+       unsigned long   ad_video_mem_term;      /* End of video memory */
+       unsigned long   ad_video_size_row;      /* Bytes per row */
+       unsigned char   ad_video_page;          /* Initial video page */
+       unsigned short  ad_video_port_reg;      /* Video register select port */
+       unsigned short  ad_video_port_val;      /* Video register value port */
+       unsigned int    ad_video_screen_size;   /* Number of bytes on video screen */
+       int     ad_can_do_color;                /* Is this adapter color or not */
+
+#ifdef CONFIG_DUALMON
+       unsigned char   ad_current_console;
+       char            *ad_display_desc;       /* type of this monitor */
+#endif
+} video_adapters[NR_ADAPTERS];
 
 static struct {
+#ifdef CONFIG_DUALMON
+       unsigned char   vc_adapter;
+       unsigned char   vc_old_adapter;
+#endif
        unsigned short  vc_video_erase_char;    /* Background erase character */
        unsigned char   vc_attr;                /* Current attributes */
        unsigned char   vc_def_color;           /* Default colors */
@@ -132,6 +161,7 @@
        unsigned long   vc_npar,vc_par[NPAR];
        unsigned long   vc_video_mem_start;     /* Start of video RAM           */
        unsigned long   vc_video_mem_end;       /* End of video RAM (sort of)   */
+       unsigned short *vc_scrbuf;
        unsigned long   vc_saved_x;
        unsigned long   vc_saved_y;
        /* mode flags */
@@ -166,10 +196,29 @@
        /* additional information is in vt_kern.h */
 } vc_cons [NR_CONSOLES];
 
-unsigned short *vc_scrbuf[NR_CONSOLES];
+static int printable = 0;
 static unsigned short * vc_scrmembuf;
 static int console_blanked = 0;
 
+#ifdef CONFIG_DUALMON
+#define curradapt              (vc_cons[currcons].vc_adapter)
+#define oldadapt               (vc_cons[currcons].vc_old_adapter)
+#else
+#define curradapt              0
+#endif
+
+#define video_num_columns      (video_adapters[curradapt].ad_video_num_columns)
+#define video_num_lines        (video_adapters[curradapt].ad_video_num_lines)
+#define video_type             (video_adapters[curradapt].ad_video_type)
+#define video_mem_base                 (video_adapters[curradapt].ad_video_mem_base)
+#define video_mem_term                 (video_adapters[curradapt].ad_video_mem_term)
+#define video_size_row                 (video_adapters[curradapt].ad_video_size_row)
+#define video_page             (video_adapters[curradapt].ad_video_page)
+#define video_port_reg                 (video_adapters[curradapt].ad_video_port_reg)
+#define video_port_val         (video_adapters[curradapt].ad_video_port_val)
+#define video_screen_size      (video_adapters[curradapt].ad_video_screen_size)
+#define video_can_do_color     (video_adapters[curradapt].ad_can_do_color)
+
 #define origin         (vc_cons[currcons].vc_origin)
 #define scr_end                (vc_cons[currcons].vc_scr_end)
 #define pos            (vc_cons[currcons].vc_pos)
@@ -191,6 +240,7 @@
 #define saved_G1       (vc_cons[currcons].vc_saved_G1)
 #define video_mem_start        (vc_cons[currcons].vc_video_mem_start)
 #define video_mem_end  (vc_cons[currcons].vc_video_mem_end)
+#define scrbuf         (vc_cons[currcons].vc_scrbuf)
 #define video_erase_char (vc_cons[currcons].vc_video_erase_char)       
 #define disp_ctrl      (vc_cons[currcons].vc_disp_ctrl)
 #define toggle_meta    (vc_cons[currcons].vc_toggle_meta)
@@ -235,7 +285,6 @@
 #define lnm            VC_CRLF
 
 int blankinterval = 10*60*HZ;
-static int screen_size = 0;
 
 /*
  * this is what the terminal answers to a ESC-Z or csi0c query.
@@ -321,6 +370,25 @@
 static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
                                       8,12,10,14, 9,13,11,15 };
 
+int con_get_num_lines(int currcons)
+{
+       return video_num_lines;
+}
+
+int con_get_num_columns(int currcons)
+{
+       return video_num_columns;
+}
+
+int is_visible_con(int currcons)
+{
+#ifdef CONFIG_DUALMON
+       return (currcons == video_adapters[curradapt].ad_current_console);
+#else
+       return (currcons == fg_console);
+#endif
+}
+
 /*
  * gotoxy() must verify all boundaries, because the arguments
  * might also be negative. If the given position is out of
@@ -359,7 +427,7 @@
 static unsigned short __real_origin;
 static unsigned short __origin;
 
-static inline void __set_origin(unsigned short offset)
+static inline void __set_origin(unsigned short offset, int currcons)
 {
        unsigned long flags;
 #ifdef CONFIG_SELECTION
@@ -374,7 +442,7 @@
        restore_flags(flags);
 }
 
-void scrollback(int lines)
+void scrollback(int lines, int currcons)
 {
        if (!lines)
                lines = video_num_lines/2;
@@ -382,10 +450,10 @@
        lines = __origin - lines;
        if (lines < 0)
                lines = 0;
-       __set_origin(lines);
+       __set_origin(lines, currcons);
 }
 
-void scrollfront(int lines)
+void scrollfront(int lines, int currcons)
 {
        if (!lines)
                lines = video_num_lines/2;
@@ -393,23 +461,27 @@
        lines = __origin + lines;
        if (lines > __real_origin)
                lines = __real_origin;
-       __set_origin(lines);
+       __set_origin(lines, currcons);
 }
 
 static void set_origin(int currcons)
 {
        if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
                return;
-       if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+       if (!is_visible_con(currcons) || console_blanked || vcmode == KD_GRAPHICS)
                return;
        __real_origin = (origin-video_mem_base) >> 1;
-       __set_origin(__real_origin);
+       __set_origin(__real_origin, currcons);
 }
 
 /*
  * Put the cursor just beyond the end of the display adaptor memory.
  */
+#ifdef CONFIG_DUALMON
+static inline void hide_cursor(int currcons)
+#else
 static inline void hide_cursor(void)
+#endif
 {
   /* This is inefficient, we could just put the cursor at 0xffff,
      but perhaps the delays due to the inefficiency are useful for
@@ -424,7 +496,7 @@
 {
        unsigned long flags;
 
-       if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+       if (!is_visible_con(currcons) || console_blanked || vcmode == KD_GRAPHICS)
                return;
        if (__real_origin != __origin)
                set_origin(__real_origin);
@@ -435,14 +507,21 @@
                outb_p(15, video_port_reg);
                outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
        } else
+#ifdef CONFIG_DUALMON
+               hide_cursor(currcons);
+#else
                hide_cursor();
+#endif
        restore_flags(flags);
 }
 
+static int cheese_video_num_columns;
 static void scrup(int currcons, unsigned int t, unsigned int b)
 {
        int hardscroll = 1;
 
+       cheese_video_num_columns = video_num_columns;
+
        if (b > video_num_lines || t >= b)
                return;
        if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
@@ -457,7 +536,7 @@
                        __asm__("cld\n\t"
                                "rep\n\t"
                                "movsl\n\t"
-                               "movl _video_num_columns,%1\n\t"
+                               "movl _cheese_video_num_columns,%1\n\t"
                                "rep\n\t"
                                "stosw"
                                : /* no output */
@@ -484,7 +563,7 @@
                __asm__("cld\n\t"
                        "rep\n\t"
                        "movsl\n\t"
-                       "movl _video_num_columns,%%ecx\n\t"
+                       "movl _cheese_video_num_columns,%%ecx\n\t"
                        "rep\n\t"
                        "stosw"
                        : /* no output */
@@ -498,13 +577,15 @@
 
 static void scrdown(int currcons, unsigned int t, unsigned int b)
 {
+       cheese_video_num_columns = video_num_columns;
+
        if (b > video_num_lines || t >= b)
                return;
        __asm__("std\n\t"
                "rep\n\t"
                "movsl\n\t"
                "addl $2,%%edi\n\t"     /* %edi has been decremented by 4 */
-               "movl _video_num_columns,%%ecx\n\t"
+               "movl _cheese_video_num_columns,%%ecx\n\t"
                "rep\n\t"
                "stosw\n\t"
                "cld"
@@ -656,7 +737,7 @@
 static void update_attr(int currcons)
 {
        attr = color;
-       if (can_do_color) {
+       if (video_can_do_color) {
                if (underline)
                        attr = (attr & 0xf0) | ulcolor;
                else if (intensity == 0)
@@ -668,7 +749,7 @@
                attr ^= 0x80;
        if (intensity == 2)
                attr ^= 0x08;
-       if (!can_do_color) {
+       if (!video_can_do_color) {
                if (underline)
                        attr = (attr & 0xf8) | 0x01;
                else if (intensity == 0)
@@ -824,7 +905,7 @@
 static void invert_screen(int currcons) {
        unsigned char *p;
 
-       if (can_do_color)
+       if (video_can_do_color)
                for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
                        *p = (*p & 0x88) | (((*p >> 4) | (*p << 4)) & 0x77);
        else
@@ -895,14 +976,14 @@
 {
        switch(par[0]) {
                case 1: /* set color for underline mode */
-                       if (can_do_color && par[1] < 16) {
+                       if (video_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) {
+                       if (video_can_do_color && par[1] < 16) {
                                halfcolor = color_table[par[1]];
                                if (intensity == 0)
                                        update_attr(currcons);
@@ -1530,7 +1611,14 @@
  */
 long con_init(long kmem_start)
 {
+#ifdef CONFIG_DUALMON
+#define display_desc video_adapters[curradapt].ad_display_desc
+       int max_screen_size;
+#else
+#define max_screen_size video_screen_size
        char *display_desc = "????";
+#endif
+
        int currcons = 0;
        long base;
        int orig_x = ORIG_X;
@@ -1564,13 +1652,33 @@
        if (tty_register_driver(&console_driver))
                panic("Couldn't register console driver\n");
        
+#ifdef CONFIG_DUALMON
+       /* -q- would like to make this more ... flexible */
+       currcons = MONO_CONSOLE;
+       curradapt = 1;
+       video_num_columns = 80;
+       video_size_row = video_num_columns * 2;
+       video_num_lines = 25;
+       video_page = 0;
+       video_screen_size = (video_num_lines * video_size_row);
+       max_screen_size = video_screen_size;
+       video_mem_base = 0xb0000;
+       video_port_reg = 0x3b4;
+       video_port_val = 0x3b5;
+       video_type = VIDEO_TYPE_MDA;
+       video_mem_term = 0xb2000;
+       display_desc = "*MDA";
+       currcons = 0;
+       curradapt = 0;
+#endif
+
        vc_scrmembuf = (unsigned short *) kmem_start;
        video_num_columns = ORIG_VIDEO_COLS;
        video_size_row = video_num_columns * 2;
        video_num_lines = ORIG_VIDEO_LINES;
        video_page = ORIG_VIDEO_PAGE;
-       screen_size = (video_num_lines * video_size_row);
-       kmem_start += NR_CONSOLES * screen_size;
+       video_screen_size = (video_num_lines * video_size_row);
+       kmem_start += NR_CONSOLES * video_screen_size;
        timer_table[BLANK_TIMER].fn = blank_screen;
        timer_table[BLANK_TIMER].expires = 0;
        if (blankinterval) {
@@ -1598,7 +1706,7 @@
        }
        else                            /* If not, it is color. */
        {
-               can_do_color = 1;
+               video_can_do_color = 1;
                video_mem_base = 0xb8000;
                video_port_reg  = 0x3d4;
                video_port_val  = 0x3d5;
@@ -1615,14 +1723,28 @@
                        display_desc = "*CGA";
                }
        }
-       
+
+#ifdef CONFIG_DUALMON
+       video_adapters[0].ad_current_console = 0;
+       video_adapters[1].ad_current_console = MONO_CONSOLE;
+       if ( video_screen_size > max_screen_size )
+               max_screen_size = video_screen_size;
+#endif
+
        /* Initialize the variables used for scrolling (mostly EGA/VGA) */
 
        base = (long)vc_scrmembuf;
        for (currcons = 0; currcons<NR_CONSOLES; currcons++) {
+#ifdef CONFIG_DUALMON
+               if ( currcons != MONO_CONSOLE )
+                       curradapt = oldadapt = 0;
+               else
+                       curradapt = oldadapt = 1;
+#endif
                pos = origin = video_mem_start = base;
-               scr_end = video_mem_end = (base += screen_size);
-               vc_scrbuf[currcons] = (unsigned short *) origin;
+               scr_end = video_mem_end = (base + video_screen_size);
+               base += max_screen_size;
+               scrbuf = (unsigned short *) origin;
                vcmode          = KD_TEXT;
                vtmode.mode     = VT_AUTO;
                vtmode.waitv    = 0;
@@ -1649,12 +1771,35 @@
        gotoxy(currcons,orig_x,orig_y);
        update_screen(fg_console);
        printable = 1;
+
+#ifndef CONFIG_DUALMON
        printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
-               can_do_color?"colour":"mono",
+#else
+       printk("Console: dual monitor driver version %s.\n"
+              "         %s %s %ldx%ld / mono *MDA 80x25, "
+                                        "%d virtual consoles\n",
+               DUALMON_VERSION,
+#endif
+               video_can_do_color?"colour":"mono",
                display_desc,
                video_num_columns,video_num_lines,
                NR_CONSOLES);
        register_console(console_print);
+
+#ifdef CONFIG_DUALMON
+       currcons = MONO_CONSOLE;
+       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,0,0);
+       save_cur(currcons);
+       gotoxy(currcons,orig_x,orig_y);
+       update_screen(MONO_CONSOLE);
+       printk("*MDA secondary adapter\n");
+       update_screen(0);
+#endif
+
        return kmem_start;
 }
 
@@ -1666,17 +1811,72 @@
 {
 }
 
+#ifdef CONFIG_DUALMON
+int set_adapter(int currcons, int ad)
+{
+       /* ignore swap attempts */
+       if (is_visible_con(currcons) && (curradapt != ad))
+               return -1;
+
+       if ( curradapt != ad ) {
+               oldadapt = curradapt;
+               curradapt = ad;
+               top = 0;
+               bottom = video_num_lines;
+       }
+       return currcons;
+}
+
+int get_fg_console_con(int cons)
+{
+       return video_adapters[vc_cons[cons].vc_adapter].ad_current_console;
+}
+
+/* this should be done last because it will reset old_adapter */
+void resize_console(int currcons)
+{
+       struct tty_struct *tty;
+
+       if ( oldadapt != curradapt ) {
+               oldadapt = curradapt;
+
+               /* this is adapted from TIOCSWINSZ in tty_io.c, as per  */
+               /* tytso's suggestion.                                  */
+
+               tty=console_driver.table[currcons];
+               
+               if (tty && tty->pgrp > 0 ) {
+
+                       if (tty->winsize.ws_row != video_num_lines ||
+                               tty->winsize.ws_col != video_num_columns) {
+
+                               if (tty->pgrp > 0)
+                                       kill_pg(tty->pgrp, SIGWINCH, 1);
+
+                               tty->winsize.ws_row=video_num_lines;
+                               tty->winsize.ws_col=video_num_columns;
+                       }
+               }
+       }
+}
+#endif CONFIG_DUALMON
+
 static void get_scrmem(int currcons)
 {
-       memcpy((void *)vc_scrbuf[currcons],(void *)origin, screen_size);
-       video_mem_start = (unsigned long)vc_scrbuf[currcons];
+       memcpy((void *)scrbuf, (void *)origin, video_screen_size);
+       video_mem_start = (unsigned long)scrbuf;
        origin  = video_mem_start;
-       scr_end = video_mem_end = video_mem_start+screen_size;
+       scr_end = video_mem_end = video_mem_start+video_screen_size;
        pos = origin + y*video_size_row + (x<<1);
 }
 
 static void set_scrmem(int currcons)
 {
+#ifdef CONFIG_DUALMON
+       int old_cols, old_rows, yl, min_rows, cpline, diffl;
+       unsigned short *pfrom, *pto;
+#endif
+
 #ifdef CONFIG_HGA
   /* This works with XFree86 1.2, 1.3 and 2.0
      This code could be extended and made more generally useful if we could
@@ -1708,27 +1908,83 @@
          }
 #endif CONFIG_HGA
 
+
        video_mem_start = video_mem_base;
        video_mem_end = video_mem_term;
        origin  = video_mem_start;
-       scr_end = video_mem_start + screen_size;
+       scr_end = video_mem_start + video_screen_size;
+
+#ifdef CONFIG_DUALMON
+       old_cols = video_adapters[oldadapt].ad_video_num_columns;
+       old_rows = video_adapters[oldadapt].ad_video_num_lines;
+       if ((video_num_columns != old_cols) || (video_num_lines != old_rows)) {
+
+               csi_J(currcons, 2);
+
+               pto = (unsigned short *)video_mem_base;
+               pfrom = scrbuf;
+               if (old_rows <= video_num_lines)
+                       min_rows = old_rows;
+               else
+                       if (y >= (min_rows = video_num_lines)) {
+                               diffl = (y - video_num_lines) + 1;
+                               pfrom += (diffl * old_cols);
+                               y -= diffl;
+               }
+
+               if (old_cols < video_num_columns)
+                       cpline = video_adapters[oldadapt].ad_video_size_row;
+               else {
+                       cpline = video_size_row;
+                       if (x >= video_num_columns)
+                               x = video_num_columns - 1;
+               }
+
+               if (old_cols == video_num_columns)
+                       memcpy((void *)pto, (void *)pfrom, min_rows * video_size_row);
+               else
+                       for (yl = 0; yl < min_rows; yl++) {
+                               memcpy((void *)pto, (void *)pfrom, cpline);
+                               pto += video_num_columns;
+                               pfrom += old_cols;
+                       }
+       }
+       else
+#endif
+               memcpy((void *)video_mem_base, (void *)scrbuf, video_screen_size);
        pos = origin + y*video_size_row + (x<<1);
-       memcpy((void *)video_mem_base, (void *)vc_scrbuf[fg_console], screen_size);
 }
 
 void blank_screen(void)
 {
+#ifdef CONFIG_DUALMON
+       int ad, currcons;
+#endif
+
        if (console_blanked)
                return;
        timer_table[BLANK_TIMER].fn = unblank_screen;
+#ifdef CONFIG_DUALMON
+       for(ad = 0; ad < 2; ad++) {
+               currcons = video_adapters[ad].ad_current_console;
+               get_scrmem(currcons);
+               hide_cursor(currcons);
+               memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
+       }
+#else
        get_scrmem(fg_console);
        hide_cursor();
-       console_blanked = 1;
        memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
+#endif
+       console_blanked = 1;
 }
 
 void unblank_screen(void)
 {
+#ifdef CONFIG_DUALMON
+       int ad, currcons;
+#endif
+
        if (!console_blanked)
                return;
        timer_table[BLANK_TIMER].fn = blank_screen;
@@ -1737,26 +1993,68 @@
                timer_active |= 1<<BLANK_TIMER;
        }
        console_blanked = 0;
+
+#ifdef CONFIG_DUALMON
+       for(ad = 0; ad < NR_ADAPTERS; ad++) {
+               currcons = video_adapters[ad].ad_current_console;
+               set_scrmem(currcons);
+               set_origin(currcons);
+               set_cursor(currcons);
+       }
+#else
        set_scrmem(fg_console);
        set_origin(fg_console);
        set_cursor(fg_console);
+#endif
 }
 
+#ifdef CONFIG_DUALMON
+/*
+ *     void change_screen(int new_console)
+ *
+ *     called when the screen is already the current adapter's fg_console but
+ *     not the global fg_console
+ */
+
+void change_screen(int new_console)
+{
+       if (!is_visible_con(new_console))
+               return;
+       fg_console = new_console;
+       set_leds();
+}
+#endif CONFIG_DUALMON
+
 void update_screen(int new_console)
 {
        static int lock = 0;
 
        if (new_console == fg_console || lock)
                return;
+
+#ifdef CONFIG_DUALMON
+       if (is_visible_con(new_console)) {
+               fg_console = new_console;
+               set_leds();
+               return;
+       }
+#endif
+
        lock = 1;
        kbdsave(new_console);
 #ifdef CONFIG_SELECTION
        highlight_pointer(fg_console,-1);
 #endif /* CONFIG_SELECTION */
+
+#ifdef CONFIG_DUALMON
+       get_scrmem(video_adapters[vc_cons[new_console].vc_adapter].ad_current_console);
+       video_adapters[vc_cons[new_console].vc_adapter].ad_current_console = new_console;
+#else
        get_scrmem(fg_console); 
+#endif
        fg_console = new_console;
-       set_scrmem(fg_console); 
-       set_origin(fg_console);
+       set_scrmem(new_console); 
+       set_origin(new_console);
        set_cursor(new_console);
        set_leds();
        compute_shiftstate();
@@ -1766,8 +2064,9 @@
 int do_screendump(int arg)
 {
        char *sptr, *buf = (char *)arg;
-       int currcons, l;
+       int currcons=0, l;
 
+       /* -q- need to fix this! */
        if (!suser())
                return -EPERM;
        l = verify_area(VERIFY_WRITE, buf,2+video_num_columns*video_num_lines);
@@ -1792,8 +2091,9 @@
 int con_open(struct tty_struct *tty, struct file * filp)
 {
        int     idx;
+       int     currcons;
 
-       idx = MINOR(tty->device) - tty->driver.minor_start;
+       currcons=idx = MINOR(tty->device) - tty->driver.minor_start;
        
        if (idx > NR_CONSOLES)
                return -ENODEV;
@@ -1873,7 +2173,7 @@
 }
 
 /* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p)
+static inline int atedge(const int p, const int currcons)
 {
        return (!(p % video_size_row) || !((p + 2) % video_size_row));
 }
@@ -1976,11 +2276,11 @@
        }
        /* select to end of line if on trailing space */
        if (new_sel_end > new_sel_start &&
-               !atedge(new_sel_end) && isspace(*(off + new_sel_end)))
+               !atedge(new_sel_end, currcons) && isspace(*(off + new_sel_end)))
        {
                for (pe = new_sel_end + 2; ; pe += 2)
                {
-                       if (!isspace(*(off + pe)) || atedge(pe))
+                       if (!isspace(*(off + pe)) || atedge(pe, currcons))
                                break;
                }
                if (isspace(*(off + pe)))
@@ -2113,11 +2413,10 @@
        int beg;
 
        /* no use to "load" CGA... */
-
-       if (video_type == VIDEO_TYPE_EGAC) {
+       if (video_adapters[0].ad_video_type == VIDEO_TYPE_EGAC) {
                charmap = colourmap;
                beg = 0x0e;
-       } else if (video_type == VIDEO_TYPE_EGAM) {
+       } else if (video_adapters[0].ad_video_type == VIDEO_TYPE_EGAM) {
                charmap = blackwmap;
                beg = 0x0a;
        } else
diff -u ../char_orig/keyboard.c ./keyboard.c
--- ../char_orig/keyboard.c     Thu Jul 21 03:49:01 1994
+++ ./keyboard.c        Mon Aug  1 04:52:50 1994
@@ -61,11 +61,22 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_DUALMON
+/* 1 is the secondary screen (mono), 0 is the primary. LEFT and RIGHT
+ * refer to the ALT keys.  this will probably go away sometime and be
+ * done with a loadable keymap that is dualmon-aware.
+ */
+#define LEFT_ADAPTER 1
+#define RIGHT_ADAPTER 0
+void resize_console(int);
+int set_adapter(int, int);
+#endif
+
 extern void poke_blanked_console(void);
 extern void ctrl_alt_del(void);
 extern void change_console(unsigned int new_console);
-extern void scrollback(int);
-extern void scrollfront(int);
+extern void scrollback(int, int);
+extern void scrollfront(int, int);
 
 #define fake_keyboard_interrupt() \
 __asm__ __volatile__("int $0x21")
@@ -480,12 +491,12 @@
 
 static void scrll_forw(void)
 {
-       scrollfront(0);
+       scrollfront(0, fg_console);
 }
 
 static void scrll_back(void)
 {
-       scrollback(0);
+       scrollback(0, fg_console);
 }
 
 static void boot_it(void)
@@ -617,7 +628,15 @@
 {
        if (up_flag)
                return;
+
+#ifdef CONFIG_DUALMON
+       if (value >= 12)
+               want_console = set_adapter(value-12, RIGHT_ADAPTER);
+       else
+               want_console = set_adapter(value, LEFT_ADAPTER);
+#else
        want_console = value;
+#endif
 }
 
 static void do_fn(unsigned char value, char up_flag)
@@ -840,6 +859,9 @@
                if (want_console != fg_console) {
                        last_console = fg_console;
                        change_console(want_console);
+#ifdef CONFIG_DUALMON
+                       resize_console(want_console);
+#endif
                }
                want_console = -1;
        }
diff -u ../char_orig/tty_io.c ./tty_io.c
--- ../char_orig/tty_io.c       Mon Jul 25 16:51:10 1994
+++ ./tty_io.c  Sun Jul 24 21:44:05 1994
@@ -98,6 +98,12 @@
                     unsigned int cmd, unsigned long arg);
 static int tty_fasync(struct inode * inode, struct file * filp, int on);
 
+int con_get_num_lines(int console);
+int con_get_num_columns(int console);
+void change_screen(int);
+int is_visible_con(int currcons);
+int get_fg_console_con(int cons);
+
 #ifndef MIN
 #define MIN(a,b)       ((a) < (b) ? (a) : (b))
 #endif
@@ -447,16 +453,28 @@
 void complete_change_console(unsigned int new_console)
 {
        unsigned char old_vc_mode;
+       unsigned char ad_fg_console;
+
+       if (new_console >= NR_CONSOLES)
+               return;
 
-       if (new_console == fg_console || new_console >= NR_CONSOLES)
+#ifdef CONFIG_DUALMON
+       if (is_visible_con(new_console)) {
+               change_screen(new_console);
                return;
+       }
 
+       ad_fg_console = get_fg_console_con(new_console);
+#else
+       ad_fg_console = fg_console;
+#endif
+       
        /*
         * If we're switching, we could be going from KD_GRAPHICS to
         * KD_TEXT mode or vice versa, which means we need to blank or
         * unblank the screen later.
         */
-       old_vc_mode = vt_cons[fg_console].vc_mode;
+       old_vc_mode = vt_cons[ad_fg_console].vc_mode;
        update_screen(new_console);
 
        /*
@@ -523,8 +541,21 @@
  */
 void change_console(unsigned int new_console)
 {
-       if (new_console == fg_console || new_console >= NR_CONSOLES)
+       unsigned char ad_fg_console;
+
+       if (new_console >= NR_CONSOLES)
+               return;
+
+#ifdef CONFIG_DUALMON
+       if (is_visible_con(new_console)) {
+               change_screen(new_console);
                return;
+       }
+
+       ad_fg_console = get_fg_console_con(new_console);
+#else
+       ad_fg_console = fg_console;
+#endif
 
        /*
         * If this vt is in process mode, then we need to handshake with
@@ -541,15 +572,15 @@
         * the user waits just the right amount of time :-) and revert the
         * vt to auto control.
         */
-       if (vt_cons[fg_console].vt_mode.mode == VT_PROCESS)
+       if (vt_cons[ad_fg_console].vt_mode.mode == VT_PROCESS)
        {
                /*
                 * Send the signal as privileged - kill_proc() will
                 * tell us if the process has gone or something else
                 * is awry
                 */
-               if (kill_proc(vt_cons[fg_console].vt_pid,
-                             vt_cons[fg_console].vt_mode.relsig,
+               if (kill_proc(vt_cons[ad_fg_console].vt_pid,
+                             vt_cons[ad_fg_console].vt_mode.relsig,
                              1) == 0)
                {
                        /*
@@ -557,7 +588,7 @@
                         * return. The process needs to send us a
                         * VT_RELDISP ioctl to complete the switch.
                         */
-                       vt_cons[fg_console].vt_newvt = new_console;
+                       vt_cons[ad_fg_console].vt_newvt = new_console;
                        return;
                }
 
@@ -570,16 +601,16 @@
                 * this outside of VT_PROCESS but there is no single process
                 * to account for and tracking tty count may be undesirable.
                 */
-               vt_cons[fg_console].vc_mode = KD_TEXT;
-               clr_vc_kbd_mode(kbd_table + fg_console, VC_RAW);
-               clr_vc_kbd_mode(kbd_table + fg_console, VC_MEDIUMRAW);
-               vt_cons[fg_console].vt_mode.mode = VT_AUTO;
-               vt_cons[fg_console].vt_mode.waitv = 0;
-               vt_cons[fg_console].vt_mode.relsig = 0;
-               vt_cons[fg_console].vt_mode.acqsig = 0;
-               vt_cons[fg_console].vt_mode.frsig = 0;
-               vt_cons[fg_console].vt_pid = -1;
-               vt_cons[fg_console].vt_newvt = -1;
+               vt_cons[ad_fg_console].vc_mode = KD_TEXT;
+               clr_vc_kbd_mode(kbd_table + ad_fg_console, VC_RAW);
+               clr_vc_kbd_mode(kbd_table + ad_fg_console, VC_MEDIUMRAW);
+               vt_cons[ad_fg_console].vt_mode.mode = VT_AUTO;
+               vt_cons[ad_fg_console].vt_mode.waitv = 0;
+               vt_cons[ad_fg_console].vt_mode.relsig = 0;
+               vt_cons[ad_fg_console].vt_mode.acqsig = 0;
+               vt_cons[ad_fg_console].vt_mode.frsig = 0;
+               vt_cons[ad_fg_console].vt_pid = -1;
+               vt_cons[ad_fg_console].vt_newvt = -1;
                /*
                 * Fall through to normal (VT_AUTO) handling of the switch...
                 */
@@ -588,7 +619,7 @@
        /*
         * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
         */
-       if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
+       if (vt_cons[ad_fg_console].vc_mode == KD_GRAPHICS)
                return;
 
        complete_change_console(new_console);

------------------------------


** FOR YOUR REFERENCE **

The service address, to which questions about the list itself and requests
to be added to or deleted from it should be directed, is:

    Internet: Linux-Development-Request@NEWS-DIGESTS.MIT.EDU

You can send mail to the entire list (and comp.os.linux.development) via:

    Internet: Linux-Development@NEWS-DIGESTS.MIT.EDU

Linux may be obtained via one of these FTP sites:
    nic.funet.fi				pub/OS/Linux
    tsx-11.mit.edu				pub/linux
    sunsite.unc.edu				pub/Linux

End of Linux-Development Digest
******************************
