/*
* 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
* LICENSED MATERIALS - PROPERTY OF IBM
* REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
*/
/* $Header:ps.c 12.9$ */
/* $ACIS:ps.c 12.9$ */
/* $Source: /ibm/acis/usr/sys/caio/RCS/ps.c,v $ */

#if !defined(lint) && !defined(NO_RCS_HDRS)
static char *rcsid = "$Header:ps.c 12.9$";
#endif

/*
* ps --  driver for IBM 4216 personal page printer 
*/


#include "ps.h"

#if NPS > 0 
#include "../h/param.h"
#include "../h/errno.h"
#include "../h/uio.h"
#include "../h/ioctl.h"
#include "../h/file.h"
#include "../h/tty.h"
#include "../h/time.h"
#include "../machine/pte.h"
#include "../machine/io.h"
#include "../h/buf.h"
#include "../machineio/ioccvar.h"
#include "../machine/debug.h"
#include "../h/kernel.h"
#ifdef ATR
#include "../ca_atr/pcif.h"
#endif ATR
#include "../h/psioctl.h"


#define MAXPS 4
#define PSINTERVENTIME 500


int probe4216();
int attach4216();
int psintr();

static void psintervene(int);



#define PS_SPACE_USAGE 0x00000002
#define PS_PACKETS     0x00000004
#define PS_TIMEOUT     0x00000008

static int PSDEBUG = 0;
static int mem_used = 0;


caddr_t std4216[] = {			/* standard line printers */
#ifdef ATR
(caddr_t)0x37c,		/* The offset to the PCIF byte	*/
(caddr_t)0x378,		/* port window will be added to	*/
(caddr_t)0x27c,		/* port window will be added to	*/
(caddr_t)0x278,		/* to these values in probe4216().*/
#endif ATR
#ifdef IBMRTPC
(caddr_t)0xf0000278,
#endif IBMRTPC
0
};

struct iocc_device *psdinfo[NPS];

struct iocc_driver psdriver = {
probe4216, 0, attach4216,
0 /* dgo */ , std4216, "ps", psdinfo, 0, 0, psintr 
};


struct psdev {  char datal,
                datah, 
                cntl, 
                stat;
             };



#if defined(ATR)
volatile struct psdev *psaddr[] = { (struct psdev *)0xd00f0278,
                                       (struct psdev *)0xd00f027c,
                                       (struct psdev *)0xd00f0378,
                                       (struct psdev *)0xd00f037c };
#else
volatile struct psdev *psaddr[] = { (struct psdev *)0xf0000278 };
#endif

struct {  int isopen;
          int in_ipl;
          int sleeping;
          int needshelp;
          int writepacket; /* NORMALMODE or PSREADPACKET  */
          int readpacket;  /* NORMALMODE or PSWRITEPACKET */
          struct buf *rcvhead;
          struct buf *rcvtail;
          char writebuff[1030];
          char readbuff[1030];
       } psdevinfo[NPS];



/*
*
*  4216 packet types 
*
*/

#define PS_STDINPUT  0
#define PS_EOF       1
#define PS_RESET     0x120
#define PS_RESTART   0x121



/*
*    probe function of autoconfig
*/

/* Not guaranteed to be called by the auto config routine. */

probe4216(psaddr)
        register struct psdev *psaddr;

{ static int nps = 0;

    DEBUGF(PSDEBUG, printf("ps%d is at address %x\n", nps, psaddr));
    nps++;

    return (PROBE_NOINT); 
}




/*
 *    init procedure for 4216
 */

/* Config sometimes thinks that the ps adapter card is an lp card, so this   */ 
/* is not guaranteed to be called by the auto config routine   The lp driver */
/* will call this if lp is configured and NPS > 0                            */

attach4216(iod)
       register struct iocc_device *iod;
{ int unit;
   
    for(unit=0; unit < NPS; unit++) {
        psdevinfo[unit].isopen      = 0;
        psdevinfo[unit].readpacket  = 0;
        psdevinfo[unit].writepacket = 0;
        psdevinfo[unit].sleeping    = 0;
        psdevinfo[unit].needshelp   = 0;
        psdevinfo[unit].rcvhead     = NULL;
        psdevinfo[unit].rcvtail     = NULL;
    }
    return 1;
}




