view pwplib/linuxcon.c @ 71:a87eb778f225

Improvements to the MinGW crossbuild. Should now build with default tools from Debian mingw packages, though you need Win32 version of libSDL with the necessary headers and so on in addition. 64-bit builds not tested and probably won't work. Tested on Debian 7.0, earlier won't work. binutils-mingw-w64-i686 gcc-mingw-w64-i686 mingw-w64-i686-dev
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 14 Aug 2012 03:08:10 +0300
parents 77f40a3c0095
children
line wrap: on
line source

#include "config.h"

#ifdef DRIVE_LINUXCON

#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/kd.h>

#include "pwplib.h"

#include "tty.h"

/******************** vcsa code ********************/

struct{
   int fd;
   int width,height;

   int fontw,fonth;
   u8*fontd;
   char*fontd_tab;
   
   /* add cfd (control fd) or something */
}pwp_linuxcon;

void vcsa_dump_attr()
{
   u8 *buf=pwplib.videobuf.d;
   int ptr=4+pwp_linuxcon.width*
           ((pwp_linuxcon.height-pwplib.videobuf.height)&~1);
   if(ptr<4)ptr=4;

   if(pwp_linuxcon.width==pwplib.videobuf.width)
   {
      lseek(pwp_linuxcon.fd,ptr,SEEK_SET);
      write(pwp_linuxcon.fd,buf,
            pwplib.videobuf.width*pwplib.videobuf.height*2);
   }else
   {
      int y=0,y1=pwplib.videobuf.height,w=pwplib.videobuf.width;
      ptr+=((pwp_linuxcon.width-pwplib.videobuf.width)&~1);
      if(y1>pwp_linuxcon.height)y1=pwp_linuxcon.height;
      if(w>pwp_linuxcon.width)w=pwp_linuxcon.width;
      w<<=1;
      for(;y<y1;y++)
      {
         lseek(pwp_linuxcon.fd,ptr,SEEK_SET);
         write(pwp_linuxcon.fd,buf,w);
         buf+=pwplib.videobuf.width*2;
         ptr+=pwp_linuxcon.width*2;
      }
   }

   pwplib.timer_counter+=pwp_linuxcon.width*pwp_linuxcon.height*2;
}

int vcsa_get()
{
   int vcsa;
   int majmin;

   { struct stat sbuf;
     int stderr2=dup(fileno(stderr));
     fstat(stderr2,&sbuf);
     majmin=sbuf.st_rdev;
     close(stderr2);
   }

   if((majmin&~0x63)==4*256)
   {
      char buf[32];
      sprintf(buf,"/dev/vcsa%i",majmin&63);
      vcsa=open(buf,O_RDWR);
      if(vcsa>=0)return vcsa;
   }
   vcsa=open("/dev/vcsa",O_RDWR);
   if(vcsa>=0)return vcsa;

   return -1;
}

int vcsa_init() /* init vcsa device */
{
   unsigned char vcsahdr[4];
   int vcsa=vcsa_get();
   if(vcsa<0)return 0;

   read(vcsa,vcsahdr,4);
   pwp_linuxcon.fd=vcsa;
   pwplib.videobuf.height=pwp_linuxcon.height=vcsahdr[0];
   pwplib.videobuf.width=pwp_linuxcon.width=vcsahdr[1];

   pwpwrite("* using vcsa device\n");

   pwplib.dump_attr=vcsa_dump_attr;
   return 1;
}


/********************************************************/

/*** some people are lazy to update their headers ... ***/

#ifndef KDFONTOP
#define KDFONTOP        0x4B72

struct console_font_op {
        unsigned int op;
        unsigned int flags;
        unsigned int width, height;
        unsigned int charcount;
        unsigned char *data;
};

#define KD_FONT_OP_SET          0
#define KD_FONT_OP_GET          1
#define KD_FONT_OP_SET_DEFAULT  2
#define KD_FONT_OP_COPY         3

#define KD_FONT_FLAG_DONT_RECALC        1
#endif

/********************************************/

enum {
   GLY_CRAP = 0,
   GLY_BLANK,
   GLY_FULL,
   GLY_TOP,
   GLY_BOTTOM,
   GLY_LEFT,
   GLY_RIGHT,
};

static int tty_linux_setfont(u8 *fontd,int w,int h)
{
   struct console_font_op fontop;
   fontop.op=KD_FONT_OP_SET;
   fontop.flags=0;
   fontop.data=fontd;
   fontop.charcount=256;
   fontop.width=w;
   fontop.height=h;

   return ioctl(2,KDFONTOP,&fontop);
}

static int tty_linux_setfont_tab()
{
   u8 *f, *font = malloc(pwp_linuxcon.fontw*32*sizeof(char));
   char *s = pwp_linuxcon.fontd_tab;

    int i,x,y;

    for(i=0;i<256;i++)
      for(y=0;y<32;y++)
      {
         int b=0,x1=(pwp_linuxcon.fontw+7)&~7;
         for(x=0;x<x1;x++)
         {
            int pix;

            if(y<pwp_linuxcon.fonth &&
               x<pwp_linuxcon.fontw)
               pix=*s++?1:0;else pix=0;
               
            b<<=1;
            b|=pix;

            if((x&7)==7)
            {
               *f++=b;
               b=0;
            }
         }
      }

   return tty_linux_setfont(font,pwp_linuxcon.fontw,pwp_linuxcon.fonth);
}

void tty_linux_restorefont(void)
{
   tty_linux_setfont(
     pwp_linuxcon.fontd,
     pwp_linuxcon.fontw,
     pwp_linuxcon.fonth);
}

