Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devconc.c

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


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

#include	"fcall.h"

#define	concdebug	1

#define	DPRINT	if(concdebug)kprint

typedef struct Conc	Conc;
typedef struct Subdev	Subdev;

/*
 *  A concentrator.  One exists for every stream that a 
 *  conc line discipline is pushed onto.
 */
struct Conc
{
	QLock;
	Stream *s;
	Queue *	wq;
	char	name[64];
	int	ndev;
	Subdev *dev;
	Block *	bp;
};

struct Subdev
{
	Conc *	cp;
	int	chan0;
	Queue *	rq;
};

static Lock	conclock;
static Conc	*concs;

/*
 * Concentrator line discipline (push here).
 */

static void concstopen(Queue*, Stream*);
static void concstclose(Queue*);
static void concstoput(Queue*, Block*);
static void concstiput(Queue*, Block*);
Qinfo concinfo =
{
	concstiput,
	concstoput,
	concstopen,
	concstclose,
	"conc"
};

/*
 * Stream interface to concentrator device (open here).
 */

static void concdevstopen(Queue*, Stream*);
static void concdevstclose(Queue*);
static void concdevstoput(Queue*, Block*);
static void concdevstiput(Queue*, Block*);
Qinfo concdevinfo =
{
	concdevstiput,
	concdevstoput,
	concdevstopen,
	concdevstclose,
	"concdev"
};

static void
concstopen(Queue *q, Stream *s)
{
	DPRINT("concstopen q=0x%ux s=0x%ux\n", q, s);

	RD(q)->ptr = 0;		/* (Conc *) for concstiput */
	WR(q)->ptr = s;

	s->opens++;		/* Hold this queue in place */
	s->inuse++;
}

static void
concstclose(Queue *q)
{
	Conc *cp = q->ptr;
	Subdev *dp;
	Block *bp;
	int ndev;

	if(RD(q)->ptr == 0)
		return;
	DPRINT("concstclose \"%s\"\n", cp->name);

	qlock(cp);
	ndev = cp->ndev;
	cp->ndev = 0;
	for(dp=cp->dev; dp<&cp->dev[ndev]; dp++){
			continue;
		bp = allocb(0);
		bp->type = M_HANGUP;
		PUTNEXT(dp->rq, bp);
	}
	qunlock(cp);
	cp->name[0] = 0;
}

static Conc *
concalloc(char *name, int aflag)
{
	Conc *free, *cp;

	DPRINT("concalloc \"%s\" %d...", name, aflag);
	lock(&conclock);
	free = 0;
	for(cp = concs; cp < &concs[conf.nconc]; cp++){
		if(strcmp(name, cp->name) == 0){
			unlock(&conclock);
			DPRINT("found\n");
			return cp;
		}
		if(cp->name[0] == 0)
			free = cp;
	}
	if(!aflag || free == 0){
		unlock(&conclock);
		DPRINT("not found/none free\n");
		return 0;
	}
	strncpy(free->name, name, sizeof free->name-1);
	unlock(&conclock);
	DPRINT("alloc'd\n");
	return free;
}

static void
concstoput(Queue *q, Block *bp)
{
	Conc *cp = 0;
	Subdev *dp;
	char *p, *err = 0;
	int n, ndev, k;

	if(bp->type != M_CTL || streamparse("config", bp) == 0){
		PUTNEXT(q, bp);
		return;
	}
	if(concdebug){
		char fmt[32];
		sprint(fmt, "concstoput config: %%.%ds\n", bp->wptr-bp->rptr);
		kprint(fmt, bp->rptr);
	}
	if(RD(q)->ptr){
		err = "stream already configured";
		goto out;
	}
	n = BLEN(bp);
	if(bp->wptr >= bp->lim){
		memmove(bp->base, bp->rptr, n);
		bp->rptr = bp->base;
		bp->wptr = bp->rptr+n;
	}
	*bp->wptr++ = 0;
	p = strchr((char *)bp->rptr, ' ');
	if(p == 0){
		err = "bad config command";
		goto out;
	}
	*p++ = 0;
	cp = concalloc((char *)bp->rptr, 1);
	bp->rptr = (uchar *)p;
	if(cp == 0){
		err = "no free conc's";
		goto out;
	}
	qlock(cp);
	if(cp->ndev){
		err = "conc name in use";
		goto out;
	}
	p = (char *)bp->rptr;
	for(ndev=0; strtoul(p, &p, 0); ndev++) ;
	DPRINT("concstoput: ndev=%d\n", ndev);
	cp->bp = allocb(ndev*sizeof(Subdev));
	if(cp->bp == 0){
		err = "can't allocb for subdevices";
		cp->name[0] = 0;
		goto out;
	}
	cp->dev = (Subdev *)cp->bp->base;
	p = (char *)bp->rptr;
	k = 0;
	DPRINT("concstoput: chan0=");
	for(dp=cp->dev; dp<&cp->dev[ndev]; dp++){
		dp->cp = cp;
		dp->chan0 = k;
		DPRINT(" %d", dp->chan0);
		k += strtoul(p, &p, 0);
		dp->rq = 0;
	}
	DPRINT("\n");
	cp->s = q->ptr;
	cp->wq = q;
	cp->ndev = ndev;
	q->ptr = cp;
	q->other->ptr = cp;
out:
	freeb(bp);
	if(cp)
		qunlock(cp);
	if(err){
		DPRINT("concstoput: err=\"%s\"\n", err);
		error(err);
	}
}