static unsigned short swapbytes(unsigned short);
void psbuildpacket(unsigned short, unsigned short, char *, unsigned short *);
int  psprintpacket(char *);
int  psgetpacket(int, char *);
int  pssendpacket(int, char *);



psopen(dev, flag)
       dev_t dev;
       int flag;

{ int unit = 0;

    unit = minor(dev);
    if (unit >= NPS) return ENODEV;
    else {

        /* cannot be opened for write by two or more processes */

        if (psdevinfo[unit].isopen && flag & FWRITE && !suser()) return EBUSY;
        else {
            DEBUGF(PSDEBUG, printf("open ps %d \n", unit));
            psdevinfo[unit].readpacket  = 0;
            psdevinfo[unit].writepacket = 0;
            psdevinfo[unit].needshelp   = 0;
            psdevinfo[unit].isopen = 1;

            return 0;
        }
    }
}




psclose(dev, flag)
        dev_t dev;
        int flag;

{ unsigned short pktbuff[4];
  int unit = minor(dev);

    DEBUGF(PSDEBUG, printf("close ps%d\n", unit));
    psbuildpacket(0, PS_EOF, (char *)pktbuff, pktbuff);
    pssendpacket(unit, (char *)pktbuff);
    psdevinfo[unit].in_ipl    = 0;
    psdevinfo[unit].isopen    = 0; 
    psdevinfo[unit].needshelp = 0;
    return(0);
}



psioctl(dev,cmd,addr,flag)
        dev_t dev;
        int cmd;
        caddr_t addr;
        int flag;

{ int unit;

    unit = minor(dev);
    DEBUGF(PSDEBUG, printf("ioctl %x on dev %x\n", cmd, unit));
    switch(cmd) {
    case PSREADPACKET:
                DEBUGF(PSDEBUG, printf("ps%d: readpackets\n", unit));
		psdevinfo[unit].readpacket = 1;
		break;
    case PSREADNORMAL:
                DEBUGF(PSDEBUG, printf("ps%d: readnormal\n", unit));
		psdevinfo[unit].readpacket = 0;
		break;

    case PSWRITEPACKET:
                DEBUGF(PSDEBUG, printf("ps%d: writepackets\n", unit));
		psdevinfo[unit].writepacket = 1;
		break;

    case PSWRITENORMAL:
                DEBUGF(PSDEBUG, printf("ps%d: writenormal\n", unit));
        	psdevinfo[unit].writepacket = 0;
        	break;

    case PSRESET:
                DEBUGF(PSDEBUG, printf("ps%d: reset adapter for ipl\n", unit));
                psdevinfo[unit].in_ipl = 1;
                psreset(unit);
                break;

    case PSENDIPL:
                DEBUGF(PSDEBUG, printf("ps%d: done with ipl\n", unit));
                psdevinfo[unit].in_ipl = 0;
                break;

    default:    DEBUGF(PSDEBUG, printf("ps%d: misunderstood ioctl %x\n", cmd, unit));
                return ENOTTY;
    }

    return 0;
}


psreset(unit)

{ volatile struct psdev *ps;


    /* set enhanced mode */

    ps = psaddr[unit];
    IOOUT(&(ps->datal), 0);
    IOOUT(&(ps->datah), 0);
    IOOUT(&(ps->cntl), 0xc0);
    DELAY(500000);   
    IOOUT(&(ps->cntl), 0x04);
    DELAY(500); 
    IOOUT(&(ps->cntl), 0x44);
}

 

psread(dev, uio)
       dev_t dev;
       register struct uio *uio;

