LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Desktop (https://www.linuxquestions.org/questions/linux-desktop-74/)
-   -   Multi monitor CLI adventures (https://www.linuxquestions.org/questions/linux-desktop-74/multi-monitor-cli-adventures-4175529114/)

bucovaina78 12-23-2014 01:25 PM

Multi monitor CLI adventures
 
Hi all,

I've always enjoyed doing stuff in CLI rather than GUI when possible. That lead to the fact that currently I do almost everything in CLI. I've wanted to use multiple monitors on CLI for a very long time but never found out how to do it. Until now that is. I'm so happy I finally got it working that I'd like to share how I did it.

So what do you need?
  • Basic Linux command line skills
  • 2 monitors
  • 2 (identical?) video cards,
  • a mother board that supports at least two video cards
  • an editor like vi(m), emac, nano, ...
  • a compiler
  • electricity.

So let's get rolling.

I assume you've got your hardware all set up properly and you just booted with the 2 videocards with on each video card a screen attached. There's a big chance one of your monitors is working and the other one isn't or is a mirror of the first monitor.

Either way, let's check if they were detected properly.
Code:

username@host:~$ lspci | grep -i vga
01:00.0 VGA compatible controller: NVIDIA Corporation NV44 [GeForce 6200 TurboCache(TM)] (rev a1)
02:00.0 VGA compatible controller: NVIDIA Corporation NV44 [GeForce 6200 TurboCache(TM)] (rev a1)
username@host:~$ ls /dev/fb*
/dev/fb0  /dev/fb1
username@host:~$

If you see 2 separate video cards and if you see 2 framebuffer devices (/dev/fb0 and /dev/fb1 then the hardest part is over :-).

The next step is creating a file with the following C code in it an compile it. If you don't have a compiler installed or if you are not sure you can always install it yourself:
On Debian
Code:

apt-get upgrade
apt-get install build-essential

On CentOS, it should be something like this:
Code:

yum groupinstall "Development Tools" "Development Libraries"
Then create a text file with this content. And in case this website ever goes down, I included the code here:
Code:

/* this is userspace utility which allows you to redirect console to another fb device
 * You can specify devices & consoles by both numbers and devices. Framebuffers numbers
 * are zero based (/dev/fb0 ... ), consoles begins with 1 (/dev/tty1 ... )
 */
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
        struct fb_con2fbmap c2m;
        char* fbPath;
        u_int32_t con, fb;
        char* e;
        char* progname = strrchr(argv[0], '/');
        int f;

        if (progname)
                progname++;
        else
                progname = argv[0];
        if (argc < 3) {
                fprintf(stderr, "usage: %s fbdev console\n", progname);
                return 1;
        }
        fb = strtoul(argv[1], &e, 10);
        if (*e) {
                struct stat sbf;

                if (stat(argv[1], &sbf)) {       
                        fprintf(stderr, "%s: are you sure that %s can be used to describe fbdev?\n", progname, argv[1]);
                        return 1;
                }
                if (!S_ISCHR(sbf.st_mode)) {
                        fprintf(stderr, "%s: %s must be character device\n", progname, argv[1]);
                        return 1;
                }
                fb = sbf.st_rdev & 0xFF;
                if (fb >= 32)
                        fb >>= 5;
                fbPath = argv[1];
        } else
                fbPath = "/dev/fb0";
        con = strtoul(argv[2], &e, 10);
        if (*e) {
                struct stat sbf;

                if (stat(argv[2], &sbf)) {
                        fprintf(stderr, "%s: are you sure that %s can be used to describe vt?\n", progname, argv[2]);
                        return 1;
                }
                if (!S_ISCHR(sbf.st_mode)) {
                        fprintf(stderr, "%s: %s must be character device\n", progname, argv[2]);
                        return 1;
                }
                con = sbf.st_rdev & 0xFF;
        }
        c2m.console = con;
        c2m.framebuffer = fb;
        f = open(fbPath, O_RDWR);
        if (f < 0) {
                fprintf(stderr, "%s: Cannot open %s\n", progname, fbPath);
                return 1;
        }
        if (ioctl(f, FBIOPUT_CON2FBMAP, &c2m)) {
                fprintf(stderr, "%s: Cannot set console mapping\n", progname);
                close(f);
                return 1;
        }
        close(f);
        return 0;
}

Save the file and compile it with gcc. Once it has compiled try to run it.
Code:

username@host:~$ gcc -o con2fb con2fb.c
username@host:~$ ./conf2fb /dev/fb0 /dev/tty1
username@host:/$ ./conf2fb /dev/fb1 /dev/tty2

The second line connected the first framebuffer device (/dev/fb0) to your first terminal device (/dev/tty1). If you press Ctrl-Alt-F1 now, your cursor on one monitor should start blinking and everything you type should go to that monitor. If you type Ctrl-Alt-F2, the cursor should go to the other screen and the keyboard is "attached" to the other screen.

Congratulations! You've got yourself a helluva working multi-monitor setup :-)

Feel free to comment. This is a very short howto.
  • Make the configuration persistent across reboots
  • Why exactly does the monitor that does not have the focus stop updating? Is there a fix or workaround for that?
  • Check if it works with two different video cards. I have tested this before with a AMD and NVIDIA combination but that did not work (only /dev/fb0 and no /dev/fb1 created, also one video card not detected while both work well separately)
  • Can this also work with one video card with 2 outputs? (I've tested it but I only get /dev/fb0 and no /dev/fb1. Do we really need 2 separate video cards?)
  • Check if it works with more than 2 monitors
  • Include more troubleshooting

Miati 12-23-2014 02:30 PM

Out of curiosity, is this for enviroments without x (or any gui)
I can do this very easily in Linux mint by simply dragging the emulator to the other monitor.

But if this is meant for without x - very impressive.

bucovaina78 12-24-2014 01:58 AM

Yes indeed, there are multiple programs for multiple monitor support in X. At the moment I'm running exclusively in framebuffer and I consider tmux to be my "window manager". X is currently not installed and from now on I've got even less reasons to do so :-).

And I don't know about the impressive part. It's no rocket science, I didn't write the code myself and I couldn't if I wanted to. It's just perseverance of a geek. However, I've got to say it looks rather cool on my desk, 2 1920x1200 24" monitors with each their own tmux session running :-).

fatmac 12-24-2014 03:44 AM

If you want it to keep updating, I think 'screen' multiplexer does that in the background, so maybe run your sessions inside of 'screen'(?).

bucovaina78 12-24-2014 04:18 AM

Thanks for your input.

I am already using tmux as a terminal multiplexer which is an alternative to 'screen'. When one monitor 'loses focus' the updating stops, also in tmux. I can try it at home with screen but I expect the same behaviour.

Why do I expect no change?
I'm not sure about this but my best guess is that this behaviour has to do with how the kernel "efficiently" stops updating a framebuffer it assumes is not shown/in use anyway. Tmux or screen are still updating but the framebuffer simply isn't so the image you can see on the monitor simply doesn't change.

But I might be wrong about this assumption :-)

alazyworkaholic 11-02-2017 12:07 PM

Single video card with multiple outputs?
 
Can the solution above be adapted to a single video card with multiple outputs of different resolutions? My current (X) setup has a 24" 1900x1200 via DVI, and a 19" 1440x900 via VGA. Otherwise, this is exactly what I wanted, and I've been looking for a solution for a few hours.


All times are GMT -5. The time now is 05:06 PM.