plan 9 kernel history: overview | file list | diff list

1994/1113/pc/devastar.c (diff list | history)

1994/1112/sys/src/9/pc/devastar.c:11,171994/1113/sys/src/9/pc/devastar.c:11,30 (short | long | prev | next)
1994/1106    
/* 
1994/1107    
 *  Stargate's Avanstar serial board.  There are ISA, EISA, microchannel 
 *  versions.  We only handle the ISA one. 
1994/1113    
 * 
 *  At the expense of performance, I've tried to be careful about 
 *  endian-ness to make this convertable to other ISA bus machines. 
 *  However, xchngus() is in assembler and will have to be translated. 
1994/1106    
 */ 
1994/1113    
#define LENDIAN 1 
 
/* unsigned short little endian representation */ 
#ifdef LENDIAN 
#define LEUS(x) (x) 
#else 
#define LEUS(x) ( (((x)<<8)&0xff00) | (((x)>>8)&0xff) ) 
#endif LENDIAN 
 
1994/1106    
typedef struct Astar Astar; 
1994/1107    
typedef struct Astarchan Astarchan; 
1994/1106    
 
1994/1112/sys/src/9/pc/devastar.c:37,461994/1113/sys/src/9/pc/devastar.c:50,62
1994/1107    
 
1994/1112    
	Maxcard=	8, 
	Pramsize=	64*1024,	/* size of program ram */ 
	Footshift=	14,		/* footprint of card mem in ISA space */ 
	Footprint=	1<<Footshift, 
1994/1113    
	Pageshift=	14,		/* footprint of card mem in ISA space */ 
	Pagesize=	1<<Pageshift, 
	Pagemask=	Pagesize-1, 
1994/1106    
}; 
 
1994/1113    
#define APAGE(x) ((x)>>Pageshift) 
 
1994/1107    
/* IRQ codes */ 
static int isairqcode[16] = 
{ 
1994/1112/sys/src/9/pc/devastar.c:60,681994/1113/sys/src/9/pc/devastar.c:76,84
1994/1106    
	ushort	avail;		/* available buffer space */ 
	ushort	type;		/* board type */ 
	ushort	cpvers;		/* control program version */ 
	ushort	ccbc;		/* control channel block count */ 
	ushort	ccbo;		/* control channel block offset */ 
	ushort	ccbc;		/* control channel block size */ 
1994/1113    
	ushort	ccbn;		/* control channel block count */ 
	ushort	ccboff;		/* control channel block offset */ 
	ushort	ccbsz;		/* control channel block size */ 
1994/1106    
	ushort	cmd2;		/* command word 2 */ 
	ushort	status2;	/* status word 2 */ 
	ushort	errserv;	/* comm error service request 'X' */ 
1994/1112/sys/src/9/pc/devastar.c:146,1551994/1113/sys/src/9/pc/devastar.c:162,168
1994/1107    
	Cb115200=	0xff01, 
 
	/* CCB.format fields */ 
	C5bit=		0<<0,	/* data bits */ 
	C6bit=		0<<1, 
	C7bit=		0<<2, 
	C8bit=		0<<3, 
1994/1113    
	Clenmask=	3<<0,	/* data bits */ 
1994/1107    
	C1stop=		0<<2,	/* stop bits */ 
	C2stop=		1<<2, 
	Cnopar=		0<<3,	/* parity */ 
1994/1112/sys/src/9/pc/devastar.c:157,1621994/1113/sys/src/9/pc/devastar.c:170,176
1994/1107    
	Cevenpar=	3<<3, 
	Cmarkpar=	5<<3, 
	Cspacepar=	7<<3, 
1994/1113    
	Cparmask=	7<<3, 
1994/1107    
	Cnormal=	0<<6,	/* normal mode */ 
	Cecho=		1<<6,	/* echo mode */ 
	Clloop=		2<<6,	/* local loopback */ 
1994/1112/sys/src/9/pc/devastar.c:220,2301994/1113/sys/src/9/pc/devastar.c:234,248
1994/1107    
	ISAConf; 
	int		id;		/* from plan9.ini */ 
1994/1111    
	int		nchan;		/* number of channels */ 
1994/1112    
	Rendez		r; 
1994/1111    
	Astarchan	*c;		/* channels */ 
1994/1107    
	int		ramsize;	/* 16k or 256k */ 
1994/1106    
	GCB		*gbc;		/* board comm area */ 
1994/1112    
	char		*addr;		/* memory area */ 
1994/1113    
	int		memsize;	/* size of memory currently mapped */ 
	int		page;		/* page currently mapped */ 
	GCB		*gbc;		/* global board comm area */ 
	uchar		*addr;		/* base of memory area */ 
	int		running; 
 
	Rendez		r;		/* when waiting for board */ 
1994/1106    
}; 
 