{ int unit;
  char *pktbuff;
  struct buf *thisbuf;
  unsigned short packetlen;
  unsigned short packettype;


    unit = minor(dev);
    DEBUGF(PSDEBUG&PS_PACKETS, printf("psread ps%d\n", unit));
    pktbuff = psdevinfo[unit].readbuff;
    if (psdevinfo[unit].readpacket) {
        if (psdevinfo[unit].rcvhead) {
            DEBUGF(PSDEBUG&PS_PACKETS, printf("ps%d: psdevinfo[unit].rcvhead\n", unit));
            packetlen  = swapbytes(*(unsigned short *)psdevinfo[unit].rcvhead->b_un.b_addr);
            packettype = swapbytes(((unsigned short *)psdevinfo[unit].rcvhead->b_un.b_addr)[1]);
            DEBUGF(PSDEBUG&PS_PACKETS, printf("packettype = %x, len = %x\n",packettype, packetlen));
            if (packettype != 0x8104) {
                DEBUGF(PSDEBUG&PS_PACKETS, printf("ps%d: not a pacing packet\n", unit));
                uiomove(((char *)psdevinfo[unit].rcvhead->b_un.b_addr), packetlen+4, 
                      UIO_READ, uio);
                DEBUGF(PSDEBUG&PS_PACKETS, printf("copied buffer\n"));
                thisbuf = psdevinfo[unit].rcvhead;
                if (!psdevinfo[unit].rcvhead->av_forw) psdevinfo[unit].rcvtail = psdevinfo[unit].rcvhead = NULL;
                else psdevinfo[unit].rcvhead = psdevinfo[unit].rcvhead->av_forw; 
                DEBUGF(PSDEBUG&PS_PACKETS, printf("release buffer addr = %x\n", thisbuf));
                DEBUGF(PSDEBUG & PS_SPACE_USAGE,
                     printf("in read. (readpacket). release %d\n", thisbuf->b_bufsize));
                mem_used -= (int)thisbuf->b_bufsize;
                brelse(thisbuf);  
                DEBUGF(PSDEBUG&PS_PACKETS, printf("release completed \n"));
            }
            else {
                DEBUGF(PSDEBUG&PS_PACKETS, printf("pacing packet \n"));
                thisbuf = psdevinfo[unit].rcvhead;
                if (!psdevinfo[unit].rcvhead->av_forw) psdevinfo[unit].rcvtail = psdevinfo[unit].rcvhead = NULL;
                else psdevinfo[unit].rcvhead = psdevinfo[unit].rcvhead->av_forw; 
                DEBUGF(PSDEBUG&PS_PACKETS, printf("release pacing packet and try again \n"));
                DEBUGF(PSDEBUG & PS_SPACE_USAGE,
                       printf("in read. (readpacket). release %d\n",
                              thisbuf->b_bufsize));
                mem_used -= (int)thisbuf->b_bufsize;
                brelse(thisbuf);  
                return psread(dev, uio);
            }
        }
        else {
            if (psgetpacket(unit, pktbuff) >= 0) {
                packetlen  = swapbytes(*(unsigned short *)pktbuff);
                packettype = swapbytes(((unsigned short *)pktbuff)[1]);
                if ((packettype) && (packettype != 0x8104)) {
                    uiomove(pktbuff, packetlen+4, UIO_READ, uio);
                }
            }
            else return EIO;
        }
    }
    else { /* read normal mode */
        if (psdevinfo[unit].rcvhead) {
            do {
                packetlen  = swapbytes(*(unsigned short *)psdevinfo[unit].rcvhead->b_un.b_addr);
                packettype = swapbytes(((unsigned short *)psdevinfo[unit].rcvhead->b_un.b_addr)[1]);
                uiomove(((char *)psdevinfo[unit].rcvhead->b_un.b_addr)+4, packetlen, UIO_READ, uio);
                thisbuf = psdevinfo[unit].rcvhead;
                if (!psdevinfo[unit].rcvhead->av_forw) psdevinfo[unit].rcvtail = psdevinfo[unit].rcvhead = NULL;
                else psdevinfo[unit].rcvhead = psdevinfo[unit].rcvhead->av_forw;
                DEBUGF(PSDEBUG & PS_SPACE_USAGE,
                       printf("in read. (readpacket). release %d\n",
                              thisbuf->b_bufsize));
                mem_used -= (int)thisbuf->b_bufsize;
                brelse(thisbuf);
             } while ((packetlen == 0) && psdevinfo[unit].rcvhead);
             if (!psdevinfo[unit].rcvhead) {
                 if (psgetpacket(unit, pktbuff) < 0) {
                     return EIO;
                 }
             packetlen = swapbytes(*(unsigned short *)pktbuff);
             uiomove(pktbuff+4, packetlen, UIO_READ, uio);
             }
        }
        else {
            if (psgetpacket(unit, pktbuff) < 0) {
                return EIO;
            }
            packetlen = swapbytes(*(unsigned short *)pktbuff);
            uiomove(pktbuff+4, packetlen, UIO_READ, uio);
        }
    }
    DEBUGF(PSDEBUG&PS_PACKETS, printf("normal return \n"));
    return(0);
}





pswrite(dev, uio)
        dev_t dev;
        register struct uio *uio;