/*
 *  Simplifying assumption:  one put == one message && the channel number
 *	is in the first block (cf. dkmuxiput).
 */
static void
concstiput(Queue *q, Block *bp)
{
	Conc *cp = q->ptr;
	Subdev *dp;
	int chan;

	if(bp->type != M_DATA){
		PUTNEXT(q, bp);
		return;
	}
	if(BLEN(bp) < 2 || cp == 0)
		goto Drop;
	chan = bp->rptr[0] | (bp->rptr[1]<<8);
	for(dp=&cp->dev[cp->ndev-1]; dp>=cp->dev; dp--)
		if(chan >= dp->chan0)
			break;
	if(dp < cp->dev || dp->rq == 0)
		goto Drop;
	chan -= dp->chan0;
	bp->rptr[0] = chan;
	bp->rptr[1] = chan>>8;
	bp->flags |= S_DELIM;	/* a process is probably waiting for this */
	PUTNEXT(dp->rq, bp);
	return;
	
Drop:
	freeb(bp);
	return;
}

static void
concdevstopen(Queue *q, Stream *s)
{
	Conc *cp;
	Subdev *dp;

	cp = &concs[s->dev];
	qlock(cp);
	if(s->id > cp->ndev){
		qunlock(cp);
		error("no such subdevice");
	}
	dp = &cp->dev[s->id];
	q->ptr = dp;
	q->other->ptr = dp;
	dp->rq = RD(q);
	streamenter(cp->s);
	qunlock(cp);
}

static void
concdevstclose(Queue *q)
{
	Subdev *dp = q->ptr;
	Conc *cp = dp->cp;

	qlock(cp);
	q->ptr = 0;
	q->other->ptr = 0;
	dp->rq = 0;
	streamexit(cp->s, 0);
	qunlock(cp);
}

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

static void
concdevstoput(Queue *q, Block *bp)
{
	Subdev *dp = q->ptr;
	Conc *cp;
	int chan;

	if(dp == 0){
		DPRINT("concdevstoput: not config'd, dropped %d\n", BLEN(bp));
		freeb(bp);
		return;
	}
	cp = dp->cp;
	qlock(cp);
	if(!putq(q, bp)){	/* send only whole messages */
		qunlock(cp);
		return;
	}
	bp = grabq(q);
	qunlock(cp);
	if(BLEN(bp) < 2 || bp->type != M_DATA){
		DPRINT("concdevstoput: dropped %d\n", BLEN(bp));
		freeb(bp);
		return;
	}
	chan = bp->rptr[0] | (bp->rptr[1]<<8);
	chan += dp->chan0;
	bp->rptr[0] = chan;
	bp->rptr[1] = chan>>8;
	PUTNEXT(cp->wq, bp);
}

void
concreset(void)
{
	concs = ialloc(conf.nconc*sizeof(Conc), 0);
	newqinfo(&concinfo);
}

void
concinit(void)
{
}

Chan *
concattach(char *spec)
{
	Chan *c;
	Conc *cp;

	/*
	 *  find a concentrator with the same name (default conc)
	 */
	if(*spec == 0)
		spec = "conc";
	cp = concalloc(spec, 0);
	if(cp == 0 || cp->ndev == 0)
		error("device not configured");

	c = devattach('K', spec);
	c->dev = cp-concs;
	c->qid = (Qid){CHDIR, 0};
	return c;
}

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