/* host per channel info */ 
1994/1112/sys/src/9/pc/devastar.c:233,2391994/1113/sys/src/9/pc/devastar.c:251,257
1994/1106    
	QLock; 
 
1994/1109    
	Astar	*a;	/* controller */ 
1994/1107    
	CCB	*ccb;	/* control block */ 
1994/1113    
	CCB	*ccb;	/* channel control block */ 
1994/1111    
	int	perm; 
1994/1112    
	int	opens; 
1994/1107    
 
1994/1112/sys/src/9/pc/devastar.c:240,2451994/1113/sys/src/9/pc/devastar.c:258,264
1994/1106    
	/* buffers */ 
	Queue	*iq; 
	Queue	*oq; 
1994/1113    
	Rendez	r; 
1994/1106    
}; 
 
1994/1109    
Astar *astar[Maxcard]; 
1994/1112/sys/src/9/pc/devastar.c:260,2651994/1113/sys/src/9/pc/devastar.c:279,302
1994/1111    
 
1994/1109    
static int astarsetup(Astar*); 
1994/1107    
 
1994/1113    
/* 
 *  Only 16k maps into ISA space 
 */ 
void 
setpage(Astar *a, ulong offset) 
{ 
	int i; 
 
	i = APAGE(offset); 
	if(i == a->page) 
		return; 
	outb(a->port+ISActl2, ISAmen|i); 
	a->page = i; 
} 
 
/* 
 *  generate the astar directory entries 
 */ 
1994/1111    
int 
1994/1112    
astargen(Chan *c, Dirtab *tab, int ntab, int i, Dir *db) 
1994/1111    
{ 
1994/1112/sys/src/9/pc/devastar.c:355,3601994/1113/sys/src/9/pc/devastar.c:392,398
1994/1107    
		if(a->irq == 0) 
			a->irq = 15; 
		a->id = i; 
1994/1113    
		a->page = -1; 
1994/1107    
 
		if(astarsetup(a) < 0){ 
			xfree(a); 
1994/1112/sys/src/9/pc/devastar.c:377,3841994/1113/sys/src/9/pc/devastar.c:415,422
1994/1107    
	if(port < 0) 
		return 0; 
 
	c = inb(port + ISAid); 
	c1 = inb(port + ISAid); 
1994/1113    
	c = inb(port+ISAid); 
	c1 = inb(port+ISAid); 
1994/1107    
	return (c == ISAid0 && c1 == ISAid1) 
1994/1112    
		|| (c == ISAid1 && c1 == ISAid0); 
1994/1107    
} 
1994/1112/sys/src/9/pc/devastar.c:407,4131994/1113/sys/src/9/pc/devastar.c:445,451
1994/1107    
	} 
 
	/* set memory address */ 
	outb(a->port + ISAmaddr, (a->mem>>12) & 0xfc); 
1994/1113    
	outb(a->port+ISAmaddr, (a->mem>>12) & 0xfc); 
1994/1112    
	a->gbc = (GCB*)(KZERO | a->mem); 
	a->addr = (char*)(KZERO | a->mem); 
1994/1107    
 