{ char *pktbuff;
  unsigned short packetlen = 0;
  unsigned short packettype = 0;
  struct buf *rcvbuf = NULL;
  int unit;


    unit = minor(dev);
    
    pktbuff = psdevinfo[unit].writebuff;
    DEBUGF(PSDEBUG&PS_PACKETS, printf("pswrite %d \n", unit));
    if (psdevinfo[unit].writepacket) {
        if (uio->uio_resid > 1028) {
            return(EFBIG);
        }
        else {
            DEBUGF(PSDEBUG&PS_PACKETS,
                   printf("ps%d: packet type = %x, len = %x\n",
                           unit, packettype, packetlen));
            if (psgetpacket(minor(dev), pktbuff) < 0) {
                return EIO;
            }
            packetlen  = swapbytes(*((unsigned short *)pktbuff));
            packettype = swapbytes(((unsigned short *)pktbuff)[1]);
            if (( packettype ) && (packettype != 0x8104)) {

                /*
                 *   if there is something in the buffer, 
                 *   buffer up the resulting packet to be returned by a
                 *   future read
                 *
                 */

                DEBUGF(PSDEBUG&PS_PACKETS,
                       printf("in write, buffered packettype = %x, len = %x\n",
                              packettype, packetlen));
                DEBUGF(PSDEBUG & PS_SPACE_USAGE, 
                       printf("in write. (writepacket). geteblk %d\n",
                              packetlen+6));
                mem_used += (int)packetlen+6;
                rcvbuf = (struct buf *)geteblk((int)packetlen+6);
                DEBUGF(PSDEBUG&PS_PACKETS,
                       printf("survived geteblk. rtn %8x\n", rcvbuf)); 
                bcopy(pktbuff, rcvbuf->b_un.b_addr, packetlen+4);
                DEBUGF(PSDEBUG&PS_PACKETS, printf("survived bcopy\n")); 
   
                rcvbuf->av_forw   = NULL;
                if (psdevinfo[unit].rcvhead) {
                    DEBUGF(PSDEBUG&PS_PACKETS,
                           printf("add to existing packet queue\n"));
                    if (psdevinfo[unit].rcvtail) {
                        psdevinfo[unit].rcvtail->av_forw = rcvbuf;
                    }
                    psdevinfo[unit].rcvtail = rcvbuf;
                }
                else {
                    psdevinfo[unit].rcvhead = psdevinfo[unit].rcvtail = rcvbuf;
                }
            }

            /* since we're writing packets, we can assume they were
             * already built . Just send it.
             */

            uiomove(pktbuff, uio->uio_resid, UIO_WRITE, uio);
            DEBUGF(PSDEBUG&PS_PACKETS,
                   printf("in write, sending %d bytes, %s\n",
                           uio->uio_resid, (*(short *)pktbuff + 4 )));
            if (pssendpacket(unit,  pktbuff) < 0) {
                return EIO; 
            }
        }
    }
    else { /* write normal mode */
	if (uio->uio_resid > 1024) {
            return(EFBIG);
	}
	else {
            DEBUGF(PSDEBUG&PS_PACKETS,
                   printf("non-packet write, zero buffer\n"));
            DEBUGF(PSDEBUG&PS_PACKETS, printf("get a packet\n"));
            if (psgetpacket(unit, pktbuff) < 0) {
                return EIO;
            }
            packetlen = swapbytes(*((unsigned short *)pktbuff));
            packettype = swapbytes(((unsigned short *)pktbuff)[1]);
            if (packettype) {

                /*
                 *   if there is something in the buffer, 
                 *   buffer up the resulting packet to be returned by a
                 *   future read.
                 */

                DEBUGF(PSDEBUG&PS_PACKETS, printf("geteblk rtn = %x\n"));
                DEBUGF(PSDEBUG & PS_SPACE_USAGE,
                       printf("in write. (writepacket). geteblk %d\n",
                              packetlen+60));
                mem_used += (int)packetlen+6;
                rcvbuf = (struct buf *)geteblk((int)packetlen+6);
                DEBUGF(PSDEBUG&PS_PACKETS, printf("rtn frm geteblk\n"));
                bcopy(pktbuff, rcvbuf->b_un.b_addr, packetlen+4);
                DEBUGF(PSDEBUG&PS_PACKETS, printf("rtn frm bcopy\n"));
                rcvbuf->av_forw   = NULL;
                if (psdevinfo[unit].rcvhead) {
                    if (psdevinfo[unit].rcvtail) {
                        psdevinfo[unit].rcvtail->av_forw = rcvbuf;
                    }
                    psdevinfo[unit].rcvtail = rcvbuf;
                }
                else {
                    psdevinfo[unit].rcvhead = psdevinfo[unit].rcvtail = rcvbuf;
                }
                DEBUGF(PSDEBUG&PS_PACKETS, printf("all done\n"));
            }


            /* build the packet and then send it */

            packetlen = *((short *)pktbuff)   = (unsigned short)uio->uio_resid;
            ((short *)pktbuff)[1] = PS_STDINPUT;
            uiomove(pktbuff+4, uio->uio_resid, UIO_WRITE, uio);
            DEBUGF(PSDEBUG&PS_PACKETS,
                   printf("pswrite: len = %d, packet = %s\n",
                          packetlen, pktbuff+4));
            if (pssendpacket(minor(dev),  pktbuff) < 0) {
                return EIO; 
            }
        } 
    }

    DEBUGF(PSDEBUG&PS_PACKETS, printf("return from pswrite\n"));
    return(0);
}




