SysIII/usr/src/uts/vax/pwb/st.c
/*
* TTY 40/4 driver for VAX 11/780
*/
#include "sys/param.h"
#include "sys/st.h"
#include "sys/dir.h"
#include "sys/map.h"
#include "sys/user.h"
#include "sys/proc.h"
#include "sys/buf.h"
#define NULL 0
#define STMPRI (PZERO + 1) /* allow interrupted reads */
#define stid(X) (unsigned)((X->sm_sta << 8) | X->sm_dev)
extern struct st st_st[]; /* sync channels */
extern int st_cnt; /* number of channels */
extern int _sdata;
struct map stomap[STMAP]; /* map for alloc of stbuf */
struct map stimap[STMAP]; /* map for alloc of stbuf */
struct stbhdr sthdrb[STHBUF]; /* header buffer pool */
struct buf sthdr; /* mask for bigetc use */
unsigned wrccnt;
int stoflg, sthflg;
char stobuf[STOBSZ];
char stibuf[STIBSZ];
int stibase, stobase;
struct stbhdr *ffree;
unsigned sthdcnt = 0;
unsigned stopflg;
unsigned ttyid[NKMC];
stopen(dev)
int dev;
{
register struct st *dp;
register struct stmsghdr *hp;
register int *ip;
dp = &st_st[dev];
if(dev >= st_cnt) {
u.u_error = ENXIO;
return;
}
spl5();
if ((dp->s_flags & CH_OPEN) == NULL) {
ip = (int *)dp;
while (ip!=(int *)(((caddr_t)dp)+sizeof(struct st)))
*ip++ = 0;
hp = &dp->s_hdr;
hp->s_act = 0;
hp->s_max = NSTCHQ;
hp->s_first = hp->s_last = 0;
if (dev < STNDSCH) {
dp->s_flags = CH_OPEN;
dp->s_ttyid = (unsigned) ( -(dev + 1));
dp->s_mode = STRAW;
} else {
dp->s_flags |= (CH_OPEN|CH_AVAIL);
while(dp->s_flags & CH_AVAIL)
sleep((caddr_t)dp,STMPRI);
dp->s_mode = STRAW;
}
}
spl0();
if ((dp->s_mode == 0) && (dev >= STNDSCH)) {
u.u_error = ENXIO;
return;
}
}
stclose(dev)
int dev;
{
register struct st *dp;
register struct stbhdr *mp;
extern struct stbhdr *getmsg();
dp = &st_st[dev];
spl5();
if (dp->s_rbuf)
stfree((unsigned) stimap,dp->s_rbuf);
while(mp = getmsg(&dp->s_hdr))
stfree((unsigned)stimap, mp);
dp->s_flags = NULL;
spl0();
}
stwrite(dev)
int dev;
{
register struct st *dp;
register short unsigned loc;
dp = &st_st[dev];
while ((loc=malloc(stomap,round(u.u_count))) == NULL) {
stoflg++;
sleep((caddr_t)stomap,STMPRI);
}
iomove(loc+stobuf,wrccnt=u.u_count,B_WRITE);
while(putmsg(loc,wrccnt,wrccnt,dp) == NULL) {
sthflg++;
sleep((caddr_t)&sthflg,STMPRI);
}
}
stread(dev)
int dev;
{
register struct st *dp;
register struct stbhdr *mp;
extern struct stbhdr *getmsg();
unsigned n, cnt;
dp = &st_st[dev];
spl5();
while(((dp->s_hdr).s_act==0)&&(dp->s_rbuf==NULL))
sleep((caddr_t)dp, STMPRI);
spl0();
while((cnt=u.u_count) && u.u_error == 0) {
if (dp->s_rbuf == NULL)
if ((dp->s_rbuf = getmsg(&dp->s_hdr)) == NULL)
return;
else
dp->s_roffset = 0;
mp = dp->s_rbuf;
iomove(mp->sm_loc + stibuf + dp->s_roffset,
n=min(cnt,mp->sm_count - dp->s_roffset),B_READ);
if (n == (mp->sm_count - dp->s_roffset)) {
stfree((unsigned)stimap,mp);
dp->s_rbuf = NULL;
}
else
dp->s_roffset += n;
continue;
}
}
strxint(sel0,sel2,sel4)
unsigned sel0, sel2;
register struct stbhdr *sel4;
{
switch(sel2) {
case RRTNXBUF:
if (sel4->sm_type & FAIL)
printf("stxmit fail\n");
stfree((unsigned)stomap,sel4);
break;
case RRTNEBUF:
stfree((unsigned)stimap,sel4);
break;
case RRTNRBUF:
strcvb(sel0);
stinput(sel0,sel4);
break;
}
}
stioctl(dev,cmd,arg,mode)
{
register struct st *dp;
struct set {
char s_spa;
char s_ssa;
char typet;
char s_dev;
unsigned mode;
} setbuff;
register struct set *sp = &setbuff;
extern struct stbhdr *stghdr();
register unsigned i;
dp = &st_st[dev];
if (dev < STNDSCH) {
if (copyin(arg,sp,sizeof setbuff)) {
u.u_error = EFAULT;
return;
}
dp->s_port = sp->s_dev;
if (sp->mode) {
vpmstop(sp->s_dev);
stopflg |= (1 << (sp->s_dev & 07));
return;
}
for (i=STOBSZ; i; i>>=1)
while (malloc(stomap,i));
for (i=STIBSZ; i; i>>=1)
while (malloc(stimap,i));
sthdcnt = 0;
stinithd();
mfree((unsigned)stomap,STOBSZ-sizeof(int),sizeof(int));
mfree((unsigned)stimap,STIBSZ-sizeof(int),sizeof(int));
stobase = (int)stobuf - (int)&_sdata;
stibase = (int)stibuf - (int)&_sdata;
if (u.u_error = vpmstart(sp->s_dev,STRM,strxint))
return;
stopflg &= ~(1 << (sp->s_dev & 07));
strcvb((unsigned)sp->s_dev & 0377);
}
}
stinput(sel0,mp)
register struct stbhdr *mp;
unsigned sel0;
{
register struct st *cp, *ap;
struct st *ep;
int sps;
ap = cp = NULL;
ep = &st_st[st_cnt];
sps = spl5();
if (mp->sm_type & FBLOCK)
ttyid[sel0 & 07] = stid(mp);
for(cp = &st_st[1]; cp != ep; cp++) {
if(cp->s_ttyid == ttyid[sel0 & 07] &&
cp->s_port == sel0 &&
(cp->s_flags & (CH_OPEN | CH_AVAIL)) == CH_OPEN)
break;
if(!ap && cp->s_flags & CH_AVAIL)
ap = cp;
}
if(cp != ep) {
if(putmesgi(&cp->s_hdr, mp)) {
if ((mp->sm_type & LBLOCK) ||
((cp->s_hdr).s_max <= (cp->s_hdr).s_act))
wakeup((caddr_t)cp);
splx(sps);
return(NULL);
}
} else if(cp == ep && ap) {
if(putmesgi(&ap->s_hdr, mp)) {
ap->s_flags &= ~CH_AVAIL;
ap->s_ttyid = ttyid[sel0 & 07];
ap->s_port = sel0;
if ((mp->sm_type & LBLOCK) ||
((ap->s_hdr).s_max <= (ap->s_hdr).s_act))
wakeup((caddr_t)ap);
splx(sps);
return(NULL);
}
}
stfree((unsigned)stimap,mp);
splx(sps);
return(ENOSPC);
}
static
putmsg(loc, size, count, cp)
register struct st *cp;
unsigned loc, size, count;
{
register struct stbhdr *dp;
extern struct stbhdr *stghdr();
int sttemp;
if((dp = stghdr()) == 0)
return(NULL);
sttemp = stobase + loc;
dp->sm_locu = (sttemp>>16) & 03;
dp->sm_locl = sttemp & 0177777;
dp->sm_loc = loc;
dp->sm_size = size;
dp->sm_count = count;
dp->sm_sta = (cp->s_ttyid >> 8) & 0377;
dp->sm_dev = cp->s_ttyid & 0377;
dp->sm_type = 0;
vpmxmtq((unsigned) cp->s_port,dp);
return(1);
}
static
putmesgi(hdr,mp)
register struct stmsghdr *hdr;
register struct stbhdr *mp;
{
register struct stbhdr *mp2;
if (hdr->s_act == hdr->s_max) {
return(NULL);
}
hdr->s_act++;
if (hdr->s_first == NULL)
hdr->s_first = mp;
if (mp2 = hdr->s_last)
mp2->sm_nxt = mp;
hdr->s_last = mp;
return(1);
}
static
struct stbhdr *
getmsg(hdr)
register struct stmsghdr *hdr;
{
register struct stbhdr *dp;
if(hdr->s_act) {
if (--hdr->s_act == 0)
hdr->s_last = 0;
dp = hdr->s_first;
hdr->s_first = dp->sm_nxt;
return(dp);
}
else
return(NULL);
}
static
stfree(map,mp)
unsigned map;
register struct stbhdr *mp;
{
register int sps;
sps = spl5();
mfree(map,round(mp->sm_size),mp->sm_loc);
stphdr(mp);
if (stoflg) {
stoflg = 0;
wakeup((caddr_t)stomap);
}
splx(sps);
}
stinithd()
{
register struct stbhdr *bp;
ffree = NULL;
for (bp=sthdrb;bp < &sthdrb[STHBUF];bp++)
stphdr(bp);
}
stphdr(bp)
register struct stbhdr *bp;
{
register int sps;
sps = spl5();
bp->sm_nxt = ffree;
ffree = bp;
sthdcnt++;
if (sthflg) {
sthflg = 0;
wakeup((caddr_t) &sthflg);
}
splx(sps);
return(0);
}
struct stbhdr *
stghdr()
{
register struct stbhdr *bp;
register int sps;
sps = spl5();
if (ffree == NULL) {
splx(sps);
return(0);
}
bp = ffree;
ffree = bp->sm_nxt;
bp->sm_nxt = 0;
sthdcnt--;
splx(sps);
return(bp);
}
strcvb(sel0)
unsigned sel0;
{
unsigned mem;
struct stbhdr *bp;
int sttemp;
if (stopflg & (1 << (sel0 & 07)))
return;
while(vpmemptq(sel0,(struct stbhdr *)0) < RCVLEN) {
bp = NULL;
if ((bp=stghdr()) && (mem=malloc(stimap,STMBSZ))) {
bp->sm_count = bp->sm_size = STMBSZ;
bp->sm_type = 0;
sttemp = stibase + mem;
bp->sm_locu = (sttemp>>16) & 03;
bp->sm_locl = sttemp & 0177777;
bp->sm_loc = mem;
vpmemptq(sel0,bp);
} else {
if (bp)
stphdr(bp);
timeout(strcvb,sel0,60);
break;
}
}
}