//com.ctp Copyright (C) 1989-2004 I.Pedley (CTPP) Wed 16-Feb-2000 at 21:23:44
#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}
UL comaddr[]={0x3f8,0x2f8,0x3e8,0x2e8};
VD setCOMbaud(UL port,UL baudrate)
{
UL a,b,c=inp(port+1);
outp(port+3,0x80); //set DLAB on
outp(port ,baudrate&0xff);
msecdelay(1);
outp(port+1,baudrate>>8);
outp(port+3,3); //8 data bits
outp(port+1,0);
a=inp(port+5);
b=inp(port+4);
msecdelay(20);
outp(port+1,c);
}
UL getCOMbaud(UL port)
{
UL baudrate;
UL portbits=inp(port+3);
outp(port+3,0x80); //set DLAB on
baudrate=inpw(port);
outp(port+3,portbits);
return baudrate;
}
UL serialoutchar(UL port,UL c)
{//output a character to a serial port, using PIO
UL t=uptime;
outp(port,c);
while(!(inp(port+5)&0x20))
{
if(uptime>t+50){return 0;}
}
return 1;
}
UL serialoutstr(UL port,CH* str)
{
while(*str)
{
if(!serialoutchar(port,*str)){return 0;}
str++;
}
return 1;
}
UL serialinchar(UL port)
{//input a character to a serial port, using PIO
UL t=0;
while(!(inp(port+5)&1))
{
t++;
if(t==500000){return 0;}
}
return inp(port);
}
UL serialinstr(UL port,CH* str,UL maxlen)
{
UL n=0;
while(*str++=serialinchar(port))
{
n++;
if(n==maxlen){break;}
}
*str=0;
return n;
}
VD setISR(UL port)
{
outp(port+1,0x0d);
}
VD clrISR(UL port)
{
outp(port+1,0x00);
}
VD setISR(DEV* d)
{
// UL n=d->svctr;
outp(d->iores->start+1,0x0d);
// while(n==d->svctr);
}
VD xmit(DEV* d,UC c)
{
UL n=d->svctr;
outp(d->iores->start,c);
while(inp(d->iores->start+5)&0x20);
}
VD clrISR(DEV* d)
{
outp(d->iores->start+1,0x00);
}
VD setCOMbaud(DEV* d,UL baudrate)
{
UL port=d->iores->start;
clrISR(d);
outp(port+3,0x80); //set DLAB on
outp(port,baudrate&0xff);
outp(port+1,baudrate>>8);
outp(port+3,3); //8 data bits
outp(port+1,0);
setISR(d);
}
VD resetCOM(DEV* d)
{
UL port=d->iores->start;
setISR(d);
outp(d->iores->start+4,0x00);
if(inp(port+2)&4)
{while(inp(port+5)&1){inp(port);}
if((inp(port+2)&0xc0)==0xc0){outp(port+2,0x00);outp(port+2,0xc1);}
// eoiIRQ(d->irqres->irqno);
}
msecdelay(50);
outp(d->iores->start+4,0x0b);//msecdelay(20);
}
//VD serialintson(UL port)
//{//switch serial port receiver interrupts on
// setISR(port);msecdelay(20);
// if(inp(port+4)){outp(port+4,0);msecdelay(100);} //GPO2 off forces reset
// outp(port+4,0x0b); //GPO2 on to connect IRQ
// inp(port);
// clrISR(port);
// setISR(port);
//// while(inp(port+5)&1){inp(port);}
//}
VD serialintson(UL port)
{//switch serial port receiver interrupts on
setISR(port);msecdelay(20);
if(inp(port+4)){outp(port+4,0);msecdelay(100);} //GPO2 off forces reset
outp(port+4,0x0b); //GPO2 on to connect IRQ
inp(port);
clrISR(port);
setISR(port);
// while(inp(port+5)&1){inp(port);}
}
VD serialintsoff(UL port)
{//switch all serial port interrupts off using interrupt enable register only
clrISR(port);
outp(port+4,0x00); //knock GPO2 off
}
//at-a-glance divisors for the 12 standard baud rates (1.8432MHz clock)
UL bauddvsr[12]={0x0417, 0x0300, 0x0180, 0x00c0,
0x0060, 0x0030, 0x0018, 0x000c,
0x0006, 0x0003, 0x0002, 0x0001};
CH* baudstr[12]= {"110", "150", "300", "600",
"1200", "2400", "4800", "9600",
"19200","38400","57600","115200"};
UL parsebaud(CH* str)
{
UL n;
for(n=0;n<12;n++)
{
if(!stricmp(str,baudstr[n])){return bauddvsr[n];}
}
return 0;
}
CH* getbaudstr(UL dvsr)
{
UL n;
for(n=0;n<12;n++)
{
if(dvsr==bauddvsr[n]){return baudstr[n];}
}
return "unset";
}
#pragma breakpoints on
SL detectCOMport(DEV* d)
{//called from DM_IDENT, must use d->sv0 to locate port!
UL port=d->sv0;
UL n;
for(n=0;n<8;n++){if(inp(port+n)!=0xff){n=10;}}
if(n==8){return 1;} //ports all read 0xff, no serial port here
UL tmp=inp(port+7);
outp(port+7,0xaa);
n=inp(port+7);
if(n!=0xaa){return 1;} //scratchpad is not read/write, no serial port here
outp(port+7,tmp);
outp(port+1,0);
return 0;
}
SL detectFSdig(DEV* d)
{
//special case for Fujitsu Stylistic 1000 inbuilt digitiser
//needed because this device doesn't appear in PnP info, or in
//BIOS data area
UL port=d->iores->start;
//Fujitsu stylistic-specifics
if(inp(port+1)!=1){return 1;}
if(getCOMbaud(port)!=BAUD19200){return 1;}
d->flg|=DF_FSDIG;
// DEV* sub=initdev(dpCOM,dtFSDIG,0,d,0,0);
// if(sub)//..initialise downline interrupt signalling
// {d->flg|=DF_CHILDHANDLER;}
return 0;
}
CH* strstr(CH* str1,CH* str2)
{
CH* ptr=strchr(str1,*str2);
if(ptr)
{
if(!memcmp(ptr,str2,strlen(str2))){return ptr;}
}
return NULL;
}
VD secpoll(UL hsec);
SL echochar(DEV* d,UL c,UL delay)
{
outp(d->iores->start,c);msecdelay(delay);
UC c1;
if((readbuf(d,&c1,1)==1)&&(c==c1)){return 0;}
return 1;
}
SL detectMDM(DEV* d)
{
// resetCOM(d);
// setbaudrate(d,BAUD1200);
UL sts=inp(d->iores->start+6);
// if((sts&0x30)!=0x30){return 1;} //no Data Set Ready and Clear to Send
if(!(sts&0x10)){return 1;} //no Clear to Send
// msecdelay(150);
// outp(d->iores->start+2,0);
if(echochar(d,'A', 100)){return 1;}
if(echochar(d,'T', 100)){return 1;}
if(echochar(d,'\r',100)){return 1;}
// outp(d->iores->start+2,0x81);
// serialoutstr(d->iores->start,"AT\r");
SL n;CH* ptr;
for(n=0;n<5;n++)
{
msecdelay(100);
// if(ptr=memchr(d->buf,'A',d->buflen))
// {if(!memcmp(ptr,"AT",6)){return 0;}}
if(strstr((CH*)d->buf,"AT"))
{if(strstr((CH*)d->buf,"OK")){return 0;}}
}
return 1;
}
SL detectGPS(DEV* d)
{
// resetCOM(d);
setbaudrate(d,BAUD4800);
// secpoll(25);
//// msecdelay(10);
// UL port=d->iores->start;
// if(inp(port+2)&4)
// {while(inp(port+5)&1){inp(port);} //clear FIFO overrun
// outp(port+2,0x81);inp(port+6);}
//// d->bufin=d->bufout=0;
// setISR(d);
// msecdelay(10);
// secpoll(50);
// if(!d->bufin){return 1;}
UL n;
UC* ptr;
for(n=0;n<20;n++)
{
secpoll(10);
// msecdelay(10);
// if(strstr((CH*)d->buf,"$GP")){return 0;}
if(ptr=memchr(d->buf,'$',d->buflen))
{if(!memcmp(ptr,"$GP",3)){return 0;}else{*ptr=0;}}
// if(d->bufin&&(n>5)){break;}
}
setbaudrate(d,BAUD9600);
for(n=0;n<15;n++)
{
secpoll(10);
// msecdelay(10);
// if(strstr((CH*)d->buf,"$GP")){return 0;}
if(ptr=memchr(d->buf,'$',d->buflen))
{if(!memcmp(ptr,"$GP",3)){return 0;}else{*ptr=0;}}
}
return 1;
}
SL detectexternalCOMdevice(DEV* d)
{
DEV* sub;
CH* ptr;
//first wait for PnP device to stop sending info
UL n,m;
do
{
n=d->bufin; //wait up to half a second for device to
for(m=0;m<25;m++) //start sending PnP info
{
// msecdelay(10); //breakout every 10msec for quicker devices
secpoll(2); //breakout every 10msec for quicker devices
if(n!=d->bufin){break;}
}
// if(d->bufin>200)
// {//continuous stream COM device connected maybe GPS
//// outp(d->iores->start+1,0);
// TRYGPS:
// if(!detectGPS(d))
// {
// sub=initdev(dpCOM,dtGPS,0,d,0,0);
// return 0;
// }
// else {return 1;}
// }
}
while(n!=d->bufin);
if(d->bufin)
{
d->usr=calloc(1,d->bufin+4);
if(d->usr){*(UL*)d->usr=d->bufin;memcpy(d->usr+4,d->buf,d->bufin);}
if(d->buf[0]=='M')
{//brk dev com2
sub=initdev(dpCOM,dtMSM,0,d,0,0);
// if(sub)//..initialise downline interrupt signalling
// {d->flg|=DF_CHILDHANDLER;}
return 0;
}
else // if(d->buf[0]=='T')
{
ptr=strchr((CH*)d->buf,0x28); //search for PnP info block
if(ptr)
{
ptr+=3; //skip 0x28 and PnP version
if(!memcmp(ptr,"KYE0100",7)){sub=initdev(dpCOM,dtKYE0100,0,d,0,0);return 0;}
if(!memcmp(ptr,"WAC0405",7)){sub=initdev(dpCOM,dtWAC0405,0,d,0,0);return 0;}
}
}
}
else
{
if(!detectMDM(d))
{
sub=initdev(dpCOM,dtMDM,0,d,0,0);
return 0;
}
}
// secpoll(50);
// if(!d->bufin){return 1;}
if(!detectGPS(d))
{
sub=initdev(dpCOM,dtGPS,0,d,0,0);
return 0;
}
return 1;
}
//embryo DRVs for COM device
//simple drivers are almost identical, (indeed 16550 handler works fine for
//8250), but two handlers are presented here to show how to use DM_IDENT to
//discriminate between chipsets
SL baud(UL argc,CH* argv[]);
SL com1(UL argc,CH* argv[]);
SL comsvc(DEV* d,UL service)
{
//common code
UL port=d->iores->start;
switch(service)
{
case DM_TRIGGER:
UL q=inp(port+2)&0x0f;
UL p=inp(port+6);
// catdisp(45,40,"Com svtrg=%02X %02X %8l ",&q,&p,&d->svctr);
// if(!q){q=inp(port+6);return q|0x100;}
return (p<<8)+q;
// if(q&1){brk return 0;}
// return inp(port+2)&0x0f;
// return inp(port+2)&4;
case DM_PREINIT: //setups before interrupts are running
detectFSdig(d);
return 0;
case DM_INIT:
initbuf(d,256,1);
if(d->flg&DF_FSDIG){return 0;}
d->flg|=DF_POLL|DF_COMMANDS;d->pollfreq=20;
setCOMbaud(d,BAUD1200);
outp(port+3,2); //set 1200,n,7,1
resetCOM(d);
// serialintson(port);
// if(inp(port+2)&4)
// {while(inp(port+5)&1){inp(port);}
// if((inp(port+2)&0xc0)==0xc0){outp(port+2,0x81);}}
detectexternalCOMdevice(d);
return 0;
case DM_TERM:
if(d->flg&DF_FSDIG){return 0;}
if(d->usr){free(d->usr);d->usr=0;}
serialintsoff(port);
termbuf(d);
return 0;
case DM_RESET:
outp(port+4,0); //GPO2 off forces reset
msecdelay(20);
outp(port+4,0x0b); //GPO2 on to connect IRQ
return 0;
case DM_HALT:
if(d->flg&DF_FSDIG){return 0;}
clrISR(d);
return 0;
case DM_RESUME:
if(d->flg&DF_FSDIG){return 0;}
setISR(d);
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;
case DM_GETCOMMAND:
if(!stricmp((CH*)d->svbuf,"baud")){d->svbuf=(UC*)baud;return 0;}
if(!stricmp((CH*)d->svbuf,"com1")){d->svbuf=(UC*)com1;return 0;}
return 1;
}
}
SL catdisp(UL row,UL col,CH* format,...);
SL comsvc0(DEV* d,UL service)
{
//8250/16450 UART services
UL port=d->iores->start;
switch(service)
{//Mandatory message support//////////////////
case DM_IDENT:
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 a 16550 UART
return 0; //no fifo, we can use this driver
case DM_HANDLER:
switch(d->svtrg&7)
{
case 4:
UC c=d->sv0=inp(port);
writebuf(d,&c,1);
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++;
}
// catdisp(46,40,"Com svtrg=%02X ",&d->svtrg);
break;
case 1:
//not quite sure why this is, but after GPO2 reset
//I sometimes see d->svtrg=1, and this seems to require
//a data input to clear the device
//you see d->svtrg=1 means NO interrupt is pending
//so I can't understand how this handler can be entered
//on this condition
inp(port);
break;
}
return 0;
default:
return comsvc(d,service);
}
}
UL resets;
SL comsvc1(DEV* d,UL service)
{
//16550 UART services
UL port=d->iores->start;
UL n,c,q;
switch(service)
{//Mandatory message support//////////////////
case DM_IDENT:
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
return 0; //got fifo, we can use this driver
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:
// c=d->sv0=inp(port);
// writebuf(d,(UC*)&c,1);
// 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++;
// }
//// catdisp(46,40,"Com svtrg=%02X ",&d->svtrg);
// break;
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_POLL:
if(inp(port+2)&4)
{
outp(port+2,0); //reset FIFO
while(inp(port+5)&1){inp(port);} //clear FIFO overrun
UL irqno=irq0(d)&0xff;
if(irqno==-1){irqno=d->irqres->irqno;}
eoiIRQ(irqno);
outp(port+2,0xc1); //restart FIFO
d->bufin=d->bufout=0; //reset buffer
}
//// if(inp(port+2)&4)
//// {outp(port+2,0x00);outp(port+2,0x81);} //reset FIFO
break;
default:
return comsvc(d,service);
}
}
//type-safe com DEV functions
UL getbaudrate(DEV* d)
{
return (*d->drv->svc)(d,DM_GETBAUDRATE);
}
CH* getbaudstr(DEV* d)
{
UL dvsr=(*d->drv->svc)(d,DM_GETBAUDRATE);
return getbaudstr(dvsr);
}
UL setbaudrate(DEV* d,UL dvsr)
{
d->sv0=dvsr;
return (*d->drv->svc)(d,DM_SETBAUDRATE);
}
SL dclick(PTR* p,UL btn);
VD mpost(PTR* p,SL type);
//SL dclick(CURSOR* p,UL btn)
//{
// MSG m;prevmsg(&m);
// SL diff=uptime-m.uptime;
// if(diff<25)
// {
// switch(btn)
// {
// case msLEFT: if(m.type==mtMLup){return 1;}break;
// case msRIGHT: if(m.type==mtMRup){return 1;}break;
// case msCENTRE:if(m.type==mtMCup){return 1;}break;
// }
// }
// return 0;
//}
//
//EX UL kbdstate;
//
//VD mpost(CURSOR* p,SL type)
//{
//// if(msgflags&msgPS2MOUSE)
// {
// qmsg(type ,p->posx,p->posy,p->press,kbdstate,p->dx,p->dy,0);
// }
//}
VD queuemessages(PTR* p)
{
SL btn;
btn=(p->status^p->olds)&msLEFT;
if(btn)
{//left button status has changed
if(p->status&msLEFT){mpost(p,mtML);if(dclick(p,msLEFT)){mpost(p,mtML2);}}
else {mpost(p,mtMLup);}
}
btn=(p->status^p->olds)&msRIGHT;
if(btn)
{//right button has changed
if(p->status&msRIGHT){mpost(p,mtMR);if(dclick(p,msRIGHT)){mpost(p,mtMR2);}}
else {mpost(p,mtMRup);}
}
btn=(p->status^p->olds)&msCENTRE;
if(btn)
{
//centre button status has changed
if(p->status&msCENTRE){mpost(p,mtMC);if(dclick(p,msCENTRE)){mpost(p,mtMC2);}}
else {mpost(p,mtMCup);}
}
//do extra message when two buttons are down at the same time
btn=(p->status^p->olds)&7;
switch(btn)
{
case msLEFT|msRIGHT: mpost(p,mtMLR);break;
case msLEFT|msCENTRE: mpost(p,mtMLC);break;
case msRIGHT|msCENTRE:mpost(p,mtMRC);break;
}
//send a pressure change message if necessary
if(p->press!=p->oldp){mpost(p,mtMPC);}
//send a mouse moved message if necessary
// if((p->posx!=p->oldx)||(p->posy!=p->oldy)){mpost(p,mtMM);}
if(memcmp(&p->posx,&p->oldx,8)){mpost(p,mtMM);}
//fill in old state variables
// p->olds=p->status;
// p->oldx=p->posx;
// p->oldy=p->posy;
// p->oldp=p->press;
// memcpy(&p->olds,&p->status,16);
}
//raw decoders and device drivers for various pointing devices follow....
//calling mousevent() in os/ps2 posts pointer messages to the system queue
//on creation all pointing devices are bound to boot VGA device
//the idea is: simply set PTR->VGA to switch pointer to a different screen
VD mouseevent(DEV* d,DEV* vga,PTR* p); //now in os/ps2
DEV* findbootmonitor(VD);
VD accelerate(SL* dx,SL* dy);
VD msmouserawdecode(DEV* d,PTR* p)
{
//decode raw device stream into PTR->status,PTR->dx,PTR->dy
// DISP* disp=(DISP*)scr->usr;
// CURSOR* p=&disp->c;
//standard MS mouse 3-byte encoding is:
//
// bits: 7 6 5 4 3 2 1 0
//byte0 0 1 right left
// btn btn
//byte1 0 0 <--dX: left=negative,right=positive----->
//byte2 0 0 <--dY: up=negative, down=positive----->
SL st=d->buf[0];
SC x=(d->buf[1]+((d->buf[0]&0x03)<<6));
SC y=(d->buf[2]+((d->buf[0]&0x0c)<<4));
SL dx=x;
SL dy=y;
if(p->flags&mfACCEL){accelerate(&dx,&dy);}
//swap dx,dy using p->dx,p->dy as placeholders
if(p->flags&mfSWXY)
{p->dx=dy*p->xdir;p->dy=dx*p->ydir;}
else{p->dx=dx*p->xdir;p->dy=dy*p->ydir;}
//set mouse button status flags
if(p->flags&mfSWLR)
{
if(st&0x20){p->status|=msRIGHT;}
else {p->status&=~msRIGHT;}
if(st&0x10){p->status|=msLEFT;}
else {p->status&=~msLEFT;}
}
else
{
if(st&0x10){p->status|=msRIGHT;}
else {p->status&=~msRIGHT;}
if(st&0x20){p->status|=msLEFT;}
else {p->status&=~msLEFT;}
}
}
SL msmsvc(DEV* d,UL service)
{
//Microsoft serial mouse
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,3,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=5;
d->sv0=(UL)finddevice("cga");
(*d->drv->svc)(d,DM_SETDISPLAY);
ptr->flags|=mfACCEL;
ptr->vga=findbootmonitor();
}
return 0;
case DM_SETDISPLAY:
scr=(DEV*)d->sv0;
if(scr)
{
ptr->s=scr;
disp=(DISP*)scr->usr;
ptr->cx=(disp->w/2)-1;
ptr->cy=(disp->h/2)-1;
ptr->mickx=0;
ptr->micky=0;
ptr->flags=mfACCEL;
disp->c.disp=0;
return 0;
}
return 1;
case DM_TERM:
free(d->usr);
termbuf(d);
return 0;
case DM_CHILDHANDLER:
if(!d->bufin) //resynch, if ! inbyte&0x40 on byte 0 of the three
{
if(d->sv0&0x40){writebuf(d,(UC*)&d->sv0,1);}
else return 0;
}
else {writebuf(d,(UC*)&d->sv0,1);} //writebuf wraps bufin to 0 after 3 bytes
if(!d->bufin)
{//we have a sequence of three bytes in the buffer now
// clidisplay("%3H",d->buf);
if(ptr)
{
msmouserawdecode(d,ptr);
mouseevent (d,ptr->vga,ptr);
// catdisp(48,40,"st=%02X,x=%4l,y=%4l",&disp->c.status,&disp->c.posx,&disp->c.posy);
}
}
return 0;
case DM_CLIDISPINFO:
// clidisplay("st=%02X,x=%4l,y=%4l",&disp->c.status,&disp->c.posx,&disp->c.posy);
return 0;
}
}
VD fsdigrawdecode(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 lsb, msb
//byte3 and 4 16-bit y co-ord lsb, msb
SL st=d->buf[0];
// SL dx=*(UI*)&d->buf[1];
// SL dy=*(UI*)&d->buf[3];
SL dx=((SL)(d->buf[2])<<7)+d->buf[1];
SL dy=((SL)(d->buf[4])<<7)+d->buf[3];
//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;}
}
}
SL fsdigsvc(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:
scr=(DEV*)d->sv0;
if(scr)
{
ptr->s=scr;
disp=(DISP*)scr->usr;
ptr->cx=(disp->w/2)-1;
ptr->cy=(disp->h/2)-1;
ptr->mickx=0;
ptr->micky=0;
ptr->flags=mfDIG;
// ptr->t=220; //Fujitsu Stylistic 1000
// ptr->l=0;
// ptr->b=5000;
// ptr->r=6400;
ptr->t=240; //Fujitsu Stylistic 2300
ptr->l=0;
ptr->b=5400;
ptr->r=6800;
ptr->ydir=-1;
disp->c.disp=0;
}
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)
{
fsdigrawdecode (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;
}
}
VD kyerawdecode(DEV* d,PTR* p)
{
//decode raw device stream into PTR->status,PTR->dx,PTR->dy
//Kye/Genius 5-byte encoding is:
//
// bits: 7 6 5 4 3 2 1 0
//byte0 1 proximity 0 1 1 0 right left
// flag btn btn
//byte1 and 2 16-bit X co-ord lsb, msb
//byte3 and 4 16-bit y co-ord lsb, msb
SL st=d->buf[0];
// SL dx=*(UI*)&d->buf[1];
// SL dy=*(UI*)&d->buf[3];
SL dx=((SL)(d->buf[2])<<7)+d->buf[1];
SL dy=((SL)(d->buf[4])<<7)+d->buf[3];
//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;}
}
}
SL kyesvc(DEV* d,UL service)
{
//Kye0100/Genius EasyPen digitiser, 5-byte decode, almost identical to fsdig
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)
{
setbaudrate(d->ifc,BAUD9600);
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);
}
return 0;
case DM_SETDISPLAY:
scr=(DEV*)d->sv0;
if(scr)
{
ptr->s=scr;
disp=(DISP*)scr->usr;
ptr->cx=(disp->w/2)-1;
ptr->cy=(disp->h/2)-1;
ptr->mickx=0;
ptr->micky=0;
ptr->flags=mfDIG;
ptr->t=000;
ptr->l=000;
ptr->b=1500;
ptr->r=2000;
ptr->ydir=-1;
disp->c.disp=0;
}
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)
{
kyerawdecode(d,ptr);
mouseevent (d,ptr->vga,ptr);
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=%5li,y=%5l sx=%5l,sy=%5l",&disp->c.status,&dx,&dy,&disp->c.posx,&disp->c.posy);
}
}
return 0;
case DM_CLIDISPINFO:
return 0;
}
}
VD wacom7rawdecode(DEV* d,PTR* p)
{
//decode raw device stream into PTR->status,PTR->dx,PTR->dy
//Wacom 7-byte encoding is:
//
// bits: 7 6 5 4 3 2 1 0
//byte0 1 proximity 1 0 right|left 0 0 0
// flag btn btn
//byte1 and 2 16-bit X co-ord msb, lsb
//byte3 0 0 0 right left 0 0 0
// btn btn
//byte4 and 5 16-bit y co-ord msb, lsb
//byte6 0 <7-bit signed pressure sense -64 to +63 --->
//also reads zero as pen leaves proximity
SL st=d->buf[3];
SL dx=*(Um*)&d->buf[1];
SL dy=*(Um*)&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&0x08){p->status|=msRIGHT;}
else {p->status&=~msRIGHT;}
if(st&0x10){p->status|=msLEFT;}
else {p->status&=~msLEFT;}
}
else
{
if(st&0x10){p->status|=msRIGHT;}
else {p->status&=~msRIGHT;}
if(st&0x08){p->status|=msLEFT;}
else {p->status&=~msLEFT;}
}
SC pr=d->buf[6]|0x80;
p->press=pr;
}
SL wacsvc(DEV* d,UL service)
{
//Wacom0405 digitiser, uses Fujitsu Stylistic 5-byte decode
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,7,1);
d->usr=(PTR*)calloc(sizeof(PTR),1);
if(d->usr)
{
setbaudrate(d->ifc,BAUD9600);
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:
scr=(DEV*)d->sv0;
if(scr)
{
ptr->s=scr;
disp=(DISP*)scr->usr;
ptr->cx=(disp->w/2)-1;
ptr->cy=(disp->h/2)-1;
ptr->mickx=0;
ptr->micky=0;
ptr->flags=mfDIG;
ptr->t=000;
ptr->l=000;
ptr->b=7490;
ptr->r=10030;
// ptr->ydir=-1;
disp->c.disp=0;
}
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 seven
{
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 7 bytes
if(!d->bufin)
{//we have a sequence of five bytes in the buffer now
// clidisplay("%7H",d->buf);
if(ptr)
{
wacom7rawdecode(d,ptr);
mouseevent (d,ptr->vga,ptr);
// catdisp(48,20,"st=%02X,x=%5p,y=%5p sx=%5l,sy=%5l",&p->status,d->buf+1,d->buf+4,&p->posx,&p->posy);
}
}
return 0;
case DM_CLIDISPINFO:
return 0;
}
}
SL pensvc0(DEV* d,UL service)
{
//8250/16450 UART services
UL port=d->iores->start;
switch(service)
{//Mandatory message support//////////////////
case DM_INIT:
if(d->sts&sfRUNNING){return 0;}
initbuf(d,256,1);
// serialintson(port);
outp(port+1,1);
d->flg|=DF_FSDIG|DF_POLL;
DEV* sub=initdev(dpCOM,dtFSDIG,0,d,0,0);
return 0;
case DM_PREINIT:
return 0;
case DM_IDENT:
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){brk return 1;} //16550 UART on a digitiser?
return 0; //no fifo, we can use this driver
case DM_HANDLER:
switch(d->svtrg&7)
{
case 6://overrun,parity,frame error or break
// if(inp(port+5)&2){outp(port+2,0);outp(port+2,0x81);}
if(inp(port+5)&2){inp(port);}
break;
case 4:
UC c=d->sv0=inp(port);
writebuf(d,&c,1);
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++;
}
// catdisp(46,40,"Com svtrg=%02X ",&d->svtrg);
break;
case 1:
//not quite sure why this is, but after GPO2 reset
//I sometimes see d->svtrg=1, and this seems to require
//a data input to clear the device
//you see d->svtrg=1 means NO interrupt is pending
//so I can't understand how this handler can be entered
//on this condition
inp(port);
break;
}
return 0;
case DM_POLL:
if(inp(port+5)&2){inp(port);}
return 0;
default:
return comsvc(d,service);
}
}
SL mdmsvc (DEV* d,UL service)
{
//MDM serial modem handler
UL n,ck,ck1,ck2;
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,256,1);
return 0;
case DM_TERM:
// free(d->usr);
termbuf(d);
return 0;
case DM_CHILDHANDLER:
if(d->sv0==0x0a)
{
d->buf[d->bufin]=0;
clidisplay((CH*)d->buf);
if(d->notify){(*d->notify)(d);}
d->bufin=0;
}
writebuf(d,(UC*)&d->sv0,1);
return 0;
case DM_CLIDISPINFO:
return 0;
}
}
SL baud(UL argc,CH* argv[])
{
if(argc<2)
{
clidisplay("Usage:BAUD ");return 1;
}
DEV* d=finddevice(argv[1]);
if(!d)
{
clidisplay("Device %sc1500 not found",argv[1]);return 1;
}
UL br;
if(d->drv)
{
if(d->drv->svc)
{
if(argc<3)
{
br=getbaudrate(d);
clidisplay("Baud rate for <%sc1500> is %s",d->name,getbaudstr(br));
}
else
{
br=parsebaud(argv[2]);
if(br){return setbaudrate(d,br);}
}
}
}
return 1;
}
SL com1(UL argc,CH* argv[])
{
//#pragma breakpoint
DEV* d=finddevice("com2");
CH msg[512];
if(d)
{
strcpy(msg,argv[1]);
strcat(msg,"\r");
if(!serialoutstr(d->iores->start,msg))
{
brk return 1;
}
}
return 0;
}
//in st4110.htm
SL st4110svc (DEV* d,UL service);
SL st4110digsvc(DEV* d,UL service);
//in gps.htm
SL gpssvc (DEV* d,UL service);
//these comdrv0 and comdrv1 could easily be merged into one, but serve to
//show how DM_IDENT can be used to load the correct driver for similar
//devices with different chipsets
//ST4110 digitiser shows how to substitute specials for
//the standard drivers - DRV table is searched backwards
//so st41drv is tried before comdrv0
DRV comdrv1={0,0x7000000,0x7000000,comsvc1,"16550 UART"};
DRV comdrv0={0,0x7000000,0x7000000,comsvc0,"8250/16450 UART"};
DRV st41drv1={dpCOM,dtST4110,dcPEN,st4110digsvc,"ST4110 pen"};
DRV st41drv={0,0x7000000,0x7000000,st4110svc,"ST4110"};
DRV msmdrv ={dpCOM,dtMSM ,dcPEN,msmsvc, "MS mouse"};
DRV pendrv ={ 0,0x9010000,0x9010000,pensvc0, "Digitiser"};
DRV kyedrv ={dpCOM,dtKYE0100,dcPEN,kyesvc, "Genius EasyPen"};
DRV fsdigdrv={dpCOM,dtFSDIG,dcPEN,fsdigsvc, "Pen mouse"};
DRV wacdrv ={dpCOM,dtWAC0405,dcPEN,wacsvc, "Wacom Tablet"};
// DRV mdmdrv ={ 0,0x7800001,0x7800001,comsvc1, "Modem"};
DRV gpsdrv ={dpCOM,dtGPS ,dcGPS ,gpssvc , "GPS"};
DRV mdmdrv ={dpCOM,dtMDM ,dcMDM ,mdmsvc , "AT Modem"};
SL main(UL argc,CH* argv[])
{
SL n,m,o;
return 0;
}
SL term(VD)
{
return 0;
}