//st4110 Copyright (C) 1989-2004 I.Pedley (CTPP) Wed 16-Feb-2000 at 21:23:44

//driver for Fujistu Stylistic ST4110
//a special case because so far, after device reset
//(which returns PnP info at 1200 baud)
//I am unable to get the device to work

//however, it is active at boot time, so by placing this driver
//in the COM drvtbl, I can detect the digitiser and install it
//before comdrv1

//note that this DRV is AFTER comdrv0 and comdrv1, because the
//DRV table is searched backwards for a match (to allow installable
//DRVs to override the inbuilt DRVs)

#pragma breakpoints on

#include {time.htm}
#include {conio.htm}
#include {string.htm}
#include {pci.htm}
#include {dev.htm}
#include {com.htm}

#include {stdlib.htm}
#include {gl.htm}
#include {msg.htm}

#include {accdis.htm}
#include {svga.htm}
#include {vesa.htm}
#include {vga.htm}


SL  detectCOMport(DEV* d);
VD  setCOMbaud(DEV* d,UL baudrate);

SL  st4110svc(DEV* d,UL service)
{
//16550 UART services
    UL  port=d->iores->start;
    UL  n,c,p,q;

switch(service)
    {//Mandatory message support//////////////////
     case DM_IDENT:
        n=0;
        if(detectCOMport(d)){return 1;}
        port=d->sv0;
        outp(port+2,0x81);           //attempt to set fifo on, threshold 8 bytes
        if((inp(port+2)&0xc0)!=0xc0){return 1;} //its not a 16550 UART
        UL baud=getCOMbaud(port);
        if((baud==BAUD19200)&&(port==0x220)){return 0;}
        return 1;
     case DM_HANDLER:
        switch(d->svtrg&0x0f)
            {
             case 0x01:inp(port);
                n=d->svtrg;break;
             case 0x06://overrun,parity,frame error or break
                if(inp(port+5)&2){outp(port+2,0);outp(port+2,0x81);}
                break;
             case 0x0c:
             case 0x04:
                UL fifo=0;
                do {
                    c=d->sv0=inp(port);
                    writebuf(d,(UC*)&c,1);
                    //downline hardware interrupt signal mechanism
                    if(d->skt&&d->skt->drv)
                        {
                         d->skt->svtrg=d->svtrg;
                         d->skt->sv0  =d->sv0;
                         (*d->skt->drv->svc)(d->skt,DM_CHILDHANDLER);
                         d->skt->svctr++;
                        }
//                    if(++fifo==16){break;}
                   }
                while(inp(port+5)&1);
                break;
             case 2:
                n=d->svtrg;
                break;
            }
//        catdisp(46,40,"Com svtrg=%04X   %8l         ",&d->svtrg,&d->svctr);
//        *(UL*)0xfec00040=0x24;
//        *(UL*)0xfee000b0=0x24;
        return 0;
     case DM_TRIGGER:
        q=inp(port+2)&0x0f;
        p=inp(port+6);
        return (p<<8)+q;
     case DM_PREINIT:   //setups before interrupts are running
        return 0;
     case DM_INIT:
        initbuf(d,256,1);
        //ST4110 digitiser is ready at boot-time but interrupts are off
        outp(port+1,1);     //interrupts on
        DEV* sub=initdev(dpCOM,dtST4110,0,d,0,0);
        if(sub)
            {
             PTR* p=(PTR*)sub->usr;
             p->flags|=mfDIG;
             p->t=p->l=0;
             p->b=3995;p->r=5310;
            }
        return 0;
     case DM_TERM:
        //do nothing or ST4110 digitiser goes to sleep
        termbuf(d);
     case DM_RESET:
     case DM_HALT:
     case DM_RESUME:
        return 0;
     case DM_CLIDISPINFO:
        CH* str=getbaudstr(d);
        clidisplay("Baud rate for %sc1400 is %sc1400",d->name,str);
        if(d->usr)
            {
             clidisplay("PnP buffer, length %4l bytes:",d->usr);
             UL  n,m=*(UL*)d->usr;
             for(n=0;nusr+4+n*16,d->usr+4+n*16);}
            }
        return 0;
     //device-specific section//////////////////
     case DM_GETBAUDRATE:
        return getCOMbaud(port);
     case DM_SETBAUDRATE:
        setCOMbaud(d,d->sv0);return 0;
        return 0;
    }
}