#define	TOPDIR		(CHDIR+1)
#define	CHANDIR		(CHDIR+2)

static int
concgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
	Conc *cp;
	char buf[16];

	cp = &concs[c->dev];
	switch(c->qid.path){
	case CHDIR:
		devdir(c, (Qid){TOPDIR,0}, concs[c->dev].name, 0, eve, 0555, dp);
		return i==0 ? 1 : -1;
	case TOPDIR:
		if(i<0 || i >= cp->ndev)
			return -1;
		sprint(buf, "%d", i);
		devdir(c, (Qid){STREAMQID(i,CHANDIR),0}, buf, 0, eve, 0555, dp);
		return 1;
	}
	return streamgen(c, 0, 0, i, dp);
}

int	 
concwalk(Chan *c, char *name)
{
	return devwalk(c, name, 0, 0, concgen);
}

void	 
concstat(Chan *c, char *dp)
{
	char buf[16], *name;
	Dir dir;

	if(c->qid.path&CHDIR)switch(c->qid.path){
	case CHDIR:
		name = ".";
		break;
	case TOPDIR:
		name = concs[c->dev].name;
		break;
	default:
		sprint(name = buf, "%d", STREAMID(c->qid.path));
		break;
	}else switch(STREAMTYPE(c->qid.path)){
	case Sdataqid:
		name = "data";
		break;
	case Sctlqid:
		name = "ctl";
		break;
	default:
		name = "panic";
		break;
	}
	devdir(c, c->qid, name, 0, eve, (c->qid.path&CHDIR)?0555:0600, &dir);
	convD2M(&dir, dp);
}

Chan *
concopen(Chan *c, int omode)
{
	if(c->qid.path & CHDIR){
		if(omode != OREAD)
			error(Eperm);
	}else
		streamopen(c, &concdevinfo);
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

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

void	 
concclose(Chan *c)
{
	if(c->stream)
		streamclose(c);
}

long	 
concread(Chan *c, void *a, long n, ulong offset)
{
	if(c->stream)
		return streamread(c, a, n);
	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, concgen);
	error(Eio);
}

long	 
concwrite(Chan *c, void *a, long n, ulong offset)
{
	return streamwrite(c, a, n, 0);
}

void	 
concremove(Chan *c)
{
	USED(c);
	error(Eperm);
}

void	 
concwstat(Chan *c, char *dp)
{
	USED(c);
	error(Eperm);
}
.
## diffname port/devconc.c 1992/0611
## diff -e /n/bootesdump/1992/0609/sys/src/9/port/devconc.c /n/bootesdump/1992/0611/sys/src/9/port/devconc.c
468a
	return -1;	/* does not return */
.
## diffname port/devconc.c 1992/0620
## diff -e /n/bootesdump/1992/0611/sys/src/9/port/devconc.c /n/bootesdump/1992/0620/sys/src/9/port/devconc.c
288c
	streamexit(cp->s);
.
## diffname port/devconc.c 1992/0622
## diff -e /n/bootesdump/1992/0620/sys/src/9/port/devconc.c /n/bootesdump/1992/0622/sys/src/9/port/devconc.c
336c
	concs = xalloc(conf.nconc*sizeof(Conc));
.
## diffname port/devconc.c 1992/0627
## diff -e /n/bootesdump/1992/0622/sys/src/9/port/devconc.c /n/bootesdump/1992/0627/sys/src/9/port/devconc.c
288c
	streamexit(cp->s, 1);
.
9,10d
## diffname port/devconc.c 1992/0711
## diff -e /n/bootesdump/1992/0627/sys/src/9/port/devconc.c /n/bootesdump/1992/0711/sys/src/9/port/devconc.c
486c
	USED(c, dp);
.
472a
	USED(offset);
.
461a
	USED(offset);
.
448c
	USED(c, name, omode, perm);
.
378a
	USED(tab, ntab);
.
286c
	streamexit(cp->s);
.
## diffname port/devconc.c 1993/0501 # deleted
## diff -e /n/bootesdump/1992/0711/sys/src/9/port/devconc.c /n/fornaxdump/1993/0501/sys/src/brazil/port/devconc.c
1,491d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].