Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Nov 1998 12:36:10 -0500
From:      Christopher Masto <chris@netmonger.net>
To:        Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
Cc:        hackers@FreeBSD.ORG
Subject:   Re: Some curiosity about syscons
Message-ID:  <19981101123610.A7850@netmonger.net>
In-Reply-To: <199811011131.UAA15844@zodiac.mech.utsunomiya-u.ac.jp>; from Kazutaka YOKOTA on Sun, Nov 01, 1998 at 08:31:24PM %2B0900
References:  <19981026230208.A8159@netmonger.net> <199811011131.UAA15844@zodiac.mech.utsunomiya-u.ac.jp>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, Nov 01, 1998 at 08:31:24PM +0900, Kazutaka YOKOTA wrote:
> You have to poll a CRTC status port for vertical retrace period.
> 
> As Mike has already suggested, it is probably best to do this sort of
> things as a screen saver LKM.  The screen saver can do whatever
> it wants (just like DOS programs... :-)
> 
> The tricky thing is that syscons will instantly deactivate the 
> screen saver LKM as soon as a key is pressed (or mouse is moved).

Doesn't the screen saver only get run periodically?  Hmm..

Anyway, I have something which works a lot more reliably than my
original call-scrn_update()-excessively hack.  Of course, this is
about four hacks in one.

Because I stubbornly didn't want to get involved in graphics mode, but
I found out that unfortunately, the lines I need to draw are slightly
closer together than one 16-pixel character (so I couldn't just use
the "IBM line drawing" character 196), I am making a special font that
has two lines per cell, in various spacings, so I can put the right
one down to simulate graphics.  I'm using syscons to load the font,
and mmap to get access to the video memory directly to update the
screen.

I then found out about the bizzaro design of text modes where there
are 8 pixels across per character, but put into a 9-pixel cell.  The
VGA hardware leaves a one-pixel gap between characters, _except_ for
the magic range of the standard IBM line drawing characters, where it
duplicates the 8th column into the 9th.  So I futz with the VGA
registers (thank you, /dev/io) behind syscons' back.. after using
syscons to request 80x30, because I need a 60Hz screen.

Finally, busy-waiting for the vertical retrace completes the evil
picture, and it all comes together.  Then it's just a matter of
putting the pieces back together so the console is again usable.

Here are the preliminary functions.. I know that this is not entirely
kosher, but it's a stupid little program that runs for ten seconds
while the user holds their watch up to the screen.  I'm not yet
dealing with issues like mono vs. color screens, but other than that,
I don't think I'll get yelled at for too much.  There is the slight
matter of not disabling interrupts while programming one of the VGA
registers, but this is a user level program.. I take my chances. :-)

[...]

#define WAIT_RETRACE { while (inb(0x3DA) & 0x08); \
                       while (!(inb(0x3DA) & 0x08)); }

u_short *vmem;
unsigned char font[16*256], oldfont[16*256];

[...]

void txt_init(void)
{
  int p1, p2, l, i=0;
  unsigned char b;
  struct rtprio rtp;

  // Set realtime priority
  rtp.type = RTP_PRIO_REALTIME;
  rtp.prio = 0;
  if (rtprio(RTP_SET, 0, &rtp)) {
    perror("Couldn't set realtime priority; rtprio()");
    exit(-1);
  }

  // Get I/O privileges
  fd = open("/dev/io", O_RDONLY, 0777);
  if (fd == -1) {
    perror("Couldn't open /dev/io");
    exit(-1);
  }

  // Map video memory
  vmem = (u_short *)mmap(0, 0x8000, PROT_READ|PROT_WRITE, 0, 0, 0x18000);
  if (vmem == MAP_FAILED) {
    perror("mmap()");
    exit(-1);
  }

  // Save the current font
  if (ioctl(0, GIO_FONT8x16, oldfont) < 0) {
    perror("Saving font failed; ioctl()");
    exit(-1);
  }

  // Change syscons mode to 80x30 (60hz)
  if (ioctl(0, SW_VGA_C80x30) < 0) {
    perror("Can't change to 80x30; ioctl()");
    exit(-1);
  }
  // 640 pixel mode
  b=inb(0x3CC);
  outb(0x3C2, b & 0xf3);
  // 8 dot clocks
  outb(0x3C4, 0x01);
  b=inb(0x3C5);
  outb(0x3C5, b | 0x01);
  sleep(2);  // Let monitor resync

  // Generate font
  for (p1 = 0; p1 < 16; p1++)
    for (p2 = 0; p2 < 16; p2++)
      for (l = 0; l < 16; l++)
	font[i++] = (l == p1 || l == p2) ? 0xff : 0x00;
  for (l = 16; l < 32; l++)
    font[l] = 0x00;
  // Install font
  if (ioctl(0, PIO_FONT8x16, font) < 0) {
    perror("ioctl()");
    exit(-1);
  }

  WAIT_RETRACE;
  clear_screen();
}

[...]

void draw_2line(int y, int l1, int l2)
{
  int start, stop;
  u_short b;

  start = y * 80;
  stop  = start + 80;

  b = (0x0f << 8) | ((l1 << 4) + l2);
  while (start < stop)
    vmem[start++] = b;
}

-- 
Christopher Masto        Director of Operations  S   NetMonger Communications
chris@netmonger.net        info@netmonger.net   SSS  http://www.netmonger.net
                                                \_/
   Microsoft, I think, is fundamentally an evil company.
   - JAMES H. CLARK

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19981101123610.A7850>