psselect(dev, rw)
    dev_t dev;
    int rw;

{
    return 1;
}





void psbuildpacket(len, type, data, pktbuff)
       unsigned short len, type, *pktbuff;
       char *data;

{ 

    pktbuff[0] = len;
    pktbuff[1] = type; 
    bcopy(data, pktbuff+2, len);
}





psprintpacket(pktptr)
char *pktptr;

{ int len, type;

    type = swapbytes(*((short *)(pktptr+2))) & 0x0000ffff;
    len  = swapbytes(*((short *)pktptr)) & 0x0000ffff;
    printf("len = %d type  =%x\n", len, type);
    printf("next 2 bytes: %x\n", *((short *)(pktptr+4)));
    printf("FROM PS: %s\n", pktptr+4);
}



int psgptimeout(int);


/*
 *
 *   getpacket -- get a packet form the 4216 smart card. 
 *                parms:
 *                      unit   which of up to NPS smart cards one wishes to      *                             address. (NPS is always 1 one the RT, may be up   *                             4 on the ATR.
 *
 *                      pktptr pointer to the buffer where the packet data will
 *                             returned.
 *
 *
 *                returns:
 *                      packet data in pktptr
 *                      length of packet data if there is a packet,
 * 			-1 if there is an error,
 *                      0 otherwise.
 */

psgetpacket(unit, pktptr)
        int unit;
        char *pktptr;