1994/1112/sys/src/9/pc/devastar.c:479,4961994/1113/sys/src/9/pc/devastar.c:517,534
1994/1112    
		qlock(a); 
		if(--a->opens == 0){ 
			/* take board out of download mode and enable IRQ */ 
			outb(a->port + ISActl1, ISAien|isairqcode[a->irq]); 
1994/1113    
			outb(a->port+ISActl1, ISAien|isairqcode[a->irq]); 
1994/1112    
 
			/* enable ISA access to first 16k */ 
			outb(a->port + ISActl2, ISAmen|0); 
1994/1113    
			outb(a->port+ISActl2, ISAmen|0); 
1994/1112    
 
			/* wait for program ready */ 
			for(i = 0; i < 21; i++){ 
				if(inb(a->port + ISActl1) & ISApr) 
1994/1113    
				if(inb(a->port+ISActl1) & ISApr) 
1994/1112    
					break; 
				tsleep(&r, return0, 0, 500); 
			} 
			if((inb(a->port + ISActl1) & ISApr) == 0) 
1994/1113    
			if((inb(a->port+ISActl1) & ISApr) == 0) 
1994/1112    
				print("astar%d program not ready\n", a->id); 
		} 
		qunlock(a); 
1994/1112/sys/src/9/pc/devastar.c:498,5101994/1113/sys/src/9/pc/devastar.c:536,595
1994/1112    
	} 
1994/1111    
} 
 
1994/1113    
static long 
memread(Astar *a, uchar *to, long n, ulong offset) 
{ 
	uchar *from, *e; 
	int i, rem; 
 
	if(offset+n > a->memsize){ 
		if(offset >= a->memsize) 
			return 0; 
		n = a->memsize - offset; 
	} 
 
	if(waserror()){ 
		qunlock(a); 
		nexterror(); 
	} 
	qlock(a); 
 
	for(rem = n; rem > 0; rem -= i){ 
 
		/* map in right piece of memory */ 
		setpage(a, offset); 
		i = offset&Pagemask; 
		to = a->addr + i; 
		i = Pagesize - i; 
		if(i > rem) 
			i = rem; 
		 
		/* byte at a time so endian doesn't matter */ 
		for(e = from + i; from < e;) 
			*to++ = *from++; 
	} 
 
	qunlock(a); 
	poperror(); 
	return n; 
} 
 
static long 
bctlread(Chan *c, void *buf, long n, ulong offset) 
{ 
	char s[128]; 
 
	sprint(s, "id %4.4ux ctl1 %2.2ux ctl2 %2.2ux maddr %2.2ux stat %4.4ux", 
		(inb(a->port+ISAid)<<8)|inb(a->port+ISAid), 
		inb(a->port+ISActl1), inb(a->port+ISActl2),  
		inb(a->port+ISAmaddr), 
		(inb(a->port+ISAstat2)<<8)|inb(a->port+ISAstat1)); 
	return readstr(offset, buf, n, s); 
} 
 
