SysIII/usr/src/uts/vax/io/kmc.c
/*
* KMC11 microprocessor driver
*/
#include "sys/param.h"
#include "sys/tty.h"
#include "sys/ioctl.h"
#include "sys/buf.h"
#include "sys/dir.h"
#include "sys/user.h"
struct device *kmc_addr[];
int kmc_cnt;
#define MAXKMC 4
struct kmc {
struct clist k_inq;
char k_stat;
char k_type;
int (*k_rint)();
} kmc [MAXKMC];
#define KMC11A 1
#define KMC11B 2
#define KASIZE 1024
#define KBSIZE 4096
#define KSTEP 1
#define KMS 2
#define KCSR 3
#define KSTOP 4
#define KMCLR 5
#define KRUN 6
#define KLU 7
#define RUN (1<<7)
#define MCLR (1<<6)
#define CWRT (1<<5)
#define LUB (1<<4)
#define LUA (1<<3)
#define ROMO (1<<2)
#define ROMI (1<<1)
#define STEP (1<<0)
#define RDYO 0200
#define RDYI 020
#define RQI 0200
#define IEI 01
#define IEO 020
#define STYPE 017
#define SRUN 020
#define SRINT 040
#define SOPEN 0100
struct device {
union {
char b[8];
ushort w[4];
} un;
};
#define bsel0 un.b[0]
#define bsel1 un.b[1]
#define bsel2 un.b[2]
#define bsel3 un.b[3]
#define bsel4 un.b[4]
#define bsel5 un.b[5]
#define bsel6 un.b[6]
#define bsel7 un.b[7]
#define sel0 un.w[0]
#define sel2 un.w[1]
#define sel4 un.w[2]
#define sel6 un.w[3]
kmcopen(dev, flag)
{
register struct device *kp;
register struct kmc *tp;
register sav;
if (dev>=kmc_cnt || (tp = &kmc[dev])->k_stat&SOPEN) {
u.u_error = ENXIO;
return;
}
tp->k_stat |= SOPEN;
if (tp->k_type==0) {
kp = kmc_addr[dev];
kp->bsel1 = ROMO;
kp->sel4 = 0;
sav = kp->sel6;
kp->sel6 = ~sav;
if (kp->sel6 != sav) {
tp->k_type = KMC11B;
kp->sel6 = sav;
} else
tp->k_type = KMC11A;
kp->bsel1 = 0;
}
}
kmcclose(dev)
{
kmc[dev].k_stat &= ~SOPEN;
}
kmcread(dev)
{
register struct device *kp;
register ad;
int dsize;
ushort sav;
if (kmc[dev].k_stat&SRUN)
return;
dsize = (kmc[dev].k_type==KMC11A)?KASIZE:KBSIZE;
kp = kmc_addr[dev];
kp->bsel1 = 0;
do {
ad = u.u_offset;
if (ad<dsize*2) {
if (ad&1) {
u.u_error = ENXIO;
break;
}
ad >>= 1;
kp->bsel1 = ROMO;
kp->sel4 = ad;
passc(kp->bsel6);
passc(kp->bsel7);
kp->bsel1 = 0;
} else if (ad -= dsize*2, ad<dsize) {
kp->bsel1 = ROMO;
kp->sel4 = 0;
sav = kp->sel6;
kp->bsel1 = ROMI;
kp->sel6 = 010000|(ad&0377); /* mov ad,mar */
kp->bsel1 = ROMI|STEP;
kp->bsel1 = ROMI;
kp->sel6 = 04000|((ad>>8)&0377); /* mov %ad,%mar */
kp->bsel1 = ROMI|STEP;
kp->bsel1 = ROMI;
kp->sel6 = 055222; /* mov mem,csr2|mar++ */
kp->bsel1 = ROMI|STEP;
passc(kp->bsel2);
kp->bsel1 = ROMI;
kp->sel6 = sav;
kp->bsel1 = 0;
} else
break;
} while (u.u_error==0 && u.u_count);
}
kmcwrite(dev)
{
register struct device *kp;
register ad;
int dsize;
short ins;
ushort sav;
if (kmc[dev].k_stat&SRUN)
return;
dsize = (kmc[dev].k_type==KMC11A)?KASIZE:KBSIZE;
kp = kmc_addr[dev];
kp->bsel1 = 0;
while (u.u_error==0 && u.u_count) {
ad = u.u_offset;
if (ad<dsize*2) {
if (ad&1) {
u.u_error = ENXIO;
break;
}
kp->bsel1 = ROMO;
kp->sel4 = ad>>1;
lobyte(ins) = cpass();
hibyte(ins) = cpass();
kp->sel6 = ins;
kp->bsel1 |= CWRT;
kp->bsel1 = 0;
} else if (ad -= dsize*2, ad<dsize) {
kp->bsel1 = ROMO;
kp->sel4 = 0;
sav = kp->sel6;
kp->bsel1 = ROMI;
kp->sel6 = 010000|(ad&0377); /* mov ad,mar */
kp->bsel1 = ROMI|STEP;
kp->bsel1 = ROMI;
kp->sel6 = 04000|((ad>>8)&0377); /* mov %ad,%mar */
kp->bsel1 = ROMI|STEP;
kp->bsel1 = ROMI;
kp->bsel2 = cpass();
kp->sel6 = 0136440; /* mov csr2,mem|mar++ */
kp->bsel1 = ROMI|STEP;
kp->bsel1 = ROMI;
kp->sel6 = sav;
kp->bsel1 = 0;
} else
break;
}
}
kmcioctl(dev, cmd, arg, mode)
{
register struct device *kp;
register cd;
register struct kmc *tp;
int kk[3];
ushort sav;
if (cmd != TIOCSETP)
return;
if (copyin(arg, kk, sizeof(kk))) {
u.u_error = EFAULT;
return;
}
kp = kmc_addr[dev];
tp = &kmc[dev];
cd = kk[0];
if (tp->k_stat&SRUN && cd!=KSTOP && cd!=KMCLR) {
u.u_error = EIO;
return;
}
switch (cd) {
case KMCLR:
spl7();
kp->bsel1 = MCLR;
spl0();
case KSTOP:
tp->k_stat &= ~SRUN;
kp->bsel1 = 0;
break;
case KMS:
kp->bsel1 = ROMI|ROMO;
sav = kp->sel6;
kp->bsel1 = ROMI;
kp->sel6 = kk[2];
kp->bsel1 = ROMI|STEP;
kp->bsel1 = ROMI;
kp->sel6 = sav;
goto lcsr;
case KSTEP:
kp->bsel1 |= STEP;
case KCSR:
lcsr:
suword((caddr_t)kk[1], kp->sel0);
suword((caddr_t)kk[1]+2, kp->sel2);
suword((caddr_t)kk[1]+4, kp->sel4);
suword((caddr_t)kk[1]+6, kp->sel6);
kp->bsel1 = 0;
break;
case KRUN:
tp->k_stat &= ~STYPE;
tp->k_stat |= (kk[2]&STYPE)|SRUN;
kp->bsel1 |= RUN;
if (tp->k_stat&SRINT) {
spl5();
kmcrint(dev);
spl0();
}
break;
case KLU:
kp->bsel1 = kk[2]&(LUA|LUB);
break;
}
}
kmcrint(dev)
{
register struct device *kp;
register struct kmc *tp;
kp = kmc_addr[dev];
tp = &kmc[dev];
kp->sel0 &= ~IEI;
while (kp->sel2&RDYI) {
kp->bsel2 = getc(&tp->k_inq)|RDYI;
kp->bsel3 = getc(&tp->k_inq);
kp->bsel4 = getc(&tp->k_inq);
kp->bsel5 = getc(&tp->k_inq);
kp->bsel6 = getc(&tp->k_inq);
kp->bsel7 = getc(&tp->k_inq);
if (tp->k_inq.c_cc==0) {
kp->sel0 &= ~RQI;
kp->sel2 &= ~RDYI;
return;
}
kp->sel2 &= ~RDYI;
}
if (tp->k_inq.c_cc)
kp->sel0 |= IEI|RQI;
}
kmcxint(dev)
{
register struct device *kp;
register struct kmc *tp;
int p1, p2, p3, p4;
kp = kmc_addr[dev];
tp = &kmc[dev];
kp->sel0 &= ~IEO;
while(kp->sel2&RDYO) {
p1 = (dev<<6)|(kp->bsel3&077);
p2 = kp->bsel2&017;
p3 = kp->sel4;
p4 = kp->sel6;
kp->sel2 &= ~RDYO;
if (tp->k_stat&SRINT)
(*tp->k_rint)(p1, p2, p3, p4);
}
kp->sel0 |= IEO;
}
kmcload(dev, p1, p2, p3)
{
register struct device *kp;
register struct kmc *tp;
register unit;
int sps;
unit = (dev>>6)&03;
tp = &kmc[unit];
if (!(tp->k_stat&SRUN))
return(-1);
kp = kmc_addr[unit];
sps = spl5();
kp->sel0 |= RQI;
putc(lobyte(p1), &tp->k_inq);
putc(dev&077, &tp->k_inq);
putc(lobyte(p2), &tp->k_inq);
putc(hibyte(p2), &tp->k_inq);
putc(lobyte(p3), &tp->k_inq);
putc(hibyte(p3), &tp->k_inq);
kmcrint(unit);
splx(sps);
return(tp->k_inq.c_cc);
}
kmcset(dev, type, rint)
int (*rint)();
{
register struct device *kp;
register struct kmc *tp;
register unit;
unit = (dev>>6)&03;
kp = kmc_addr[unit];
tp = &kmc[unit];
if ((tp->k_stat&(STYPE|SRUN|SOPEN))!=((type&STYPE)|SRUN))
return (1);
tp->k_stat |= SRINT;
tp->k_rint = rint;
kp->sel0 |= IEO;
return(0);
}
kmcdclr(dev)
register dev;
{
register struct kmc *tp;
register struct device *kp;
if (dev < 0 || dev >= kmc_cnt)
return;
tp = &kmc[dev];
while (getc(&tp->k_inq) >= 0) ;
kp = kmc_addr[dev];
kp->sel0 = 0;
kp->sel2 = 0;
}