Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/gnot/devisdn.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname gnot/devisdn.c 1992/0609
## diff -e /dev/null /n/bootesdump/1992/0609/sys/src/9/gnot/devisdn.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"devtab.h"

#include	"io.h"
#ifdef	SET
#undef	SET
#endif
#include	"isdn.h"
#include	"unite.h"

#define DPRINT 	if(isdndebug)kprint

#define	BSIZE	260

Isdn *	isdndev;
Isdn *	isdndevN;

static void	devinit(int);
static void	devctl(Isdn*, int, int);
static void	devlctl(Isdn*, int);
static void	isdnkproc(void*);
static int	isdnintr(void);
static int	isdnInfo(Isdn*);
static int	isdnrecv(Isdn*);
static int	isdnxmit(Isdn*);

enum {
	Qdir, Qloop, QInfo, Qstats, Qdev, Qdebug
};

Dirtab isdndir[]={
	"loop",		{Qloop},	5,	0666,
	"info",		{QInfo},	1,	0666,
	"stats",	{Qstats},	0,	0444,
	"dev",		{Qdev},		0,	0666,
	"debug",	{Qdebug},	0,	0666,
};
#define	NISDN	(sizeof isdndir/sizeof(Dirtab))

/*
 *  I.430 stream module definition
 */
static void isdniput(Queue*, Block*);
static void isdnoput(Queue*, Block*);
static void isdnstopen(Queue*, Stream*);
static void isdnstclose(Queue*);
Qinfo isdninfo = { isdniput, isdnoput, isdnstopen, isdnstclose, "isdn" };

int	venval;
int	isdndebug;

void
isdnreset(void)
{
	isdndev = ialloc(conf.nisdn*sizeof(Isdn), 0);
	isdndevN = &isdndev[conf.nisdn];
}

void
isdninit(void)
{}

Chan*
isdnattach(char *spec)
{
	Chan *c;
	int dev;

	if(spec && *spec){
		if(*spec < '0' || *spec > '9')
			error(Enonexist);
		dev = strtoul(spec, 0, 0);
	}else
		dev = 0;
	if(dev >= conf.nisdn)
		error(Enonexist);
	if(!isdndev[dev].asr){
		addportintr(isdnintr);
		devinit(dev);
	}
	c = devattach('I', spec);
	c->dev = dev;
	return c;
}

Chan*
isdnclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int	 
isdnwalk(Chan *c, char *name)
{
	return devwalk(c, name, isdndir, NISDN, streamgen);
}

void	 
isdnstat(Chan *c, char *dp)
{
	devstat(c, dp, isdndir, NISDN, streamgen);
}