{ unsigned short i, j, len, type, *dp;
  int t, numtries, pri;
  char *pp, c1, c2;              
  volatile struct psdev *ps;


    ps = psaddr[unit];
    pp = pktptr;
    dp = (unsigned short *)pp; 
    bzero((char *)dp, 4);

    if (!(IOIN(&(ps->stat))&0x10) && !psdevinfo[unit].in_ipl) {
        printf("ps%d device not initialized\n", unit);
        return -1;
    }

    
    if (!(IOIN(&(ps->stat))&0x08)) {
        printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
        return -1;  
    }

    numtries = 0;
    while (!(IOIN(&(ps->stat))&0x80)) {
        if (numtries++ > 1000) {
           return -1;
        }
        if (!(IOIN(&(ps->stat))&0x08)) {
            printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
            return -1;
        }
        else if (IOIN(&(ps->stat))&0x20) { 
            printf("ps%d: intervention required\n", unit);
            psintervene(unit);
        }
        DELAY(1000);
    }


    IOOUT(&(ps->cntl), 0x44);  /* 0x44 == non-enhanced, read mode, not init */
    numtries = 0;
    DELAY(50);
    while (!(IOIN(&(ps->stat))&0x01)) {
        if (numtries++ > 1) {
           IOOUT(&(ps->cntl), 0x04);
           return 0;
        }
        if (!(IOIN(&(ps->stat))&0x08)) {
            printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
            return -1;
        }
        else if (IOIN(&(ps->stat))&0x20) { 
            printf("ps%d: intervention required\n", unit);
            psintervene(unit);
        }
        DELAY(1000);
    }

    DELAY(50);
    *pp++ = IOIN(&(ps->datal));
    DELAY(50);
    *pp++ = IOIN(&(ps->datah));

    numtries = 0;
    while (!(IOIN(&(ps->stat))&0x01)) {
        if (numtries++ > 100) {
           bzero((char *)dp, 4);
           IOOUT(&(ps->cntl), 0x04);
           return 0;
        }
        if (!(IOIN(&(ps->stat))&0x08)) {
            printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
            return -1;
        }
        else if (IOIN(&(ps->stat))&0x20) { 
            printf("ps%d: intervention required\n", unit);
            psintervene(unit);
        }
        DELAY(1000);
    }

    len = swapbytes(*dp); 
    if (len > 1024) { /* Guaranteed bad length */
        printf("ps%d: bad packet length in read : %x\n", unit, len);
        bzero((char *)dp, 4);
        IOOUT(&(ps->cntl), 0x04);
        return -1; 
    }
    else {
        DELAY(50);
        *pp++ = IOIN(&(ps->datal));
        DELAY(50);
        *pp++ = IOIN(&(ps->datah));
        type = swapbytes(dp[1]);
        t = 0x0000ffff & type;

        DEBUGF(PSDEBUG & PS_PACKETS, 
               printf("ps%d: type = %x, len =%x\n", unit, type, len));
        switch(t) {
        default:
        case 0x8000: /* standard output from the interpreter */
                for (i = 0; i < len; i+=2) {
	            numtries = 0;
              	    while (!(IOIN(&(ps->stat))& 0x01)) {
        	        numtries++;
		        if (numtries > 100) {
                            printf("ps%d: timeout in read i = %d\n", unit, i);
                            IOOUT(&(ps->cntl), 0x04);
			    return 0;
		        }
		        DELAY(1000);
	            }
                    DELAY(10);
                    c2 = IOIN(&(ps->datal));
                    DELAY(10);
                    c1 = IOIN(&(ps->datah));
                    *pp++ = c1;
                    *pp++ = c2;
                }
                *pp++ = '\0';
                break;
        case 0x8001: /* EOF acknolegment */
                break;

        case 0x8102: /* Status reponse */
                break;

        case 0x8103: /* stop request from interpreter */
                DEBUGF(PSDEBUG && psdevinfo[unit].sleeping, 
                       panic("ps: duplicate pacing packet"));
                psdevinfo[unit].sleeping = 1;
                IOOUT(&(ps->cntl), 0x04);
                while (psdevinfo[unit].sleeping) {
                    DEBUGF(PSDEBUG & PS_TIMEOUT, 
                           printf("ps%d: setup timeout\n", unit)); 
                    pri = spl5();        /* to prevent interrupt from       */
                                         /*  occuring while setting timeout */
                    timeout(psgptimeout, (caddr_t)unit, 10);
                    DEBUGF(PSDEBUG & PS_TIMEOUT,
                           printf("sleep time unit = %d\n", unit));
                    sleep(&(psdevinfo[unit].sleeping), PZERO+3);
                    splx(pri);
                    if (psgetpacket(unit, pktptr) < 0) {
                        return -1; 
                    }
                }
                
                return psgetpacket(unit, pktptr);
                break;

        case 0x8104: /* resume request from interpreter */
                psdevinfo[unit].sleeping = 0;
                break;

        case 0x810f:
                break;

        case 0x8123:
                break;
        }
    }
    IOOUT(&(ps->cntl), 0x04);
    return len;
}



psgptimeout(unit)
    int unit;

{ 

   DEBUGF(PSDEBUG & PS_TIMEOUT,
          printf("wakeup from timeout. unit = %d\n", unit));
   wakeup(&(psdevinfo[unit].sleeping));
}




/*
 *  sendpacket -- send a packet to the 4216 smart card.
 *             
 *                parms:
 *                   unit  which of up to NPS smart cards (1 on the RT, up
 *                         to 4 on the ATR).
 *
 *                   packptr buffer containing the packet data
 *
 *
 *
 */

pssendpacket(unit, packptr)
       int unit;
       char *packptr;