int tty_linux_fixfont()
{
#if 0
   char newfont[pwp_linuxcon.fontw*
                pwp_linuxcon.fonth*sizeof(char)];

   glyphgen_fixtoibm(
      pwp_linuxcon.fontd_tab,
      pwp_linuxcon.fontw,
      pwp_linuxcon.fonth);

   return tty_linux_setfont_tab();
#endif

   return 0;
}

/**********************************/

static int tty_linux_analyzefont()
{
   u8 analysis[256];

   u8*s=pwp_linuxcon.fontd;
/*   char*d=pwp_linuxcon.fontd_tab; */
   int c=0;

/*   fprintf(stderr,"font analysis?\n");*/

   for(;c<256;c++)
   {
      int x0=33,x1=-1,y0=33,y1=-1,x,y;
      int dens=0;
      
      for(y=0;y<32;y++)
      {
         int byte;
         for(x=0;x<pwp_linuxcon.fontw;x++)
         {
            if(!(x&7))byte=*s++;

/*            if(y<pwp_linuxcon.fonth)*d++=byte&128;*/

            if(byte&128)
            {
               if(x<x0)x0=x;
               if(x>x1)x1=x+1;
               if(y<y0)y0=y;
               if(y>y1)y1=y+1;
               dens++;
            }
            byte<<=1;
         }
      }

      {int a=GLY_CRAP;
       int w=(x1-x0),h=(y1-y0);

       if(h<=0)a=GLY_BLANK; 
       else
       {
          if(w>=pwp_linuxcon.fontw-1)
          {
             if(h>=pwp_linuxcon.fontw-1)a=GLY_FULL;
             else
             if(y1>=pwp_linuxcon.fontw-2)a=GLY_BOTTOM;
             else
             if(!y0)a=GLY_TOP;
          }
           else
          if(h>=pwp_linuxcon.fonth-1)
          {
             if(x1>=pwp_linuxcon.fonth-2)a=GLY_RIGHT;
             else
             if(!x0)a=GLY_LEFT;
          }
       }
       analysis[c]=a;
/*       if(a)fprintf(stderr,"char %d: %d\n",c,a);*/
      }
     }
   
   if(analysis[176]==GLY_FULL &&
      analysis[177]==GLY_FULL &&
      analysis[178]==GLY_FULL &&
      analysis[219]==GLY_FULL &&
      analysis[220]==GLY_BOTTOM &&
      analysis[223]==GLY_TOP) return 2;

/*   fprintf(stderr,"done\n");*/

   return 1;
}

int tty_linux_getfont()
{
   {
      struct console_font_op fontop;
      fontop.op=KD_FONT_OP_GET;
      fontop.flags=0;
      fontop.data=NULL;
      fontop.charcount=0;

      /* if handle 2 doesn't work, try handles 1 and 0?
         also with vcsa */

      /* use this bitreverter somewhere (X11-1bpp code?) not here.
         replaces lookups in fast machines.

 	a=((a&0xf0f0f0f0)>>4)|((a&0x0f0f0f0f)<<4);
 	a=((a&0xcccccccc)>>2)|((a&0x33333333)<<2);
 	a=((a&0xaaaaaaaa)>>1)|((a&0x55555555)<<1);
      */

      ioctl(2,KDFONTOP,&fontop);
      if(fontop.charcount)
      {
         pwp_linuxcon.fontw=fontop.width;
         pwp_linuxcon.fonth=fontop.height;

         if(!fontop.data)
         {
            fontop.data=malloc(((pwp_linuxcon.fontw+7)>>3)*32*
                                fontop.charcount*sizeof(u8));
            fontop.op=KD_FONT_OP_GET;
            fontop.flags=KD_FONT_FLAG_DONT_RECALC;
            if(ioctl(2,KDFONTOP,&fontop)<0)
               goto oldcall;
         }

         pwp_linuxcon.fontd=fontop.data;
         goto gotfont;
      }
   }

   oldcall:
   {
      struct consolefontdesc fontx;
      fontx.chardata=malloc(512*32*sizeof(u8));

      if(ioctl(2,GIO_FONTX,&fontx)<0)return 0;

      pwp_linuxcon.fontw=8;
      pwp_linuxcon.fonth=fontx.charheight;
      pwp_linuxcon.fontd=fontx.chardata;
   }

   gotfont:
   
   pwp_linuxcon.fontd_tab=
       malloc(pwp_linuxcon.fontw*pwp_linuxcon.fonth*sizeof(char));
   
   return tty_linux_analyzefont();
}

/********************************************************/

int tty_linux_initstring()
{
   write(pwp_tty.fd,"\33[11m",5*sizeof(char)); /* select ibmpc charset */
   tty_vt_initstring();
}

int tty_linux_init()
{
   if(!vcsa_init())
   {
      pwplib.dump_attr=tty_ansicol_dump_attr;
      pwplib.prep_attr=tty_ansicol_prep_attr;
      pwpwrite("* no vcsa access - using tty\n");
      /* send init */
   }

   {int i=tty_linux_getfont();

    pwpwrite("* font analysis: ");
    
    if(i==0)pwpwrite("can't access - assuming ibm\n");else
    if(i==1)pwpwrite("no ibm rasters - using ascii\n");else
    if(i==2)pwpwrite("ibm rasters found - using ibm\n");

    if(i==0 || i==2) conv_init(2,0,0);
                else conv_init(2,2,1);
   }

   tty_linux_initstring();
}

#endif

/*
    additional stuff:

      - font customization:
        - save font
        - if evil: if font bigger than 8x8, change to 8x8
        - include rasterchars (64 chars as in vt220 driver)
        ...
        - restore old font
*/