Chan*
isdnopen(Chan *c, int omode)
{
	if(c->qid.path == CHDIR){
		if(omode != OREAD)
			error(Eperm);
	}else switch(STREAMTYPE(c->qid.path)){
	case Qloop:
	case QInfo:
	case Qstats:
	case Qdev:
	case Qdebug:
		break;
	default:
		DPRINT("isdnopen dev=%d\n", c->dev);
		streamopen(c, &isdninfo);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void	 
isdncreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void	 
isdnclose(Chan *c)
{
	if(c->qid.path != CHDIR)
		streamclose(c);
}

long	 
isdnread(Chan *c, void *buf, long n, ulong offset)
{
	Isdn *ip = &isdndev[c->dev];
	char nbuf[512]; int k;

	if(n <= 0)
		return 0;
	if(c->qid.path == CHDIR){
		return devdirread(c, buf, n, isdndir, NISDN, streamgen);
	}else switch(STREAMTYPE(c->qid.path)){
	case Qloop:
		k = sprint(nbuf, "0x%2.2ux ", ip->lctl);
		goto Readnbuf;
	case QInfo:
		if(offset>0)
			return 0;
		k = isdnpeek(ip, &unite->listat)&Rss;
		*(char *)buf = "024L"[k>>2];
		return 1;
	case Qstats:
		k = 0;
		k += sprint(&nbuf[k], "inchars  %10lud\n", ip->inchars);
		k += sprint(&nbuf[k], "badcrc   %10lud\n", ip->badcrc);
		k += sprint(&nbuf[k], "abort    %10lud\n", ip->abort);
		k += sprint(&nbuf[k], "overrun  %10lud\n", ip->overrun);
		k += sprint(&nbuf[k], "badcount %10lud\n", ip->badcount);
		k += sprint(&nbuf[k], "overflow %10lud\n", ip->overflow);
		k += sprint(&nbuf[k], "toolong  %10lud\n", ip->toolong);
		k += sprint(&nbuf[k], "underrun %10lud\n", ip->underrun);
		k += sprint(&nbuf[k], "outchars %10lud\n", ip->outchars);
		goto Readnbuf;
	case Qdev:
		k = isdnpeek(ip, (void *)ip->devaddr);
		k = sprint(nbuf, "0x%2.2ux = 0x%2.2ux\n", ip->devaddr, k);
		goto Readnbuf;
	case Qdebug:
		k = sprint(nbuf, "%d\n", isdndebug);
	Readnbuf:
		if (offset >= k)
			return 0;
		if (offset+n > k)
			n = k - offset;
		memmove(buf, nbuf+offset, n);
		return n;
	}
	return streamread(c, buf, n);
}

long	 
isdnwrite(Chan *c, void *buf, long n, ulong offset)
{
	Isdn *ip = &isdndev[c->dev];
	char nbuf[32], *p;

	if(n <= 0)
		return 0;
	switch(STREAMTYPE(c->qid.path)){
	case Qloop:
		if(offset>0)
			return 0;
		if (n>sizeof nbuf)
			n = sizeof nbuf;
		memmove(nbuf, buf, n);
		nbuf[n-1] = 0;
		devlctl(ip, strtoul(nbuf,0,0));
		return n;
	case QInfo:
		if(offset>0)
			return 0;
		switch(*(char *)buf){
		case '0':
		case '1':
		case '3':
			devctl(ip, Tss, *(char *)buf - '0');
			break;
		default:
			error(Ebadarg);
		}
		return 1;
	case Qdev:
		if (n>sizeof nbuf)
			n = sizeof nbuf;
		memmove(nbuf, buf, n);
		nbuf[n-1] = 0;
		ip->devaddr = strtoul(nbuf,0,0);
		if (p = strchr(nbuf, '='))	/* assign = */
			isdnpoke(ip, (void *)ip->devaddr, strtoul(++p,0,0));
		return n;
	case Qdebug:
		if (n>sizeof nbuf)
			n = sizeof nbuf;
		memmove(nbuf, buf, n);
		nbuf[n-1] = 0;
		isdndebug = strtoul(nbuf,0,0);
		return n;
	}
	return streamwrite(c, buf, n, 0);
}

void	 
isdnremove(Chan *c)
{
	error(Eperm);
}

void	 
isdnwstat(Chan *c, char *dp)
{
	error(Eperm);
}

/*
 *	to sleep, perchance to dream...
 */

#define	Predicate(name, expr)	static int name(void *arg) { return expr; }
#define	ip	((Isdn *)arg)

Predicate(kLive, ip->kstart != 0)
Predicate(kDead, ip->kstart == 0)

Predicate(kRun, !ip->rq || ip->ri != ip->wi || ip->so != ip->ro)

Predicate(lActive, (ip->listat&Rss)>>1 == 4)

Predicate(tEmpty, ip->ro == ip->wo)
Predicate(tFull, NEXT(ip->wo) == ip->so)
Predicate(tNotFull, NEXT(ip->wo) != ip->so)

#undef	ip

/*
 *	the stream routines
 */

static void
isdnstopen(Queue *q, Stream *s)
{
	Isdn *ip = &isdndev[s->dev];
	char name[32];
	int rss;

	DPRINT("isdnstopen %d...", s->dev);
	qlock(&ip->kctl);
	if (ip->kstart) {
		qunlock(&ip->kctl);
		DPRINT("active\n", s->dev);
		return;
	}
	q->ptr = q->other->ptr = ip;
	ip->rq = q;
	rss = (isdnpeek(ip, &unite->listat)&Rss)>>1;
	if (ip->lctl & Lld)		/* if loopback D, */
		devctl(ip, Tss, 0);	/* transmit INFO 0 */
	else if (rss == 2 || rss ==4)	/* else if line active */
		devctl(ip, Tss, 3);	/* transmit INFO 3 */
	else
		devctl(ip, Tss, 1);	/* transmit INFO 1 */
	sprint(name, "isdn%d", s->dev);
	kproc(name, isdnkproc, ip);
	if (waserror()) {
		qunlock(&ip->kctl);
		DPRINT("aborted\n");
		nexterror();
	}
	sleep(&ip->kctlr, kLive, ip);
	qunlock(&ip->kctl);
	poperror();
	DPRINT("started\n");
	if (!(ip->lctl & Lld)) {
		DPRINT("waiting for INFO 4\n");
		sleep(&ip->ar, lActive, ip);
		DPRINT("got INFO 4\n");
	}
}

static void
isdnstclose(Queue * q)
{
	Isdn *ip = (Isdn *)q->ptr;
	DPRINT("isdnstclose %d...", ip-isdndev);
	qlock(&ip->kctl);
	qlock(ip);
	ip->rq = 0;
	qunlock(ip);
	wakeup(&ip->kr);
	if (waserror()) {
		qunlock(&ip->kctl);
		DPRINT("aborted\n");
		nexterror();
	}
	sleep(&ip->kctlr, kDead, ip);
	qunlock(&ip->kctl);
	poperror();
	DPRINT("stopped\n");
}

static void
showframe(char *t, uchar *buf, int n)
{
	kprint("I %s [", t);
	while (--n >= 0)
		kprint(" %2.2ux", *buf++);
	kprint(" ]\n");
}

/*
 *  this is only called by hangup
 */
static void
isdniput(Queue *q, Block *bp)
{
	PUTNEXT(q, bp);
}

/*
 *  output a block
 */
static void
isdnoput(Queue *q, Block *bp)
{
	Isdn *ip = (Isdn *)q->ptr;
	uchar set, clr;

	if(bp->type != M_DATA){
		set = clr = 0;
		if(streamparse("ear", bp)){
			if(streamparse("on", bp))
				set = DRCODEC;
			else if(streamparse("off", bp))
				clr = DRCODEC;
		}else if(streamparse("mic", bp)){
			if(streamparse("on", bp))
				set = DXCODEC;
			else if(streamparse("off", bp))
				clr = DXCODEC;
		}
		freeb(bp);
		isdnlock(ip);
		ip->venval &= ~clr;
		ip->venval |= set;
		*(ip->asr) = ip->venval;
		isdnunlock(ip);
		return;
	}
	qlock(&ip->wlock);
	if(!putq(q, bp)){	/* send only whole messages */
		qunlock(&ip->wlock);
		return;
	}
	DPRINT("isdnoput: len=%d\n", q->len);
	if (tFull(ip))
		sleep(&ip->tr, tNotFull, ip);
	ip->outb[ip->wo] = grabq(q);
	ip->wo = NEXT(ip->wo);
	qunlock(&ip->wlock);

	isdnlock(ip);
	if (isdnxmit(ip))
		wakeup(&ip->kr);
	isdnunlock(ip);
}

static void
isdnkproc(void *arg)
{
	Isdn *ip = (Isdn *)arg;
	int i;

	if (waserror()) {
		devctl(ip, Enr, 0);
		ip->kstart = 0;
		wakeup(&ip->kctlr);
		return;
	}
	/*
	 *  create a number of blocks for input
	 */
	for (i=0; i<NB; i++)
		if (!ip->inb[i])
			ip->inb[i] = allocb(BSIZE);
	ip->ri = 0;
	ip->wi = 0;
	devctl(ip, 0, Enr);
	ip->kstart = 1;
	wakeup(&ip->kctlr);
	for (;;) {
		qlock(ip);
		if (!ip->rq) {
			qunlock(ip);
			break;
		}
		while (ip->ri != ip->wi) {
			PUTNEXT(ip->rq, ip->inb[ip->ri]);
			ip->inb[ip->ri] = allocb(BSIZE);
			ip->ri = NEXT(ip->ri);
		}
		i = 0;
		while (ip->so != ip->ro) {
			freeb(ip->outb[ip->so]);
			ip->so = NEXT(ip->so);
			i++;
		}
		qunlock(ip);
		if (i)
			wakeup(&ip->tr);
		sleep(&ip->kr, kRun, ip);
	}
	devctl(ip, Enr, 0);
	sleep(&ip->kr, tEmpty, ip);
	while (ip->so != ip->ro) {
		freeb(ip->outb[ip->so]);
		ip->so = NEXT(ip->so);
	}
	poperror();
	ip->kstart = 0;
	wakeup(&ip->kctlr);
}

void
isdnlock(Isdn *ip)
{
	int s;

	s = spl2();
	lock(&ip->dev);
	ip->pri = s;
}

void
isdnunlock(Isdn *ip)
{
	int s;

	s = ip->pri;
	unlock(&ip->dev);
	splx(s);
}

static void
devinit(int h)
{
	Isdn *ip = &isdndev[h];

	isdnlock(ip);
	ip->asr = ISDNDEV0+2*h;
	ip->data = ip->asr+1;
	ip->venval = DRCODEC | DXCODEC;
	SET(unite->reset, Mres);
	ip->lctl = 0;		/* no loopback or 1's transmission */
	SET(unite->lctl, ip->lctl);
	SET(unite->stictl, Prye); /* S/T interface normal */
	SET(unite->itl, 0x88);	/* interrupt on 8 rcv/xmit char's */
	SET(unite->hcr, Tpol|Ipol|Clkmux|B2f|B1f);
	ip->tctl = Ent;		/* enable transmitter, send INFO 0 */
	ip->imask = Richgie|Teie;
	SET(unite->tctl, ip->tctl);
	SET(unite->imask, ip->imask);
	ip->listat = GET(unite->listat);
	isdnunlock(ip);
}

static void
devctl(Isdn *ip, int clear, int set)
{
	isdnlock(ip);
	ip->tctl &= ~clear;
	ip->tctl |= set;
	if (clear & Ent)
		ip->imask &= ~Teie;
	if (set & Ent)
		ip->imask |= Teie;
	if (clear & Enr)
		ip->imask &= ~(Rfie|Reofie);
	if (set & Enr)
		ip->imask |= (Rfie|Reofie);
	ip->imask |= Richgie;
	SET(unite->tctl, ip->tctl);
	SET(unite->imask, ip->imask);
	isdnunlock(ip);
}

int
isdnpeek(Isdn *ip, void *arg)
{
	int r;

	isdnlock(ip);
	SETADDR(arg);
	r = *(ip->data);
	isdnunlock(ip);
	return r;
}

void
isdnpoke(Isdn *ip, void *arg, int data)
{
	isdnlock(ip);
	SETADDR(arg);
	*(ip->data) = data;
	isdnunlock(ip);
}

static void
devlctl(Isdn *ip, int val)
{
	isdnlock(ip);
	ip->lctl = val;
	SET(unite->lctl, val);
	if (val & Lld)
		SET(unite->stictl, Clrmm);
	else
		SET(unite->stictl, Prye);
	isdnunlock(ip);
}

static int
isdnintr(void)
{
	int status, wake = 0, intr = 0;
	Isdn *ip;

	for(ip=isdndev; ip<isdndevN; ip++){
		if (!ip->asr)
			continue;
		if (!(*(ip->asr)&Uint))
			continue;
		++intr;
		status = GET(unite->istat);
		if (status & Richg)
			wake += isdnInfo(ip);
		if (status & (Rfull|Reof))
			wake += isdnrecv(ip);
		if (status & Tempty)
			wake += isdnxmit(ip);
		if (wake)
			wakeup(&ip->kr);
	}
	return intr;
}

static int
isdnInfo(Isdn *ip)
{
	int newstat;

	newstat = GET(unite->listat);
	DPRINT("isdnInfo: old=0x%2.2ux, new=0x%2.2ux\n",
		ip->listat, newstat);
	ip->listat = newstat;
	if (!ip->rq) {
		ip->imask &= ~Richgie;
		SET(unite->imask, ip->imask);
		return 0;
	}
	newstat = (newstat&Rss)>>1;
	ip->tctl &= ~Tss;
	if (newstat == 2 || newstat == 4)
		ip->tctl |= 3;	/* transmit INFO 3 */
	else
		ip->tctl |= 1;	/* transmit INFO 1 */
	SET(unite->tctl, ip->tctl);
	DPRINT("isdnInfo: tctl=0x%2.2ux\n", ip->tctl);
	if (newstat == 4)
		wakeup(&ip->ar);
	return 0;
}

static int
isdnrecv(Isdn *ip)
{
	Block *bp = ip->inb[ip->wi];
	uchar status, *p;
	int i, n, wake = 0;
Loop:
	status = GET(unite->rstat);
	if (status&Overrun) {
		ip->overrun++;
		goto Reset;
	}
	if (!(n = status&Rqs))
		return wake;
	p = bp->wptr;
	if (p+n > bp->lim) {
		ip->toolong++;
		goto Reset;
	}
	ip->inchars += n;
	SETADDR(&unite->data);
	while (--n >= 0)
		*p++ = *(ip->data);
	if (status&Eof) {
		if (*--p == 0) {
			i = NEXT(ip->wi);
			if (i == ip->ri)
				ip->overflow++;
			else {
				bp->wptr = p;
				bp->flags |= S_DELIM;
				ip->wi = i;
				bp = ip->inb[i];
				++wake;
			}
		} else {
			if (*p & 0x80)
				ip->badcrc++;
			if (*p & 0x40)
				ip->abort++;
			if (*p & 0x20)
				ip->overrun++;
			if (*p & 0x10)
				ip->badcount++;
		}
		bp->wptr = bp->base;
	} else
		bp->wptr = p;
	goto Loop;
Reset:
	bp->wptr = bp->base;
	SET(unite->reset, Rres);
	return wake;
}

static int
isdnxmit(Isdn *ip)
{
	Block *bp;
	uchar status, *p;
	int n, k, wake = 0;
Loop:
	status = GET(unite->tstat);
	if (status&Undabt) {
		ip->underrun++;
		SET(unite->reset, Tres);
		if (ip->out) {
			ip->ro = NEXT(ip->ro);
			ip->out = 0;
			++wake;
		}
	}
	if (!(n = status&Tqs))
		return wake;
	if (!(bp = ip->out)) {
		if (ip->ro == ip->wo)
			return wake;
		ip->out = bp = ip->outb[ip->ro];
	}
	p = bp->rptr;
	k = bp->wptr - p;
	if (n > k)
		n = k;
	ip->outchars += n;
	SETADDR(&unite->data);
	while (--n >= 0)
		*(ip->data) = *p++;
	bp->rptr = p;
	if (bp->rptr == bp->wptr) {
		if (bp->flags & S_DELIM)
			SET(unite->tctl, ip->tctl|Tfc);
		if (!(ip->out = bp = bp->next)) {
			ip->ro = NEXT(ip->ro);
			++wake;
		}
	}
	goto Loop;
}
.
## diffname gnot/devisdn.c 1992/0627
## diff -e /n/bootesdump/1992/0609/sys/src/9/gnot/devisdn.c /n/bootesdump/1992/0627/sys/src/9/gnot/devisdn.c
60c
	isdndev = xalloc(conf.nisdn*sizeof(Isdn));
.
## diffname gnot/devisdn.c 1992/0630
## diff -e /n/bootesdump/1992/0627/sys/src/9/gnot/devisdn.c /n/bootesdump/1992/0630/sys/src/9/gnot/devisdn.c
664a
	bp->rptr = bp->base;
.
659a
		bp->rptr = bp->base;
.
## diffname gnot/devisdn.c 1992/0701
## diff -e /n/bootesdump/1992/0630/sys/src/9/gnot/devisdn.c /n/bootesdump/1992/0701/sys/src/9/gnot/devisdn.c
456c
	while(ip->so != ip->ro){
.
444c
		while(ip->so != ip->ro){
.
438,439c
		while (ip->ri != ip->wi){
			FLOWCTL(ip->rq, ip->inb[ip->ri]);
.
434c
		if (!ip->rq){
.
432c
	for(;;){
.
424c
	for(i=0; i<NB; i++)
.
415c
	if(waserror()){
.
18c
#define	BSIZE	200	/* should be 260, but for xalloc */
.
## diffname gnot/devisdn.c 1992/0711
## diff -e /n/bootesdump/1992/0701/sys/src/9/gnot/devisdn.c /n/bootesdump/1992/0711/sys/src/9/gnot/devisdn.c
253a
	USED(c, dp);
.
247a
	USED(c);
.
134a
	USED(c, name, omode, perm);
.
## diffname gnot/devisdn.c 1992/1204
## diff -e /n/bootesdump/1992/0711/sys/src/9/gnot/devisdn.c /n/bootesdump/1992/1204/sys/src/9/gnot/devisdn.c
613a
		return 0;
	}
	if(oldstat == 4){
		ip->hangup = 1;
		return 1;
	}
.
612c
	if(newstat == 4){
.
597a
	oldstat = (ip->listat&Rss)>>1;
.
593c
	int oldstat, newstat;
.
564a
static void
devb1xb2(Isdn *ip, int val)
{
	isdnlock(ip);
	if(val)
		ip->stictl |= B1xb2;
	else
		ip->stictl &= ~B1xb2;
	SET(unite->stictl, ip->stictl);
	isdnunlock(ip);
}

.
561c
		ip->stictl |= Prye;
	SET(unite->stictl, ip->stictl);
.
559c
		ip->stictl |= Clrmm;
.
557a
	ip->stictl &= ~(Clrmm|Prye);
.
500c
	ip->stictl = Prye;	/* S/T interface normal */
	SET(unite->stictl, ip->stictl);
.
445a
		if(ip->hangup){
			ip->hangup = 0;
			bp = allocb(0);
			bp->type = M_HANGUP;
			PUTNEXT(ip->rq, bp);
		}
.
441c
		while(ip->ri != ip->wi){
.
437c
		if(!ip->rq){
.
415a
	Block *bp;
.
299a
	ip->hangup = 0;
.
225c
		return n;
	case Qb1xb2:
		if(offset>0)
			return 0;
		switch(*(char *)buf){
		case '0':
		case '1':
			devb1xb2(ip, *(char *)buf - '0');
			break;
		default:
			error(Ebadarg);
		}
		return n;
.
183,190c
		sprint(nbuf, "%d\n", isdndebug);
		return readstr(offset, buf, n, nbuf);
.
180,181c
		sprint(nbuf, "0x%2.2ux = 0x%2.2ux\n", ip->devaddr, k);
		return readstr(offset, buf, n, nbuf);
.
167,177c
		p = nbuf;
		p += sprint(p, "inchars  %10lud\n", ip->inchars);
		p += sprint(p, "badcrc   %10lud\n", ip->badcrc);
		p += sprint(p, "abort    %10lud\n", ip->abort);
		p += sprint(p, "overrun  %10lud\n", ip->overrun);
		p += sprint(p, "badcount %10lud\n", ip->badcount);
		p += sprint(p, "overflow %10lud\n", ip->overflow);
		p += sprint(p, "toolong  %10lud\n", ip->toolong);
		p += sprint(p, "underrun %10lud\n", ip->underrun);
		p += sprint(p, "outchars %10lud\n", ip->outchars);
		USED(p);
		return readstr(offset, buf, n, nbuf);
.
165a
	case Qb1xb2:
		if(offset>0)
			return 0;
		k = isdnpeek(ip, &unite->stictl)&B1xb2;
		*(char *)buf = "01"[k != 0];
		return 1;
.
158,159c
		sprint(nbuf, "0x%2.2ux ", ip->lctl);
		return readstr(offset, buf, n, nbuf);
.
150c
	char nbuf[512], *p;
	int k;
.
117a
	case Qb1xb2:
.
38a
	"b1xb2",	{Qb1xb2},	1,	0666,
.
33c
	Qdir, Qloop, QInfo, Qb1xb2, Qstats, Qdev, Qdebug
.
25a
static void	devb1xb2(Isdn*, int);
.
## diffname gnot/devisdn.c 1993/0127
## diff -e /n/bootesdump/1992/1204/sys/src/9/gnot/devisdn.c /n/bootesdump/1993/0127/sys/src/9/gnot/devisdn.c
88c
	c = devattach('J', spec);
.
## diffname gnot/devisdn.c 1993/0501 # deleted
## diff -e /n/bootesdump/1993/0127/sys/src/9/gnot/devisdn.c /n/fornaxdump/1993/0501/sys/src/brazil/gnot/devisdn.c
1,763d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.