VD  st4110rawdecode(DEV* d,PTR* p)
{
//decode raw device stream into CURSOR->status,CURSOR->dx,CURSOR->dy

//Fujitsu Stylistic 5-byte encoding is:
//
// bits:  7      6      5      4      3     2     1     0
//byte0   1      0   proximity 0      0     0   right  left
//                     flag                      btn    btn
//byte1 and 2   16-bit X co-ord   msb, lsb
//byte3 and 4   16-bit y co-ord   msb, lsb

    SL  st=d->buf[0];

//    SL  dx=*(UI*)&d->buf[1];
//    SL  dy=*(UI*)&d->buf[3];
    SL  dx=((SL)(d->buf[1])<<7)+d->buf[2];
    SL  dy=((SL)(d->buf[3])<<7)+d->buf[4];

    //swap dx,dy using p->dx,p->dy as placeholders
    if(p->flags&mfSWXY)
        {p->dx=dy;p->dy=dx;}
    else{p->dx=dx;p->dy=dy;}

    //set mouse button status flags
    if(p->flags&mfSWLR)
        {
         if(st&0x01){p->status|=msRIGHT;}
         else       {p->status&=~msRIGHT;}
         if(st&0x02){p->status|=msLEFT;}
         else       {p->status&=~msLEFT;}
       }
    else
       {
        if(st&0x02){p->status|=msRIGHT;}
        else       {p->status&=~msRIGHT;}
        if(st&0x01){p->status|=msLEFT;}
        else       {p->status&=~msLEFT;}
       }
}

VD  mouseevent(DEV* d,DEV* vga,PTR* p);
DEV*  findbootmonitor(VD);

SL  st4110digsvc(DEV* d,UL service)
{
//Fujitsu Stylistic digitiser
    DEV*   scr=NULL;
    DISP* disp=NULL;
    PTR*   ptr=(PTR*)d->usr;
    if(ptr)
        {
         scr=ptr->s;
         if(scr)
            {
             disp=(DISP*)scr->usr;
            }
        }

switch(service)
    {//Mandatory message support//////////////////
     case DM_IDENT:
        return 0;               //COM DEV decides is this device is present
     case DM_PREINIT:
        return 0;               //device MUST support DM_PREINIT
     case DM_INIT:
        initbuf(d,5,1);
        d->usr=(PTR*)calloc(sizeof(PTR),1);
        if(d->usr)
            {
             ptr=(PTR*)d->usr;
             ptr->xdir=ptr->ydir=1;//ptr->ydir=-1;
             ptr->xratio=ptr->yratio=1;
             d->sv0=(UL)finddevice("cga");
             (*d->drv->svc)(d,DM_SETDISPLAY);
             ptr->vga=findbootmonitor();
            }
        return 0;
     case DM_SETDISPLAY:
        return 0;
     case DM_TERM:
        free(d->usr);
        termbuf(d);
        return 0;
     case DM_CHILDHANDLER:
        if(!d->bufin)   //resynch, if ! inbyte&0x80 on byte 0 of the five
            {
             if(d->sv0&0x80){writebuf(d,(UC*)&d->sv0,1);}
             else return 0;
            }
        else {writebuf(d,(UC*)&d->sv0,1);} //wraps bufin to 0 after 5 bytes
        if(!d->bufin)
            {//we have a sequence of five bytes in the buffer now
//             clidisplay("%5H",d->buf);
             if(ptr)
                {
                 st4110rawdecode  (d,ptr);
                 mouseevent      (d,ptr->vga,ptr);
//                 catdisp(48,40,"st=%02X,x=%5l,y=%5l",&disp->c.status,&disp->c.posx,&disp->c.posy);
//                 catdisp(48,20,"st=%02X,x=%5i,y=%5i sx=%5l,sy=%5l",&disp->c.status,d->buf+1,d->buf+3,&disp->c.posx,&disp->c.posy);
                 SL  dx=((SL)(d->buf[2])<<7)+d->buf[1];
                 SL  dy=((SL)(d->buf[4])<<7)+d->buf[3];
//                 catdisp(48,20,"st=%02X,x=%5l,y=%5l sx=%5l,sy=%5l",&disp->c.status,&dx,&dy,&disp->c.posx,&disp->c.posy);
                }
            }
        return 0;
     case DM_CLIDISPINFO:
        return 0;
    }
}