{ char *pb;
  unsigned short len, type;
  int sent = 0;
  int numtries = 0;
  volatile struct psdev *ps;
  int control;

    
    ps = psaddr[unit];
    len  = *((short *)packptr)+4;
    type = ((short *)packptr)[1];
    if (!(IOIN(&(ps->stat))&0x10) && !(psdevinfo[unit].in_ipl)) {
        printf("ps%d device not initialized\n", unit);
        return -1;
    }

    control = (type > 0x01 && type != 0x0123 && type != 0x0124);
    pb = packptr;
        
    /* first word : length */

    while (!(IOIN(&(ps->stat)) & 0x80)) {
        numtries++;
        if (!(IOIN(&(ps->stat)) & 0x08)) {
            printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
            return -1;
 
        }
        else if (IOIN(&(ps->stat)) & 0x20) { 
            printf("ps%d: intervention required\n", unit);
            psintervene(unit);
        }
        if (numtries > 1000) { 
            printf("ps%d: tired of waiting 1\n", unit); 
            return -1; 
        }
        DELAY(1000);
    }
    IOOUT(&(ps->datal), pb[1]); sent +=2;
    DELAY(10);
    IOOUT(&(ps->datah), pb[0]);
    DELAY(30);
    pb += 2;


    /* set enhanced interface */


    IOOUT(&(ps->cntl), control ? 0x86 : 0x84);

    /*  Next word, datatype */


    numtries = 0;
    while (!(IOIN(&(ps->stat))&0x80)) {
        if (numtries++ > 1000) { 
            printf("tired of waiting 2\n"); 
            return -1; 
        }
        if (!(IOIN(&(ps->stat))&0x08)) {
            printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
            return -1;
        }
        else if (IOIN(&(ps->stat))&0x20) { 
            printf("ps%d: intervention required\n", unit);
            psintervene(unit);
        }

        if (numtries > 1) {  
            DELAY(1000);
        }
        else DELAY(100);
    }
    IOOUT(&(ps->datal), pb[1]); sent +=2;
    DELAY(10);
    IOOUT(&(ps->datah), pb[0]);
    DELAY(30); pb += 2;


    /* packet data */

    while(pb < packptr+len) {
        numtries = 0;
        while (!(IOIN(&(ps->stat))&0x80)) {
            if (numtries++ > 1000) return -1;
                if (!(IOIN(&(ps->stat))&0x08)) {
                printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
                return -1;
            }
            else if (IOIN(&(ps->stat))&0x20) { 
                printf("ps%d: intervention required\n", unit);
                psintervene(unit);
            }

            if (numtries > 1) { DELAY(1000); }
            else DELAY(100);
        }
        IOOUT(&(ps->datal), pb[1]), sent +=2;
        DELAY(25);
        IOOUT(&(ps->datah), pb[0]);
        DELAY(25);  pb +=2;
    }

    /* set the enhanced bit off. tells the card that i'm done */

    numtries = 0;
    while (!(IOIN(&(ps->stat))&0x80))  {
        if (numtries++ > 100) return -1; 
        if (!(IOIN(&(ps->stat))&0x08)) {
            printf("ps%d: unrecoverable error. reinitialize printer\n", unit);
            return -1;
        }
        else if (IOIN(&(ps->stat))&0x20) { 
            printf("ps%d: intervention required\n", unit);
            psintervene(unit);
        }
        DELAY(1000);
    }  
    IOOUT(&(ps->cntl), 0x04); 
    return 0;
}




static unsigned short swapbytes(i)
unsigned short i;

{ char t;
  char *ip;

    ip = (char *)(&i);
    t = *ip;
    *ip = ip[1];
    ip[1] = t;
    return i;
}





psintervtimeout(unit)
    int unit;

{ 

   printf(" ps%d: intervention required\n", unit);
   wakeup(&(psdevinfo[unit].needshelp));
}


static void
psintervene(unit)
     int unit;

{ int pri;
  volatile struct psdev *ps;

     ps = psaddr[unit];
     while (IOIN(&(ps->stat))&0x20) { 
         printf("ps%d: intervention required\n", unit);
         DEBUGF(PSDEBUG & PS_TIMEOUT, 
                printf("ps%d: setup timeout\n", unit)); 
         pri = spl5();        /* to prevent interrupt from       */
                              /*  occuring while setting timeout */
         timeout(psintervtimeout, (caddr_t)unit, PSINTERVENTIME);
         DEBUGF(PSDEBUG & PS_TIMEOUT,
                printf("sleep time unit = %d\n", unit));
         sleep(&(psdevinfo[unit].needshelp), PZERO+3);
         splx(pri);
     }
     psdevinfo[unit].needshelp;
}



psintr()

{   
     return(0);
}
#endif