1994/1111    
long 
astarread(Chan *c, void *buf, long n, ulong offset) 
{ 
1994/1112    
	int i; 
1994/1111    
	Astar *a; 
1994/1112    
	char *to, *from, *e; 
	char status[128]; 
1994/1111    
 
	if(c->qid.path & CHDIR) 
		return devdirread(c, buf, n, 0, 0, astargen); 
1994/1112/sys/src/9/pc/devastar.c:511,6441994/1113/sys/src/9/pc/devastar.c:596,897
1994/1111    
 
	switch(TYPE(c->qid.path)){ 
	case Qmem: 
1994/1112    
		a = astar[BOARD(c->qid.path)]; 
		if(offset+n > Pramsize){ 
			if(offset >= Pramsize) 
				return 0; 
			n = Pramsize - offset; 
		} 
1994/1113    
		return memread(astar[BOARD(c->qid.path)], buf, n, offset); 
	case Qbctl: 
		return bctlread(astar[BOARD(c->qid.path)], buf, n, offset); 
	} 
1994/1112    
 
		if(waserror()){ 
			qunlock(a); 
			nexterror(); 
		} 
		qlock(a); 
		from = buf; 
		while(n > 0){ 
			/* map in right piece of memory */ 
			outb(a->port + ISActl2, ISAmen|(offset>>Footshift)); 
			i = offset%Footprint; 
			to = a->addr + i; 
			i = Footprint - i; 
			if(i > n) 
				i = n; 
			                 
			/* byte at a time so endian doesn't matter */ 
			for(e = from + i; from < e;) 
				*to++ = *from++; 
1994/1113    
	return 0; 
} 
1994/1112    
 
			n -= i; 
1994/1113    
static long 
memwrite(Astar *a, uchar *from, long n, ulong offset) 
{ 
	uchar *to, *e; 
	int i, rem; 
 
	if(offset+n > a->memsize){ 
		if(offset >= a->memsize) 
			return 0; 
		n = a->memsize - offset; 
	} 
 
	if(waserror()){ 
		qunlock(a); 
		nexterror(); 
	} 
	qlock(a); 
 
	for(rem = n; rem > 0; rem -= i){ 
 
		/* map in right piece of memory */ 
		setpage(a, offset); 
		i = offset&Pagemask; 
		from = a->addr + i; 
		i = Pagesize - i; 
		if(i > rem) 
			i = rem; 
		 
		/* byte at a time so endian doesn't matter */ 
		for(e = from + i; from < e;) 
			*to++ = *from++; 
	} 
 
	qunlock(a); 
	poperror(); 
	return n; 
} 
 
/* 
 *  setup a channel 
 */ 
static void 
chansetup(Astar *a, Astarchan *ac, void *ccb) 
{ 
	ac->a = a; 
	ac->ccb = ccb; 
	ac->iq = qopen(4*1024, 0, 0, 0); 
	ac->oq = qopen(4*1024, 0, astarkick, p); 
} 
 
/* 
 *  start control progarm 
 */ 
static void 
startcp(Astar *a) 
{ 
	int n, i, sz; 
	uchar *x; 
	CCB *ccb; 
 
	if(a->running) 
		error(Eio); 
 
	/* take board out of download mode and enable IRQ */ 
	outb(a->port+ISActl1, ISAien|isairqcode[a->irq]|ISAnotdl); 
	a->memsize = a->ramsize; 
 
	/* wait for control program to signal life */ 
	for(i = 0; i < 21; i++){ 
		if(inb(a->port+ISActl1) & ISApr) 
			break; 
		tsleep(&a->r, return0, 0, 500); 
	} 
	if((inb(a->port+ISActl1) & ISApr) == 0){ 
		print("astar%d program not ready\n", a->id); 
		error(Eio); 
	} 
 
	setpage(a, 0); 
	i = LEUS(a->gcb->type); 
	switch(i){ 
	default: 
		print("astar%d wrong board type %ux\n", a->id, i); 
		error(Eio); 
	case 0xc: 
		break; 
	} 
 
	/* check assumptions */ 
	n = LEUS(a->gcb->ccbn); 
	if(n != 8 && n != 16){ 
		print("astar%d had %d channels?\n", a->id, i); 
		error(Eio); 
	} 
	x = a->addr + LEUS(a->gcb->ccboff); 
	sz = LEUS(a->gcb->ccbsz); 
	if(x+n*sz > a->addr+Pagesize){ 
		print("astar%d ccb's not in 1st page\n", a->id); 
		error(Eio); 
	} 
	for(i = 0; i < n; i++){ 
		ccb = (CCB*)(x + i*sz); 
		if(APAGE(LEUS(ccb->inbase)) != APAGE(LEUS(ccb->inlim)) || 
		   APAGE(LEUS(ccb->outbase)) != APAGE(LEUS(ccb->outlim))){ 
			print("astar%d chan buffer spans pages\n", a->id); 
			error(Eio); 
1994/1112    
		} 
1994/1113    
	} 
 
	/* setup the channels */ 
	a->running = 1; 
	a->nchan = i; 
	a->c = xalloc(a->nchan * sizeof(Astarchan)); 
	for(i = 0; i < a->nchan; i++){ 
		chansetup(a, &a->c[i], (CCB*)x); 
		x += sz; 
	} 
} 
 
static long 
bctlwrite(Astar *a, char *msg) 
{ 
	int i; 
	uchar c; 
 
	if(waserror()){ 
1994/1112    
		qunlock(a); 
		poperror(); 
1994/1113    
		nexterror(); 
	} 
	qlock(a); 
 
	if(strncmp(cmsg, "download", 8) == 0){ 
		if(a->running) 
			error(Eio); 
 
		/* put board in download mode */ 
		c = inb(a->port+ISActl1); 
		outb(a->port+ISActl1, c & ~ISAnotdl); 
		a->memsize = Pramsize; 
 
		/* enable ISA access to first 16k */ 
		outb(a->port+ISActl2, ISAmen); 
 
	} else if(strncmp(cmsg, "run", 3) == 0){ 
		if(a->running) 
			error(Eio); 
		startcp(a); 
 
	} else 
		error(Ebadarg); 
 
	qunlock(a); 
	poperror(); 
	return n; 
} 
 
/* 
 *  change channel parameters 
 */ 
void 
astarctl(Astarchan *ac, char *cmd) 
{ 
	int i, n; 
	int command; 
 
	/* let output drain for a while */ 
	for(i = 0; i < 16 && qlen(ac->oq); i++) 
		tsleep(&ac->r, qlen, ac->oq, 125); 
 
	if(strncmp(cmd, "break", 5) == 0) 
		cmd = "k"; 
 
	command = 0; 
	n = atoi(cmd+1); 
	switch(*cmd){ 
	case 'B': 
	case 'b': 
		switch(n){ 
		case 76800: 
			ac->ccb->baud = LEUS(Cb76800); 
			break; 
		case 115200: 
			ac->ccb->baud = LEUS(Cb115200); 
			break; 
		default: 
			ac->ccb->baud = LEUS(n); 
			break; 
		} 
		command = Cconfall; 
1994/1112    
		break; 
	case Qbctl: 
		a = astar[BOARD(c->qid.path)]; 
		sprint(status, "id %2.2ux%2.2ux ctl1 %2.2ux ctl2 %2.2ux maddr %2.2ux stat %2.2ux%2.2ux", 
			inb(a->port+ISAid), inb(a->port+ISAid), 
			inb(a->port+ISActl1), inb(a->port+ISActl2),  
			inb(a->port+ISAmaddr), 
			inb(a->port+ISAstat2), inb(a->port+ISAstat1)); 
		n = readstr(offset, buf, n, status); 
1994/1113    
	case 'D': 
	case 'd': 
1994/1112    
		break; 
1994/1113    
	case 'f': 
	case 'F': 
		qflush(ac->oq); 
		break; 
	case 'H': 
	case 'h': 
		qhangup(ac->iq); 
		qhangup(ac->oq); 
		break; 
	case 'L': 
	case 'l': 
		n -= 5; 
		if(n < 0 || n > 3) 
			error(Ebadarg); 
		n |= LEUS(ac->ccb->format) & ~Clenmask; 
		ac->ccb->format = LEUS(n); 
		command = Cconfall; 
		break; 
	case 'm': 
	case 'M': 
		n = LEUS(ac->ccb->format) | Cobeycts; 
		ac->ccb->proto = LEUS(n); 
		command = Cconfall; 
		break; 
	case 'n': 
	case 'N': 
		qnoblock(p->oq, n); 
		break; 
	case 'P': 
	case 'p': 
		switch(*(cmd+1)){ 
		case 'e': 
			n = Cevenpar; 
			break; 
		case 'o': 
			n = Coddpar; 
			break; 
		default: 
			n = Cnopar; 
			break; 
		} 
		n |= LEUS(ac->ccb->format) & ~Cparmask; 
		ac->ccb->format = LEUS(n); 
		command = Cconfall; 
		break; 
	case 'K': 
	case 'k': 
		break; 
	case 'R': 
	case 'r': 
		break; 
	case 'Q': 
	case 'q': 
		qsetlimit(ac->iq, n); 
		qsetlimit(ac->oq, n); 
		break; 
	case 'X': 
	case 'x': 
		n = LEUS(ac->ccb->format) | Cobeyxon; 
		ac->ccb->proto = LEUS(n); 
		command = Cconfall; 
		break; 
1994/1111    
	} 
                 
	return 0; 
} 
 
1994/1113    
 
1994/1111    
long 
astarwrite(Chan *c, void *buf, long n, ulong offset) 
{ 
1994/1112    
	Astar *a; 
	char *to, *from, *e; 
	int i; 
1994/1113    
	Astarchan *ac; 
1994/1112    
	char cmsg[32]; 
1994/1111    
 
	if(c->qid.path & CHDIR) 
		error(Eperm); 
 
1994/1113    
	a = astar[BOARD(c->qid.path)]; 
1994/1111    
	switch(TYPE(c->qid.path)){ 
	case Qmem: 
1994/1112    
		a = astar[BOARD(c->qid.path)]; 
		if(offset+n > Pramsize){ 
			if(offset >= Pramsize) 
				return 0; 
			n = Pramsize - offset; 
		} 
                 
		if(waserror()){ 
			qunlock(a); 
			nexterror(); 
		} 
		qlock(a); 
		to = buf; 
		while(n > 0){ 
			/* map in right piece of memory */ 
			outb(a->port + ISActl2, ISAmen|(offset>>Footshift)); 
			i = offset%Footprint; 
			from = a->addr + i; 
			i = Footprint - i; 
			if(i > n) 
				i = n; 
			                 
			/* byte at a time so endian doesn't matter */ 
			for(e = from + i; from < e;) 
				*to++ = *from++; 
                 
			n -= i; 
		} 
		qunlock(a); 
		poperror(); 
		break; 
1994/1113    
		return memwrite(a, buf, n, offset); 
1994/1112    
	case Qbctl: 
		if(n > sizeof cmsg) 
			n = sizeof(cmsg) - 1; 
		memmove(cmsg, buf, n); 
		cmsg[n] = 0; 
                 
		if(waserror()){ 
			qunlock(a); 
			nexterror(); 
		} 
		qlock(a); 
		if(strncmp(cmsg, "download", 8) == 0){ 
			/* put board in download mode */ 
			outb(a->port + ISActl1, ISAdl); 
                 
			/* enable ISA access to first 16k */ 
			outb(a->port + ISActl2, ISAmen); 
                 
		} else if(strncmp(cmsg, "run", 3) == 0){ 
			/* take board out of download mode and enable IRQ */ 
			outb(a->port + ISActl1, ISAien|isairqcode[a->irq]); 
                 
			/* enable ISA access to first 16k */ 
			outb(a->port + ISActl2, ISAmen); 
                 
			/* wait for control program to signal life */ 
			for(i = 0; i < 21; i++){ 
				if(inb(a->port + ISActl1) & ISApr) 
					break; 
				tsleep(&a->r, return0, 0, 500); 
			} 
			if((inb(a->port + ISActl1) & ISApr) == 0) 
				print("astar%d program not ready\n", a->id); 
                 
		} else 
			error(Ebadarg); 
		qunlock(a); 
		poperror(); 
		break; 
1994/1113    
		return bctlwrite(a, cmsg); 
	case Qdata: 
		ac = a->c + CHAN(c->qid.path); 
		return qwrite(ac->oq, buf, n); 
	case Qctl: 
		if(n > sizeof cmsg) 
			n = sizeof(cmsg) - 1; 
		memmove(cmsg, buf, n); 
		cmsg[n] = 0; 
		return astarctl(a, msg); 
1994/1111    
	} 
1994/1109    
 
	return 0; 
1994/1112/sys/src/9/pc/devastar.c:664,6661994/1113/sys/src/9/pc/devastar.c:917,920
1994/1112    
	USED(c, dp); 
	error(Eperm); 
1994/1106    
} 
1994/1113    
 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)