/* OS- and machine-dependent stuff for HP 110+ running MS-DOS */ #if defined(__TURBOC__) #pragma inline #include #include "config.h" #if defined(PLUS) #include "global.h" #include "8250.h" #include "asy.h" #include "plus.h" #include "iface.h" struct asy asy[ASY_MAX]; unsigned nasy; byte model; void _Cdecl __int__ (int interruptnum); void interrupt (* _Cdecl getvect(int interruptno)) (); #define geninterrupt(i) __int__(i) extern unsigned char intstk[]; extern unsigned int sssave, spsave; /* ================================================================= */ int16 modemdev, serialdev; struct plusasy plusasy[ASY_MAX]; /* ASY interrupt handlers */ byte modemconfig, serialconfig; extern void interrupt plustxsvec(); extern void interrupt plusrxsvec(); extern void interrupt plustxmvec(); extern void interrupt plusrxmvec(); byte *com1_name="COM1"; /* file to open for serial */ byte *com3_name="COM3"; /* file to open for modem */ int com1handle; /* file handle saved here */ int com3handle; /* file handle saved here */ byte *ioctlon1="M1;"; /* IOCTL to turn on serial port */ byte *ioctloff1="M3;"; /* IOCTL to turn off serial port */ byte *ioctlon3="M4;"; /* IOCTL to turn on modem port */ byte *ioctloff3="M5;"; /* IOCTL to turn off modem port */ /* Initialize asynch port "dev" */ int asy_init(dev,arg1,arg2,bufsize) int16 dev; char *arg1,*arg2; unsigned bufsize; { register unsigned base; register struct fifo *fp; register struct asy *ap; ap = &asy[dev]; ap->addr = htoi(arg1); ap->vec = htoi(arg2); /* Set up receiver FIFO */ fp = &ap->fifo; if((fp->buf = malloc(bufsize)) == NULLCHAR){ printf("asy%d: No space for rx buffer\r\n"); fflush(stdout); return; } fp->bufsize = bufsize; fp->wp = fp->rp = fp->buf; fp->cnt = 0; base = ap->addr; /* Purge the receive data buffer * Set line control register: 8 bits, no parity * * Turn on receive interrupt enable, leave transmit * interrupts turned off for now * * Set modem control register: assert DTR, RTS, turn on serial * port * * Enable rx interrupt */ (void)init_com(dev,'N',1); /* * set calibration in delay */ /* * turn off lousy beeper on ring interrupts. */ _AL=2; __int__(0x59); /* Set interrupt vector to SIO handler * DON'T bump them by 8 as we use the actual * interrupt numbers, not the number -8 as in * the pc asy entry. * * If the computer is a portable only the serial interrupts are used * If the computer is a P+ both serial and modem interrupts are used * * 110 110p serial 110p modem * rx vector 0x4f 0x4f 0x4e * tx vector 0x4a 0x4a 0x40 * base addr 0xa4 0x44 0xa4 * */ if(base==0x44 || model==1) { plusasy[dev].oldrx=getvect(0x4f); plusasy[dev].oldtx=getvect(0x4a); if(model==1) { asy[dev].addr=0xa4; setvect(0x4a,plustxmvec); setvect(0x4f,plusrxmvec); modemdev=dev; } else { setvect(0x4a,plustxsvec); setvect(0x4f,plusrxsvec); serialdev=dev; } } else { /* address not 0x44 and not a portable, must be plus modem */ plusasy[dev].oldrx=getvect(0x4e); plusasy[dev].oldtx=getvect(0x40); setvect(0x40,plustxmvec); setvect(0x4e,plusrxmvec); modemdev=dev; } } /* asy_init */ int asy_stop(iface) struct interface *iface; { register unsigned base; register struct asy *ap; ap = &asy[iface->dev]; base = ap->addr; /* * hardware ints off */ outportb(base+INTRCONTROL,(unsigned char)0xf0); /* * turn off power to the serial port and * Restore original interrupt vectors */ if(base==0x44 || model==1) { serial_power(0); setvect(0x4f,plusasy[iface->dev].oldrx); setvect(0x4a,plusasy[iface->dev].oldtx); } else { modem_power(0); setvect(0x4e,plusasy[iface->dev].oldrx); setvect(0x40,plusasy[iface->dev].oldtx); } return(0); } /* Asynchronous line I/O control */ asy_ioctl(interface,argc,argv) struct interface *interface; int argc; char *argv[]; { if(argc < 1){ printf("%d\r\n",asy[interface->dev].speed); return 0; } return asy_speed(interface->dev,atoi(argv[0])); } /* Set asynch line speed */ int asy_speed(dev,speed) int16 dev; int speed; { register unsigned base; register int divisor; char i_state; if(speed == 0 || dev >= nasy) return; base = asy[dev].addr; asy[dev].speed = speed; /* * Setup baud rate */ divisor=1333500L/speed - 1; i_state = disable(); outportb((unsigned)(base+BAUDLO), (unsigned char)(divisor)); outportb((unsigned)(base+BAUDHI), (unsigned char)(divisor>>8)); restore(i_state); } /* Send a buffer to serial transmitter */ asy_output(dev,buf,cnt) unsigned dev; char *buf; unsigned short cnt; { register struct dma *dp; unsigned base; char i_state; if(cnt == 0) return; if(dev >= nasy) return; base = asy[dev].addr; dp = &asy[dev].dma; i_state = disable(); if(dp->flags){ restore(i_state); return; /* Already busy */ } dp->data = buf; dp->cnt = cnt; dp->flags = 1; /* Enable transmitter buffer empty interrupt and simulate * an interrupt; this will get things rolling. */ clrbit(base+INTRCONTROL,0x80); setbit(base+INTRCONTROL,0x40); asytxint(dev); restore(i_state); } /* Receive characters from asynch line * Returns count of characters read */ int16 asy_recv(dev,buf,cnt) int16 dev; char *buf; unsigned cnt; { unsigned tot,n; int kbread(); char i_state; struct fifo *fp; fp = &asy[dev].fifo; tot = 0; /* Read from serial I/O input buffer */ i_state = disable(); for(;;){ n = min(cnt,fp->cnt); if(n == 0) break; n = min(n,&fp->buf[fp->bufsize] - fp->rp); memcpy(buf,fp->rp,n); fp->rp += n; if(fp->rp >= &fp->buf[fp->bufsize]) fp->rp = fp->buf; fp->cnt -= n; buf += n; tot += n; cnt -= n; } restore(i_state); return tot; } /* Process 110P receiver interrupts */ static asyrxint(dev) unsigned dev; { unsigned base; register struct fifo *fp; char c; base = asy[dev].addr; fp = &asy[dev].fifo; c = inportb(base+RXDATA); /* Process incoming data; * If buffer is full, we have no choice but * to drop the character */ if(fp->cnt != fp->bufsize){ *fp->wp++ = c; if(fp->wp == &fp->buf[fp->bufsize]) /* Wrap around */ fp->wp = fp->buf; fp->cnt++; } } /* Handle 110P transmitter interrupts */ static asytxint(dev) unsigned dev; { register struct dma *dp; register unsigned base; base = asy[dev].addr; dp = &asy[dev].dma; if(!dp->flags){ /* "Shouldn't happen", but disable transmit * interrupts anyway */ setbit(base+INTRCONTROL,0xc0); return; /* Nothing to send */ } while(inportb(base+STATUS) & 0x02){ outportb(base+TXDATA,*dp->data++); if(--dp->cnt == 0){ dp->flags = 0; /* Disable transmit interrupts */ setbit(base+INTRCONTROL,0xc0); break; } /* * turn em back on, we got more to do */ clrbit(base+INTRCONTROL,0x80); setbit(base+INTRCONTROL,0x40); } } int stxrdy(dev) int16 dev; { return(!asy[dev].dma.flags); } /* Set bit(s) in I/O port */ setbit(port,bits) unsigned port; char bits; { outportb(port,(char)inportb(port)|bits); } /* Clear bit(s) in I/O port */ clrbit(port,bits) unsigned port; char bits; { outportb(port,(char)(inportb(port) & ~bits)); } int init_com(dev,wordlen,parity) int dev, wordlen; char parity; { int i, offset, sconfig; i=peek(0xffff,0x0e) & 0xff; if(i==0xb6) { model=1; /* portable */ asy[dev].addr=0xa4; offset=i=0x60; } else if((i=='A') || (i=='B')) { model=0; /* portable plus */ offset=i=0; } else if(i>0xfb) model=2; /* pc type */ if(model==2) { return(offset=-1); } /* * turn on port */ outportb((unsigned)(asy[dev].addr+INTRCONTROL), (unsigned char)0xf0); /* make sure no ints from serial */ if(offset || asy[dev].addr==0x44) { serial_power(1); } else { modem_power(1); } i=wordlen-5; if ((i<0) || (i>3)) i=3; i=i<<6; sconfig=i | 2; /* setup our local copy */ switch(parity) { case 'n': case 'N': i=0; break; case 'e': case 'E': i=2; break; case 'o': case 'O': i=3; break; default: i=0; } i=i<<2; sconfig|=i; if(offset || asy[dev].addr==0xa4) modemconfig=sconfig; else serialconfig=sconfig; /* * set up serial configuration register */ outportb((unsigned)(asy[dev].addr+FORMATCONTROL), (unsigned char)sconfig); /* * interrupt on data avail */ outportb((unsigned)(asy[dev].addr+INTRCONTROL+offset), (unsigned char)0xd0); return 4; } /* init_com */ #if 0 /* * This code is if def'ed out. I left it in in case someone wanted to * see how to read these lines. WA7TAS */ /* * state of cts and dsr lines are inverted on the portable plus * and not inverted on the portable. CTS is bit 6 on the portable, * and bit 7 on the portable plus. DSR is bit 7 on the portable, * and bit 6 on the portable plus. */ int cts() { if(model==1) return((int)(inportb(0x2f) & 0x40)); return(!((int)(inportb(0x2f) & 0x80))); } /* cts */ int dsr() { if(model==1) return((int)(inportb(0x2f) & 0x80)); return(!((int)(inportb(0x2f) & 0x40))); } /* dsr */ #endif void interrupt plustxsvec() { asm mov ds:sssave,ss; asm mov ds:spsave,sp; _BX=intstk; _SS=_DS; asm mov sp,bx asytxint(serialdev); asm mov sp,ds:spsave; asm mov ss,ds:sssave; } /* plustxsvec */ /* * see turbo c user's guide page p283 */ void interrupt plusrxsvec() { register int tchar, dd; asm mov ds:sssave,ss; asm mov ds:spsave,sp; _BX=intstk; _SS=_DS; asm mov sp,bx if((inportb(SERIAL_STATUS) & 0x80) != 0) asyrxint(serialdev); outportb(SERIAL_FMTCNTL,serialconfig | 2); tchar=inportb(SERIAL_INTRCNTL); tchar|=0x10; tchar&=(~0x20); asm mov sp,ds:spsave; asm mov ss,ds:sssave; outportb(SERIAL_INTRCNTL,tchar); } /* plusrxsvec */ void interrupt plustxmvec() { asm mov ds:sssave,ss; asm mov ds:spsave,sp; _BX=intstk; _SS=_DS; asm mov sp,bx asytxint(modemdev); asm mov sp,ds:spsave; asm mov ss,ds:sssave; } /* plustxmvec */ /* * see turbo c user's guide page p283 */ void interrupt plusrxmvec() { register int tchar, dd; asm mov ds:sssave,ss; asm mov ds:spsave,sp; _BX=intstk; _SS=_DS; asm mov sp,bx if((inportb(MODEM_STATUS) & 0x80) != 0) asyrxint(modemdev); outportb(MODEM_FMTCNTL,modemconfig | 2); tchar=inportb(MODEM_INTRCNTL); tchar|=0x10; tchar&=(~0x20); asm mov sp,ds:spsave; asm mov ss,ds:sssave; outportb(MODEM_INTRCNTL,tchar); } /* plusrmsvec */ void modem_power(on_off) int on_off; { /* * open com3 file see 110+ tech ref page 6-18 */ _AX=0x3d02; _DX=com3_name; geninterrupt(0x21); com3handle=_AX; /* * get com3 device status info */ _BX=_AX; _AX=0x4400; geninterrupt(0x21); /* * set raw bit */ _BX=com3handle; _DH=0; _DL|=0x20; _AX=0x4401; geninterrupt(0x21); /* * turn on rs232 port or off */ if(on_off!=0) { /* turn it on */ _BX=com3handle; _DX=ioctlon3; _CX=3; _AX=0x4403; } else { _DX=ioctloff3; _CX=3; _AX=0x4403; geninterrupt(0x21); /* * close the file handle as we're done with it. */ _BX=com3handle; _AX=0x3e00; } geninterrupt(0x21); } /* modem_power */ void serial_power(on_off) int on_off; { /* * open com1 file see 110+ tech ref page 6-18 */ _AX=0x3d02; _DX=com1_name; geninterrupt(0x21); com1handle=_AX; /* * get com1 device status info */ _BX=_AX; _AX=0x4400; geninterrupt(0x21); /* * set raw bit */ _BX=com1handle; _DH=0; _DL|=0x20; _AX=0x4401; geninterrupt(0x21); /* * turn on rs232 port or off */ if(on_off!=0) { /* turn it on */ _BX=com1handle; _DX=ioctlon1; _CX=3; _AX=0x4403; } else { _DX=ioctloff1; _CX=3; _AX=0x4403; geninterrupt(0x21); /* * close the file handle as we're done with it. */ _BX=com1handle; _AX=0x3e00; } geninterrupt(0x21); } /* serial_power */ #endif /* if defined(PLUS) */ #endif /* if defined(__TURBOC__) */