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

1999/0819/pc/devastar.c (diff list | history)

pc/devastar.c on 1994/1106
1994/1106    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
#include	"../port/error.h" 
 
 
/* 
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. 
1998/0109    
 *  However, xchgw() 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    
 
enum 
{ 
	/* ISA control ports */ 
	ISAid=		0,		/* Id port and its values */ 
	 ISAid0=	 0xEC, 
	 ISAid1=	 0x13, 
1996/0807    
	 ISAid0x=	 0x69, 
	 ISAid1x=	 0x96, 
1994/1106    
	ISActl1=	1,		/* board control */ 
	 ISAien=	 1<<7,		/*  interrupt enable */ 
1994/1107    
	 ISAirq=	 7<<4,		/*  mask for irq code */ 
1994/1115    
	 ISAnotdl=	 1<<1,		/*  download bit (0 == download) */ 
1994/1106    
	 ISApr=		 1<<0,		/*  program ready */ 
	ISActl2=	2,		/* board control */ 
	 ISA186ien=	 1<<7,		/*  I186 irq enable bit state */ 
	 ISA186idata=	 1<<6,		/*  I186 irq data bit state */ 
1994/1107    
	 ISAmen=	 1<<4,		/*  enable memory to respond to ISA cycles */ 
1994/1121    
	 ISAmbank=	 0xf<<0,	/*  shift for 4 bit memory bank */ 
1994/1107    
	ISAmaddr=	3,		/* bits 14-19 of the boards mem address */ 
1994/1106    
	ISAstat1=	4,		/* board status (1 bit per channel) */ 
	ISAstat2=	5,		/* board status (1 bit per channel) */ 
1994/1107    
 
1994/1113    
	Pageshift=	14,		/* footprint of card mem in ISA space */ 
	Pagesize=	1<<Pageshift, 
	Pagemask=	Pagesize-1, 
1998/0109    
 
	PCIrange=	0x00, 
	PCIremap=	0x04, 
	PCIregion=	0x18, 
	PCImailbox=	0x40, 
	PCIdoorbell0=	0x60, 
	PCIdoorbell1=	0x64, 
	PCIcontrol=	0x68,		/* write */ 
	PCIstatus=	0x68,		/* read */ 
	PCIcommand=	0x6C, 
 
	Maxcard=	8, 
	Pramsize=	64*1024,	/* size of program ram */ 
1994/1106    
}; 
 
1994/1113    
#define APAGE(x) ((x)>>Pageshift) 
 
1994/1116    
#define LOCKPAGE(a, o) if((a)->needpage){ilock(&(a)->pagelock);setpage(a, o);} 
#define UNLOCKPAGE(a) if((a)->needpage)iunlock(&(a)->pagelock) 
 
1994/1107    
/* IRQ codes */ 
static int isairqcode[16] = 
{ 
	-1,	-1,	-1,	0<<4, 
	1<<4,	2<<4,	-1,	-1, 
	-1,	3<<4,	4<<4,	5<<4, 
	6<<4,	-1,	-1,	7<<4, 
}; 
 
1994/1106    
/* control program global control block */ 
typedef struct GCB GCB; 
struct GCB 
{ 
	ushort	cmd;		/* command word */ 
	ushort	status;		/* status word */ 
	ushort	serv;		/* service request, must be accessed via exchange 'X' */ 
	ushort	avail;		/* available buffer space */ 
	ushort	type;		/* board type */ 
	ushort	cpvers;		/* control program version */ 
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' */ 
	ushort	inserv;		/* input buffer service request 'X' */ 
	ushort	outserv;	/* output buffer service request 'X' */ 
	ushort	modemserv;	/* modem change service request 'X' */ 
	ushort	cmdserv;	/* channel command service request 'X' */ 
}; 
 
1994/1107    
enum 
{ 
	/* GCB.cmd commands/codes */ 
	Greadycmd=	0, 
	Gdiagcmd=	1, 
	Gresetcmd=	2, 
 
	/* GCB.status values */ 
	Gready=		0, 
	Gstopped=	1, 
	Gramerr=	2, 
	Gbadcmd=	3, 
	Gbusy=		4, 
 
	/* GCB.type values */ 
	Gx00m=		0x6, 
	G100e=		0xA, 
	Gx00i=		0xC, 
 
1994/1114    
	/* GCB.cmd2 bit */ 
	Gintack=	0x1, 
 
1994/1107    
	/* GCB.status2 bits */ 
	Ghas232=	(1<<0), 
	Ghas422=	(1<<1), 
	Ghasmodems=	(1<<2), 
	Ghasrj11s=	(1<<7), 
	Ghasring=	(1<<8), 
	Ghasdcd=	(1<<9), 
	Ghasdtr=	(1<<10), 
	Ghasdsr=	(1<<11), 
	Ghascts=	(1<<12), 
	Ghasrts=	(1<<13), 
}; 
 
1994/1106    
/* control program channel control block */ 
typedef struct CCB CCB; 
struct CCB 
{ 
	ushort	baud;		/* baud rate */ 
	ushort	format;		/* data format */ 
1994/1107    
	ushort	proto;		/* line protocol */ 
1994/1106    
	ushort	insize;		/* input buffer size */ 
	ushort	outsize;	/* output buffer size */ 
	ushort 	intrigger;	/* input buffer trigger rate */ 
	ushort	outlow;		/* output buffer low water mark */ 
1994/1107    
	char	xon[2];		/* xon characters */ 
1994/1106    
	ushort	inhigh;		/* input buffer high water mark */ 
	ushort	inlow;		/* input buffer low water mark */ 
	ushort	cmd;		/* channel command */ 
	ushort	status;		/* channel status */ 
	ushort	inbase;		/* input buffer start addr */ 
	ushort 	inlim;		/* input buffer ending addr */ 
	ushort	outbase;	/* output buffer start addr */ 
	ushort 	outlim;		/* output buffer ending addr */ 
	ushort	inwp;		/* input read and write pointers */ 
	ushort	inrp; 
	ushort	outwp;		/* output read and write pointers */ 
	ushort	outrp; 
	ushort	errstat;	/* error status */ 
	ushort	badp;		/* bad character pointer */ 
	ushort	mctl;		/* modem control */ 
	ushort	mstat;		/* modem status */ 
	ushort	bstat;		/* blocking status */ 
	ushort	rflag;		/* character received flag */ 
1994/1107    
	char	xoff[2];	/* xoff characters */ 
1994/1106    
	ushort	status2; 
1994/1107    
	char	strip[2];	/* strip/error characters */ 
1994/1106    
}; 
 
1994/1107    
enum 
{ 
	/* special baud rate codes for CCB.baud */ 
	Cb76800=	0xff00, 
	Cb115200=	0xff01, 
 
	/* CCB.format fields */ 
1994/1113    
	Clenmask=	3<<0,	/* data bits */ 
1994/1107    
	C1stop=		0<<2,	/* stop bits */ 
	C2stop=		1<<2, 
	Cnopar=		0<<3,	/* parity */ 
	Coddpar=	1<<3, 
	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 */ 
	Crloop=		3<<6,	/* remote loopback */ 
 
	/* CCB.proto fields */ 
	Cobeyxon=	1<<0,	/* obey received xoff/xon controls */ 
	Canyxon=	1<<1,	/* any rcvd character restarts xmit */ 
	Cgenxon=	1<<2,	/* generate xoff/xon controls */ 
	Cobeycts=	1<<3,	/* obey hardware flow ctl */ 
	Cgendtr=	1<<4,	/* dtr off when uart rcvr full */ 
	C½duplex=	1<<5,	/* rts off while xmitting */ 
	Cgenrts=	1<<6,	/* generate hardware flow ctl */ 
	Cmctl=		1<<7,	/* direct modem control via CCB.mctl */ 
	Cstrip=		1<<12,	/* to strip out characters */ 
	Ceia422=	1<<13,	/* to select eia 422 lines */ 
 
	/* CCB.cmd fields */ 
	Cconfall=	1<<0,	/* configure channel and UART */ 
	Cconfchan=	1<<1,	/* configure just channel */ 
	Cflushin=	1<<2,	/* flush input buffer */ 
	Cflushout=	1<<3,	/* flush output buffer */ 
	Crcvena=	1<<4,	/* enable receiver */ 
	Crcvdis=	1<<5,	/* disable receiver */ 
	Cxmtena=	1<<6,	/* enable transmitter */ 
	Cxmtdis=	1<<7,	/* disable transmitter */ 
	Cmreset=	1<<9,	/* reset modem */ 
 
	/* CCB.errstat fields */ 
	Coverrun=	1<<0, 
	Cparity=	1<<1, 
	Cframing=	1<<2, 
	Cbreak=		1<<3, 
 
	/* CCB.mctl fields */ 
	Cdtrctl=	1<<0, 
	Crtsctl=	1<<1, 
1994/1112    
	Cbreakctl=	1<<4, 
1994/1107    
 
	/* CCB.mstat fields */ 
	Cctsstat=	1<<0, 
	Cdsrstat=	1<<1, 
	Cristat=	1<<2, 
	Cdcdstat=	1<<3, 
 
	/* CCB.bstat fields */ 
	Cbrcvoff=	1<<0, 
	Cbxmtoff=	1<<1, 
	Clbxoff=	1<<2,	/* transmitter blocked by XOFF */ 
	Clbcts=		1<<3,	/* transmitter blocked by CTS */ 
	Crbxoff=	1<<4,	/* remote blocked by xoff */ 
	Crbrts=		1<<4,	/* remote blocked by rts */ 
}; 
 
1994/1106    
/* host per controller info */ 
struct Astar 
{ 
1994/1114    
	QLock;				/* lock for rendez */ 
	Rendez		r;		/* waiting for command completion */ 
1994/1112    
 
1994/1107    
	ISAConf; 
1998/0109    
	Pcidev*		pci; 
1994/1114    
	Lock		pagelock;	/* lock for setting page */ 
	int		page;		/* page currently mapped */ 
1994/1107    
	int		id;		/* from plan9.ini */ 
1994/1111    
	int		nchan;		/* number of channels */ 
	Astarchan	*c;		/* channels */ 
1994/1107    
	int		ramsize;	/* 16k or 256k */ 
1994/1113    
	int		memsize;	/* size of memory currently mapped */ 
1994/1116    
	int		needpage; 
1998/0109    
	int		pagebase;	/* pci */ 
1994/1115    
	GCB		*gcb;		/* global board comm area */ 
1994/1113    
	uchar		*addr;		/* base of memory area */ 
	int		running; 
1994/1106    
}; 
 
/* host per channel info */ 
struct Astarchan 
{ 
1994/1121    
	QLock;			/* lock for rendez */ 
	Rendez	r;		/* waiting for command completion */ 
1994/1106    
 
1994/1121    
	Astar	*a;		/* controller */ 
	CCB	*ccb;		/* channel control block */ 
1994/1111    
	int	perm; 
1994/1112    
	int	opens; 
1994/1121    
	int	baud;		/* baud rate */ 
	int	framing;	/* framing errors */ 
	int	overrun;	/* overruns */ 
1999/0315    
	int	hup_dsr;	/* hangup when dsr goes away */ 
	int	hup_dcd;	/* hangup when dcd goes away */ 
1994/1121    
	int	dtr;		/* non-zero means dtr on */ 
1994/1122    
	int	rts;		/* non-zero means rts on */ 
1999/0315    
	int	dsr;		/* non-zero means dsr on */ 
	int	dcd;		/* non-zero means dcd on */ 
1994/1107    
 
1994/1106    
	Queue	*iq; 
	Queue	*oq; 
}; 
 
1994/1109    
Astar *astar[Maxcard]; 
1994/1111    
static int nastar; 
1994/1107    
 
1994/1111    
enum 
{ 
1997/0710    
	Qmem= 1, 
1994/1112    
	Qbctl, 
1994/1111    
	Qdata, 
	Qctl, 
	Qstat, 
}; 
#define TYPE(x)		((x)&0xff) 
1994/1122    
#define BOARD(x)	(((x)>>16)&0xff) 
#define CHAN(x)		(((x)>>8)&0xff) 
1994/1111    
#define QID(b,c,t)	(((b)<<16)|((c)<<8)|(t)) 
 
1994/1114    
static int	astarsetup(Astar*); 
static void	astarintr(Ureg*, void*); 
1999/0629    
static void	astarkick(void*); 
static void	astarkickin(void*); 
1994/1114    
static void	enable(Astarchan*); 
static void	disable(Astarchan*); 
1994/1115    
static void	astarctl(Astarchan*, char*); 
1994/1107    
 
1994/1113    
/* 
 *  Only 16k maps into ISA space 
 */ 
1994/1114    
static void 
1994/1113    
setpage(Astar *a, ulong offset) 
{ 
1994/1121    
	int i; 
1994/1113    
 
1998/0109    
	if(a->pci){ 
1999/0501    
		print("#G%d: setpage caller pc %luX\n", a->id, getcallerpc(&a)); 
1998/0109    
		return; 
	} 
 
1994/1113    
	i = APAGE(offset); 
	if(i == a->page) 
		return; 
1994/1120    
 
1994/1121    
	outb(a->port+ISActl2, ISAmen|i); 
1994/1113    
	a->page = i; 
} 
 
/* 
 *  generate the astar directory entries 
 */ 
1997/0327    
static int 
1998/0319    
astargen(Chan *c, Dirtab *, int , int i, Dir *db) 
1994/1111    
{ 
	int dev, sofar, ch, t; 
1994/1112    
	extern ulong kerndate; 
1994/1111    
 
1994/1115    
	memset(db, 0, sizeof(Dir)); 
 
1994/1111    
	sofar = 0; 
 
1994/1112    
	for(dev = 0; dev < nastar; dev++){ 
1994/1111    
		if(sofar == i){ 
1994/1115    
			sprint(db->name, "astar%dmem", astar[dev]->id); 
1994/1112    
			db->qid.path = QID(dev, 0, Qmem); 
1994/1111    
			db->mode = 0660; 
1998/0414    
			db->length = astar[dev]->memsize; 
1994/1111    
			break; 
		} 
1994/1112    
		sofar++; 
1994/1111    
 
1994/1112    
		if(sofar == i){ 
1994/1115    
			sprint(db->name, "astar%dctl", astar[dev]->id); 
1994/1112    
			db->qid.path = QID(dev, 0, Qbctl); 
			db->mode = 0660; 
			break; 
		} 
		sofar++; 
 
		if(i - sofar < 3*astar[dev]->nchan){ 
1994/1111    
			i -= sofar; 
			ch = i/3; 
			t = i%3; 
			switch(t){ 
			case 0: 
1994/1121    
				sprint(db->name, "eia%d%2.2d", astar[dev]->id, ch); 
1994/1111    
				db->mode = astar[dev]->c[ch].perm; 
1994/1115    
				db->qid.path = QID(dev, ch, Qdata); 
1999/0801    
				db->length = qlen(astar[dev]->c[ch].iq); 
1994/1111    
				break; 
			case 1: 
1994/1121    
				sprint(db->name, "eia%d%2.2dctl", astar[dev]->id, ch); 
1994/1111    
				db->mode = astar[dev]->c[ch].perm; 
1994/1115    
				db->qid.path = QID(dev, ch, Qctl); 
1994/1111    
				break; 
			case 2: 
1994/1121    
				sprint(db->name, "eia%d%2.2dstat", astar[dev]->id, ch); 
1994/1111    
				db->mode = 0444; 
1994/1115    
				db->qid.path = QID(dev, ch, Qstat); 
1994/1111    
				break; 
1994/1112    
			} 
1994/1111    
			break; 
		} 
1994/1112    
		sofar += 3*astar[dev]->nchan; 
1994/1111    
	} 
 
1994/1112    
	if(dev == nastar) 
1994/1111    
		return -1; 
 
1994/1115    
	db->qid.vers = 0; 
1994/1111    
	db->atime = seconds(); 
	db->mtime = kerndate; 
	memmove(db->uid, eve, NAMELEN); 
	memmove(db->gid, eve, NAMELEN); 
1997/0408    
	db->type = devtab[c->type]->dc; 
1994/1111    
	db->dev = c->dev; 
	if(c->flag&CMSG) 
		db->mode |= CHMOUNT; 
 
	return 1; 
} 
 
1997/0327    
static void 
1994/1107    
astarreset(void) 
1994/1106    
{ 
1998/0109    
	int i, x; 
1994/1107    
	Astar *a; 
1998/0109    
	Pcidev *p; 
1999/0714    
	char name[8]; 
1994/1106    
 
1998/0109    
	p = nil; 
1994/1106    
	for(i = 0; i < Maxcard; i++){ 
1994/1109    
		a = astar[nastar] = xalloc(sizeof(Astar)); 
1994/1112    
		if(isaconfig("serial", i, a) == 0){ 
1994/1107    
			xfree(a); 
1994/1109    
			astar[nastar] = 0; 
1994/1118    
			continue; 
1994/1106    
		} 
 
1998/0109    
		a->ramsize = 0; 
1994/1120    
		/* check all possible names */ 
1998/0109    
		if(cistrcmp(a->type, "a100i") == 0 || cistrcmp(a->type,"A100I") == 0) 
1994/1107    
			a->ramsize = 16*1024; 
1998/0109    
 		else if(cistrcmp(a->type, "a200i") == 0 || 
		      cistrcmp(a->type,"A200I") == 0 || 
		      cistrcmp(a->type, "a16i") == 0) 
1994/1107    
			a->ramsize = 256*1024; 
1998/0109    
		else if(cistrcmp(a->type, "AvanstarXp") == 0){ 
			if(p = pcimatch(p, 0x114F, 0x6001)){ 
				a->pci = p; 
				/* 
				 * It's really 128KB, but split into 
				 * two 64KB chunks. 
				 */ 
				a->ramsize = 64*1024; 
			} 
		} 
 
		if(a->ramsize == 0){ 
1994/1118    
			xfree(a); 
			astar[nastar] = 0; 
1994/1107    
			continue; 
1994/1118    
		} 
1994/1108    
 
1994/1107    
		a->id = i; 
1998/0109    
		if(a->pci){ 
			a->irq = p->intl; 
			a->port = p->mem[1].bar & ~0x03; 
			a->mem = upamalloc(p->mem[2].bar & ~0x0F, p->mem[2].size, 0); 
			a->addr = (uchar*)a->mem; 
			a->gcb = (GCB*)(a->mem+0x10000); 
1994/1107    
 
1999/0714    
			sprint(name, "astar%d", i); 
1999/0721    
			if(ioalloc(a->port, p->mem[1].size, 0, name) < 0){ 
				print("#G%d: port 0x%lux in use\n", a->id, a->port); 
1999/0714    
				xfree(a); 
				astar[nastar] = 0; 
				continue; 
			} 
 
1998/0109    
			/* 
			 * Toggle the software reset and wait for 
			 * the adapter local init status to indicate done. 
			 */ 
			outl(a->port+PCIremap, 0xA0000001); 
			x = inl(a->port+PCIcommand); 
			outl(a->port+PCIcommand, 0x40000000|x); 
			microdelay(1); 
			outl(a->port+PCIcommand, x); 
			delay(100); 
			for(x = 0; x < 10000; x++){ 
				 if(inl(a->port+PCIcommand) & 0x80000000) 
					break; 
			} 
			if(!(inl(a->port+PCIcommand) & 0x80000000)) 
1998/0813    
				print("#G%d: didn't reset\n", a->id); 
1994/1210    
 
1998/0109    
			/* 
			 * So the memory can be read before any other 
			 * initialisation takes place. 
			 */ 
			a->memsize = a->ramsize; 
1994/1107    
		} 
1998/0109    
		else{ 
			/* defaults */ 
			if(a->irq == 0) 
				a->irq = 15; 
	 
			a->mem = umbmalloc(a->mem, Pagesize, Pagesize); 
			if(a->mem == 0) 
				panic("astarreset: %lux", a->mem); 
			a->mem = PADDR(a->mem); 
	 
			if(astarsetup(a) < 0){ 
				xfree(a); 
				astar[nastar] = 0; 
				continue; 
			} 
			print("\tctl1 %ux ctl2 %ux maddr %ux stat1 %ux stat2 %ux\n", 
				inb(a->port+ISActl1), inb(a->port+ISActl2), inb(a->port+ISAmaddr), 
				inb(a->port+ISAstat1), inb(a->port+ISAstat2)); 
		} 
 
1998/0825    
		print("#G%d: %s port 0x%luX addr 0x%luX irq %lud\n", 
1998/0109    
			a->id, a->type, a->port, a->addr, a->irq); 
1994/1109    
		nastar++; 
1994/1107    
	} 
} 
 
1994/1109    
/* isa ports an ax00i can appear at */ 
1997/0327    
static int isaport[] = { 0x200, 0x208, 0x300, 0x308, 0x600, 0x608, 0x700, 0x708, 0 }; 
1994/1107    
 
1994/1109    
static int 
astarprobe(int port) 
1994/1107    
{ 
	uchar c, c1; 
 
	if(port < 0) 
		return 0; 
 
1994/1113    
	c = inb(port+ISAid); 
	c1 = inb(port+ISAid); 
1994/1107    
	return (c == ISAid0 && c1 == ISAid1) 
1996/0807    
		|| (c == ISAid1 && c1 == ISAid0) 
		|| (c == ISAid0x && c1 == ISAid1x) 
		|| (c == ISAid1x && c1 == ISAid0x); 
1994/1107    
} 
 
1994/1109    
static int 
1994/1107    
astarsetup(Astar *a) 
{ 
1994/1121    
	int i, found; 
1999/0714    
	char name[8]; 
1994/1107    
 
	/* see if the card exists */ 
	found = 0; 
	if(a->port == 0) 
		for(i = 0; isaport[i]; i++){ 
			a->port = isaport[i]; 
1999/0714    
			sprint(name, "astar%d", a->id); 
			if(ioalloc(a->port, 6, 0, name) < 0) 
				continue; 
1994/1109    
			found = astarprobe(isaport[i]); 
1994/1107    
			if(found){ 
				isaport[i] = -1; 
				break; 
			} 
		} 
1999/0714    
	else { 
		sprint(name, "astar%d", a->id); 
		if(ioalloc(a->port, 6, 0, name) < 0){ 
			print("#G%d: port 0x%lux in use\n", a->id, a->port); 
			return -1; 
		} 
1994/1112    
		found = astarprobe(a->port); 
1999/0714    
	} 
1994/1107    
	if(!found){ 
1998/0109    
		print("#G%d: not found\n", a->id); 
1999/0714    
		iofree(a->port); 
1994/1107    
		return -1; 
	} 
 
1994/1120    
	/* check interrupt level */ 
1994/1112    
	if(isairqcode[a->irq] == -1){ 
1998/0825    
		print("#G%d: bad irq %lud\n", a->id, a->irq); 
1999/0714    
		iofree(a->port); 
1994/1107    
		return -1; 
	} 
1994/1111    
 
1994/1120    
	/* set ISA memory address */ 
	outb(a->port+ISAmaddr, (a->mem>>12) & 0xfc); 
1998/0109    
	a->gcb = KADDR(a->mem); 
	a->addr = KADDR(a->mem); 
1994/1120    
 
	/* disable ISA memory response */ 
1994/1121    
	outb(a->port+ISActl2, 0); 
1994/1120    
	a->memsize = 0; 
	a->page = -1; 
 
1994/1121    
	/* reset processor */ 
	outb(a->port+ISActl1, 0); 
 
1994/1111    
	return 0; 
} 
 
1997/0327    
static Chan* 
1994/1111    
astarattach(char *spec) 
{ 
1998/0414    
	ulong ctlrno; 
	char *p; 
 
	ctlrno = 0; 
	if(spec && *spec){ 
		ctlrno = strtoul(spec, &p, 0); 
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= Maxcard)) 
			error(Ebadarg); 
	} 
	if(astar[ctlrno] == nil) 
		error(Enodev); 
 
1994/1115    
	return devattach('G', spec); 
1994/1111    
} 
 
1997/0327    
static int 
1994/1111    
astarwalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, 0, 0, astargen); 
} 
 
1997/0327    
static void 
1994/1111    
astarstat(Chan *c, char *dp) 
{ 
	devstat(c, dp, 0, 0, astargen); 
} 
 
1997/0327    
static Chan* 
1994/1111    
astaropen(Chan *c, int omode) 
{ 
1994/1112    
	Astar *a; 
1994/1115    
	Astarchan *ac; 
1994/1111    
 
	c = devopen(c, omode, 0, 0, astargen); 
1994/1115    
	a = astar[BOARD(c->qid.path)]; 
1994/1111    
 
1994/1112    
	switch(TYPE(c->qid.path)){ 
	case Qmem: 
	case Qbctl: 
		if(!iseve()) 
			error(Eperm); 
		break; 
1994/1114    
	case Qdata: 
	case Qctl: 
1994/1115    
		ac = a->c + CHAN(c->qid.path); 
1994/1114    
		qlock(ac); 
		if(waserror()){ 
1994/1115    
			qunlock(ac); 
1995/0207    
			ac->opens--; 
1994/1114    
			nexterror(); 
		} 
1994/1116    
		if(ac->opens++ == 0){ 
1994/1114    
			enable(ac); 
1994/1116    
			qreopen(ac->iq); 
			qreopen(ac->oq); 
		} 
1994/1114    
		qunlock(ac); 
		poperror(); 
		break; 
1994/1112    
	} 
 
1994/1111    
	return c; 
} 
 
1997/0327    
static void 
1994/1111    
astarclose(Chan *c) 
{ 
1994/1112    
	Astar *a; 
1994/1115    
	Astarchan *ac; 
1994/1112    
 
1997/0710    
	if((c->flag & COPEN) == 0) 
		return; 
 
1994/1115    
	a = astar[BOARD(c->qid.path)]; 
 
1994/1112    
	switch(TYPE(c->qid.path)){ 
1994/1114    
	case Qdata: 
	case Qctl: 
1994/1115    
		ac = a->c + CHAN(c->qid.path); 
1994/1114    
		qlock(ac); 
		if(waserror()){ 
1994/1115    
			qunlock(ac); 
1994/1114    
			nexterror(); 
1994/1112    
		} 
1994/1122    
		if(--(ac->opens) == 0){ 
1994/1114    
			disable(ac); 
1994/1115    
			qclose(ac->iq); 
			qclose(ac->oq); 
		} 
1994/1114    
		qunlock(ac); 
		poperror(); 
1994/1112    
		break; 
	} 
1994/1111    
} 
 
1994/1114    
/* 
1998/0109    
 *  read PCI mapped memory 
 */ 
static long 
pcimemread(Astar *a, uchar *to, long n, ulong offset) 
{ 
	uchar *from; 
	int rem; 
 
	if(offset+n > a->memsize){ 
		if(offset >= a->memsize) 
			return 0; 
		n = a->memsize - offset; 
	} 
 
	from = a->addr+offset; 
	for(rem = n; rem > 0; rem--) 
		*to++ = *from++; 
 
	return n; 
} 
 
/* 
1994/1114    
 *  read ISA mapped memory 
 */ 
1994/1113    
static long 
1998/0109    
isamemread(Astar *a, uchar *to, long n, ulong offset) 
1994/1113    
{ 
1994/1114    
	uchar *from, *e, *tp; 
1994/1113    
	int i, rem; 
1994/1114    
	uchar tmp[256]; 
1994/1113    
 
	if(offset+n > a->memsize){ 
		if(offset >= a->memsize) 
			return 0; 
		n = a->memsize - offset; 
	} 
 
	for(rem = n; rem > 0; rem -= i){ 
 
		/* map in right piece of memory */ 
		i = offset&Pagemask; 
1994/1114    
		from = a->addr + i; 
1994/1113    
		i = Pagesize - i; 
		if(i > rem) 
			i = rem; 
1994/1115    
		if(i > sizeof(tmp)) 
			i = sizeof(tmp); 
1994/1114    
 
		/* 
		 *  byte at a time so endian doesn't matter, 
		 *  go via tmp to avoid pagefaults while ilock'd 
		 */ 
		tp = tmp; 
1994/1116    
		LOCKPAGE(a, offset); 
1994/1115    
		for(e = tp + i; tp < e;) 
1994/1114    
			*tp++ = *from++; 
1994/1116    
		UNLOCKPAGE(a); 
1994/1114    
		memmove(to, tmp, i); 
		to += i; 
1994/1115    
 
		offset += i; 
1994/1113    
	} 
 
	return n; 
} 
 
1994/1114    
/* 
 *  read ISA status 
 */ 
1994/1113    
static long 
1994/1115    
bctlread(Astar *a, void *buf, long n, ulong offset) 
1994/1113    
{ 
	char s[128]; 
 
1998/0109    
	if(a->pci) 
1998/0825    
		sprint(s, "range %luX remap %luX region %luX mailbox %luX doorbell0 %luX doorbell1 %luX control %luX command %luX", 
1998/0109    
			inl(a->port+PCIrange), 
			inl(a->port+PCIremap), 
			inl(a->port+PCIregion), 
			inl(a->port+PCImailbox), 
			inl(a->port+PCIdoorbell0), 
			inl(a->port+PCIdoorbell1), 
			inl(a->port+PCIcontrol), 
			inl(a->port+PCIcommand)); 
	else 
		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)); 
 
1994/1113    
	return readstr(offset, buf, n, s); 
} 
 
1994/1121    
static long 
statread(Astarchan *ac, void *buf, long n, ulong offset) 
{ 
1999/0315    
	char s[256]; 
	int mstat, bstat, fstat; 
1994/1121    
 
	LOCKPAGE(ac->a, 0); 
	mstat = LEUS(ac->ccb->mstat); 
	bstat = LEUS(ac->ccb->bstat); 
1999/0315    
	fstat = LEUS(ac->ccb->format); 
1994/1121    
	UNLOCKPAGE(ac->a); 
 
1999/0315    
	snprint(s, sizeof s, 
		"b%d c%d d%d e%d l%d m%d p%c r%d s%d\n" 
		"%ld %d %d%s%s%s%s\n", 
1994/1121    
 
1999/0315    
		ac->baud, 
		ac->hup_dcd, 
		ac->dtr, 
		ac->hup_dsr, 
		(fstat & Clenmask), 
		0, 	/* change in modem status? */ 
		(fstat & Cparmask) ? ((fstat & Cevenpar) == Cevenpar ? 'e' : 'o') : 'n', 
		(bstat & Crbrts) ? 1 : 0, 
		(fstat & C2stop) ? 2 : 1, 
 
		ac - ac->a->c, 
		ac->framing, 
		ac->overrun, 
		(mstat & Cctsstat)    ? " cts"  : "", 
		(mstat & Cdsrstat)    ? " dsr"  : "", 
		(mstat & Cdcdstat)    ? " dcd"  : "", 
		(mstat & Cristat)   ? " ring" : "" 
	); 
1994/1121    
	return readstr(offset, buf, n, s); 
} 
 
1997/0327    
static long 
1998/0319    
astarread(Chan *c, void *buf, long n, vlong off) 
1994/1111    
{ 
1994/1115    
	Astar *a; 
	Astarchan *ac; 
1998/0319    
	ulong offset = off; 
1994/1111    
 
	if(c->qid.path & CHDIR) 
		return devdirread(c, buf, n, 0, 0, astargen); 
 
	switch(TYPE(c->qid.path)){ 
1994/1121    
	case Qstat: 
		a = astar[BOARD(c->qid.path)]; 
		return statread(a->c + CHAN(c->qid.path), buf, n, offset); 
1994/1111    
	case Qmem: 
1998/0109    
		a = astar[BOARD(c->qid.path)]; 
		if(a->pci) 
			return pcimemread(a, buf, n, offset); 
		return isamemread(a, buf, n, offset); 
1994/1113    
	case Qbctl: 
		return bctlread(astar[BOARD(c->qid.path)], buf, n, offset); 
1994/1115    
	case Qdata: 
		a = astar[BOARD(c->qid.path)]; 
		ac = a->c + CHAN(c->qid.path); 
1994/1116    
		return qread(ac->iq, buf, n); 
1994/1113    
	} 
1994/1112    
 
1994/1113    
	return 0; 
} 
1994/1112    
 
1994/1114    
/* 
1998/0109    
 *  write PCI mapped memory 
 */ 
static long 
pcimemwrite(Astar *a, uchar *from, long n, ulong offset) 
{ 
	uchar *to; 
	int rem; 
	ulong limit; 
 
	/* 
	 * Disallow writes above 0xD000 where the i960 
	 * data structures live if writing in the lower bank. 
	 */ 
	if(a->addr == (uchar*)a->mem) 
		limit = 0xD000; 
	else 
		limit = a->memsize; 
	if(offset+n > limit){ 
		if(offset >= limit) 
			return 0; 
		n = limit - offset; 
	} 
 
	to = a->addr+offset; 
	for(rem = n; rem > 0; rem--) 
		*to++ = *from++; 
 
	return n; 
} 
 
/* 
1994/1114    
 *  write ISA mapped memory 
 */ 
1994/1113    
static long 
1998/0109    
isamemwrite(Astar *a, uchar *from, long n, ulong offset) 
1994/1113    
{ 
1994/1114    
	uchar *to, *e, *tp; 
1994/1113    
	int i, rem; 
1994/1114    
	uchar tmp[256]; 
1994/1113    
 
	if(offset+n > a->memsize){ 
		if(offset >= a->memsize) 
			return 0; 
		n = a->memsize - offset; 
	} 
 
	for(rem = n; rem > 0; rem -= i){ 
 
		/* map in right piece of memory */ 
		i = offset&Pagemask; 
1994/1114    
		to = a->addr + i; 
1994/1113    
		i = Pagesize - i; 
		if(i > rem) 
			i = rem; 
1994/1115    
		if(i > sizeof(tmp)) 
			i = sizeof(tmp); 
1994/1113    
		 
1994/1114    
		/* 
		 *  byte at a time so endian doesn't matter, 
		 *  go via tmp to avoid pagefaults while ilock'd 
		 */ 
		memmove(tmp, from, i); 
		tp = tmp; 
1994/1116    
		LOCKPAGE(a, offset); 
1994/1115    
		for(e = tp + i; tp < e;) 
1994/1114    
			*to++ = *tp++; 
1994/1116    
		UNLOCKPAGE(a); 
1994/1114    
		from += i; 
1994/1115    
 
		offset += i; 
1994/1113    
	} 
 
	return n; 
} 
 
/* 
1996/0808    
 *  put board into download mode 
 */ 
static void 
downloadmode(Astar *a) 
{ 
	int c, i; 
 
	/* put board in download mode */ 
1998/0109    
	if(a->pci){ 
		/* 
		 * Don't let the download write over the 
		 * i960 data structures. 
		 */ 
		a->memsize = 0xD000; 
		a->addr = (uchar*)a->mem; 
1996/0808    
	} 
1998/0109    
	else{ 
		a->memsize = Pramsize; 
		a->needpage = 1; 
		c = inb(a->port+ISActl1); 
		outb(a->port+ISActl1, c & ~ISAnotdl); 
1996/0808    
 
1998/0109    
		/* give it up to 5 seconds to reset */ 
		for(i = 0; i < 21; i++){ 
			if(!(inb(a->port+ISActl1) & ISAnotdl)) 
				break; 
			tsleep(&a->r, return0, 0, 500); 
		} 
		if(inb(a->port+ISActl1) & ISAnotdl){ 
			print("#G%d: did not reset\n", a->id); 
			error(Eio); 
		} 
 
		/* enable ISA access to first 16k */ 
		a->page = -1; 
		setpage(a, 0); 
	} 
1996/0808    
} 
 
/* 
1995/0505    
 *  start control program 
1994/1113    
 */ 
static void 
startcp(Astar *a) 
{ 
1994/1120    
	int c, n, i, sz; 
1994/1113    
	uchar *x; 
	CCB *ccb; 
1994/1114    
	Astarchan *ac; 
1999/0819    
	char name[10]; 
1994/1113    
 
	if(a->running) 
		error(Eio); 
 
	/* take board out of download mode and enable IRQ */ 
1998/0109    
	if(a->pci){ 
		outl(a->port+PCImailbox, 1); 
 
		/* wait for control program to signal life */ 
		delay(100); 
		for(i = 0; i < 10; i++){ 
			if(inl(a->port+PCImailbox) & 0x80000000) 
				break; 
			tsleep(&a->r, return0, 0, 100); 
		} 
		if(!(inl(a->port+PCImailbox) & 0x80000000)){ 
			print("#G%d: program not ready\n", a->id); 
			//error(Eio); 
		} 
 
		a->addr = (uchar*)(a->mem+0x10000); 
	} 
	else{ 
		c = inb(a->port+ISActl1); 
		outb(a->port+ISActl1, c|ISAien|ISAnotdl); 
 
		/* 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("#G%d: program not ready\n", a->id); 
			error(Eio); 
		} 
	} 
 
1994/1113    
	a->memsize = a->ramsize; 
1998/0109    
	if(a->pci || a->memsize <= Pagesize) 
1994/1116    
		a->needpage = 0; 
1998/0109    
	else{ 
		a->page = -1; 
		setpage(a, 0); 
1994/1116    
		a->needpage = 1; 
1994/1113    
	} 
 
1994/1114    
	if(waserror()){ 
1994/1116    
		UNLOCKPAGE(a); 
1994/1114    
		poperror(); 
	} 
1994/1119    
 
1994/1116    
	LOCKPAGE(a, 0); 
1994/1113    
	i = LEUS(a->gcb->type); 
	switch(i){ 
	default: 
1998/0109    
		print("#G%d: wrong board type %uX\n", a->id, i); 
1994/1113    
		error(Eio); 
1998/0109    
	case 0x0C: 
	case 0x12:					/* AvanstarXp */ 
1994/1113    
		break; 
	} 
 
	/* check assumptions */ 
	n = LEUS(a->gcb->ccbn); 
	if(n != 8 && n != 16){ 
1998/0109    
		print("#G%d: has %d channels?\n", a->id, i); 
1994/1113    
		error(Eio); 
	} 
	x = a->addr + LEUS(a->gcb->ccboff); 
	sz = LEUS(a->gcb->ccbsz); 
	if(x+n*sz > a->addr+Pagesize){ 
1998/0109    
		print("#G%d: ccb's not in 1st page\n", a->id); 
1994/1113    
		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))){ 
1998/0109    
			print("#G%d: chan buffer spans pages\n", a->id); 
1994/1113    
			error(Eio); 
1994/1112    
		} 
1994/1113    
	} 
1994/1116    
 
	UNLOCKPAGE(a); 
1994/1114    
	poperror(); 
1994/1113    
 
	/* setup the channels */ 
	a->running = 1; 
	a->nchan = i; 
1994/1121    
	a->c = smalloc(a->nchan * sizeof(Astarchan)); 
1994/1113    
	for(i = 0; i < a->nchan; i++){ 
1994/1114    
		ac = &a->c[i]; 
		ac->a = a; 
		ac->ccb = (CCB*)x; 
1994/1122    
		ac->baud = 9600;	/* a100i default */ 
1994/1115    
		ac->perm = 0660; 
1994/1116    
		ac->iq = qopen(4*1024, 0, astarkickin, ac); 
1994/1114    
		ac->oq = qopen(4*1024, 0, astarkick, ac); 
1994/1113    
		x += sz; 
	} 
1994/1121    
 
1999/0819    
	snprint(name, sizeof name, "astar%d", a->id); 
1994/1121    
	/* set up interrupt level, enable interrupts */ 
1998/0109    
	if(a->pci){ 
		/* 
		 * Which bits in the interrupt control register should be set? 
		 */ 
		outl(a->port+PCIcontrol, 0x00031F00); 
1999/0819    
		intrenable(a->irq, astarintr, a, a->pci->tbdf, name); 
1998/0109    
	} 
	else{ 
		c = inb(a->port+ISActl1); 
		c &= ~ISAirq; 
		c |= ISAien|isairqcode[a->irq]; 
		outb(a->port+ISActl1, c); 
1999/0819    
		intrenable(a->irq, astarintr, a, BUSUNKNOWN, name); 
1998/0109    
	} 
1994/1121    
 
	/* enable control program interrupt generation */ 
	LOCKPAGE(a, 0); 
	a->gcb->cmd2 = LEUS(Gintack); 
	UNLOCKPAGE(a); 
1994/1113    
} 
 
1994/1115    
static void 
bctlwrite(Astar *a, char *cmsg) 
1994/1113    
{ 
	if(waserror()){ 
1994/1112    
		qunlock(a); 
1994/1113    
		nexterror(); 
	} 
	qlock(a); 
 
1994/1115    
	if(a->running) 
		error(Eio); 
1994/1113    
 
1994/1115    
	if(strncmp(cmsg, "download", 8) == 0){ 
1994/1113    
		/* put board in download mode */ 
1996/0808    
		downloadmode(a); 
1994/1113    
 
	} else if(strncmp(cmsg, "run", 3) == 0){ 
1994/1115    
		/* start up downloaded program */ 
1994/1113    
		startcp(a); 
 
	} else 
		error(Ebadarg); 
 
	qunlock(a); 
	poperror(); 
} 
 
/* 
1994/1114    
 *  Send a command to a channel 
 *  (must be called with ac qlocked) 
 */ 
static int 
chancmddone(void *arg) 
{ 
1994/1115    
	Astarchan *ac = arg; 
1994/1114    
	int x; 
 
1994/1116    
	LOCKPAGE(ac->a, 0); 
1994/1115    
	x = ac->ccb->cmd; 
1994/1116    
	UNLOCKPAGE(ac->a); 
1994/1114    
 
1994/1115    
	return !x; 
1994/1114    
} 
static void 
chancmd(Astarchan *ac, int cmd) 
{ 
	CCB *ccb; 
1994/1115    
	int status; 
1994/1114    
 
	ccb = ac->ccb; 
 
1994/1116    
	LOCKPAGE(ac->a, 0); 
1994/1114    
	ccb->cmd = cmd; 
1994/1116    
	UNLOCKPAGE(ac->a); 
1994/1114    
 
	/* wait outside of lock */ 
1994/1115    
	tsleep(&ac->r, chancmddone, ac, 1000); 
1994/1114    
 
1994/1116    
	LOCKPAGE(ac->a, 0); 
1994/1115    
	status = ccb->status; 
	cmd = ccb->cmd; 
1994/1116    
	UNLOCKPAGE(ac->a); 
1994/1115    
	if(cmd){ 
1998/0109    
		print("#G%d: cmd didn't terminate\n", ac->a->id); 
1994/1114    
		error(Eio); 
	} 
1994/1115    
	if(status){ 
1998/0109    
		print("#G%d: cmd status %ux\n", ac->a->id, status); 
1994/1114    
		error(Eio); 
	} 
} 
 
/* 
 *  enable a channel for IO, set standard params. 
 *  (must be called with ac qlocked) 
 */ 
static void 
enable(Astarchan *ac) 
{ 
1994/1115    
	Astar *a = ac->a; 
	int n; 
 
1994/1114    
	/* make sure we control RTS, DTR and break */ 
1994/1116    
	LOCKPAGE(a, 0); 
1994/1114    
	n = LEUS(ac->ccb->proto) | Cmctl; 
	ac->ccb->proto = LEUS(n); 
1994/1115    
	ac->ccb->outlow = 64; 
1994/1116    
	UNLOCKPAGE(a); 
1994/1115    
	chancmd(ac, Cconfall); 
1994/1114    
 
	astarctl(ac, "l8"); 
	astarctl(ac, "p0"); 
	astarctl(ac, "d1"); 
	astarctl(ac, "r1"); 
1994/1115    
 
	chancmd(ac, Crcvena|Cxmtena|Cconfall); 
1994/1114    
} 
 
/* 
 *  disable a channel for IO 
 *  (must be called with ac qlocked) 
 */ 
static void 
disable(Astarchan *ac) 
{ 
1994/1117    
	int n; 
 
1994/1114    
	astarctl(ac, "d0"); 
	astarctl(ac, "r0"); 
 
1994/1117    
	LOCKPAGE(ac->a, 0); 
	n = LEUS(ac->ccb->proto) | Cmctl; 
	ac->ccb->proto = LEUS(n); 
	UNLOCKPAGE(ac->a); 
1994/1114    
	chancmd(ac, Crcvdis|Cxmtdis|Cflushin|Cflushout|Cconfall); 
1999/0315    
	ac->dsr = ac->dcd = 0; 
1994/1114    
} 
 
/* 
1994/1113    
 *  change channel parameters 
1994/1114    
 *  (must be called with ac qlocked) 
1994/1113    
 */ 
1994/1114    
static void 
1994/1113    
astarctl(Astarchan *ac, char *cmd) 
{ 
	int i, n; 
	int command; 
1994/1114    
	CCB *ccb; 
	Astar *a; 
1994/1113    
 
	/* let output drain for a while */ 
	for(i = 0; i < 16 && qlen(ac->oq); i++) 
1999/0629    
		tsleep(&ac->r, (int (*)(void*))qlen, ac->oq, 125); 
1994/1113    
 
	if(strncmp(cmd, "break", 5) == 0) 
		cmd = "k"; 
 
1994/1114    
	ccb = ac->ccb; 
1994/1113    
	command = 0; 
1994/1114    
	i = atoi(cmd+1); 
1994/1115    
 
1994/1114    
	a = ac->a; 
1994/1116    
	LOCKPAGE(a, 0); 
1994/1115    
 
1994/1113    
	switch(*cmd){ 
	case 'B': 
	case 'b': 
1994/1116    
		/* set baud rate (high rates are special - only 16 bits) */ 
1994/1114    
		switch(i){ 
1994/1113    
		case 76800: 
1994/1114    
			ccb->baud = LEUS(Cb76800); 
1994/1113    
			break; 
		case 115200: 
1994/1114    
			ccb->baud = LEUS(Cb115200); 
1994/1113    
			break; 
		default: 
1994/1115    
			ccb->baud = LEUS(i); 
1994/1113    
			break; 
		} 
1994/1116    
		ac->baud = i; 
 
		/* set trigger level to about 50  per second */ 
		n = i/500; 
		i = (LEUS(ccb->inlim) - LEUS(ccb->inbase))/2; 
		if(n > i) 
			n = i; 
		ccb->intrigger = LEUS(n); 
 
1994/1113    
		command = Cconfall; 
1994/1112    
		break; 
1994/1113    
	case 'D': 
	case 'd': 
1994/1114    
		n = LEUS(ccb->mctl); 
		if(i) 
			 n |= Cdtrctl; 
		else 
			 n &= ~Cdtrctl; 
1994/1122    
		ac->dtr = i; 
1994/1114    
		ccb->mctl = LEUS(n); 
1994/1112    
		break; 
1994/1113    
	case 'f': 
	case 'F': 
		qflush(ac->oq); 
		break; 
	case 'H': 
	case 'h': 
1997/0327    
		qhangup(ac->iq, nil); 
		qhangup(ac->oq, nil); 
1994/1113    
		break; 
	case 'L': 
	case 'l': 
1994/1115    
		n = i - 5; 
1994/1113    
		if(n < 0 || n > 3) 
			error(Ebadarg); 
1994/1114    
		n |= LEUS(ccb->format) & ~Clenmask; 
		ccb->format = LEUS(n); 
1994/1113    
		command = Cconfall; 
		break; 
	case 'm': 
	case 'M': 
1994/1114    
		/* turn on cts */ 
		n = LEUS(ccb->proto); 
1994/1116    
		if(i){ 
			n |= Cobeycts|Cgenrts; 
			n &= ~Cmctl; 
		} else { 
			n &= ~(Cobeycts|Cgenrts); 
			n |= Cmctl; 
		} 
1994/1114    
		ccb->proto = LEUS(n); 
 
1994/1113    
		command = Cconfall; 
		break; 
	case 'n': 
	case 'N': 
1994/1115    
		qnoblock(ac->oq, i); 
1994/1113    
		break; 
	case 'P': 
	case 'p': 
		switch(*(cmd+1)){ 
		case 'e': 
			n = Cevenpar; 
			break; 
		case 'o': 
			n = Coddpar; 
			break; 
		default: 
			n = Cnopar; 
			break; 
		} 
1994/1114    
		n |= LEUS(ccb->format) & ~Cparmask; 
		ccb->format = LEUS(n); 
1994/1113    
		command = Cconfall; 
		break; 
	case 'K': 
	case 'k': 
1994/1114    
		if(i <= 0) 
			i = 250; 
		n = LEUS(ccb->mctl) | Cbreakctl; 
		ccb->mctl = LEUS(n); 
1994/1116    
		UNLOCKPAGE(a); 
1994/1114    
 
		tsleep(&ac->r, return0, 0, i); 
 
1994/1116    
		LOCKPAGE(a, 0); 
1994/1114    
		n &= ~Cbreakctl; 
		ccb->mctl = LEUS(n); 
1994/1113    
		break; 
	case 'R': 
	case 'r': 
1994/1114    
		n = LEUS(ccb->mctl); 
		if(i) 
			 n |= Crtsctl; 
		else 
			 n &= ~Crtsctl; 
		ccb->mctl = LEUS(n); 
1994/1122    
		ac->rts = i; 
1994/1113    
		break; 
	case 'Q': 
	case 'q': 
1994/1115    
		qsetlimit(ac->iq, i); 
		qsetlimit(ac->oq, i); 
1994/1113    
		break; 
	case 'X': 
	case 'x': 
1994/1114    
		n = LEUS(ccb->proto); 
		if(i) 
			n |= Cobeyxon; 
		else 
			n &= ~Cobeyxon; 
		ccb->proto = LEUS(n); 
1994/1113    
		command = Cconfall; 
		break; 
1994/1111    
	} 
1994/1116    
	UNLOCKPAGE(a); 
1994/1114    
 
	if(command) 
		chancmd(ac, command); 
1994/1111    
} 
 
1997/0327    
static long 
1998/0319    
astarwrite(Chan *c, void *buf, long n, vlong off) 
1994/1111    
{ 
1994/1112    
	Astar *a; 
1994/1113    
	Astarchan *ac; 
1994/1112    
	char cmsg[32]; 
1998/0319    
	ulong offset = off; 
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: 
1998/0109    
		if(a->pci) 
			return pcimemwrite(a, buf, n, offset); 
		return isamemwrite(a, buf, n, offset); 
1994/1112    
	case Qbctl: 
		if(n > sizeof cmsg) 
			n = sizeof(cmsg) - 1; 
		memmove(cmsg, buf, n); 
		cmsg[n] = 0; 
1994/1115    
		bctlwrite(a, cmsg); 
		return n; 
1994/1113    
	case Qdata: 
		ac = a->c + CHAN(c->qid.path); 
		return qwrite(ac->oq, buf, n); 
	case Qctl: 
1994/1114    
		ac = a->c + CHAN(c->qid.path); 
1994/1113    
		if(n > sizeof cmsg) 
			n = sizeof(cmsg) - 1; 
		memmove(cmsg, buf, n); 
		cmsg[n] = 0; 
1994/1114    
 
		if(waserror()){ 
			qunlock(ac); 
			nexterror(); 
		} 
		qlock(ac); 
1994/1115    
		astarctl(ac, cmsg); 
1994/1114    
		qunlock(ac); 
		poperror(); 
1994/1111    
	} 
1994/1109    
 
	return 0; 
1995/0108    
} 
 
1997/0327    
static void 
1994/1112    
astarwstat(Chan *c, char *dp) 
{ 
1994/1115    
	Dir d; 
	Astarchan *ac; 
 
	if(!iseve()) 
		error(Eperm); 
	if(CHDIR & c->qid.path) 
		error(Eperm); 
	if(TYPE(c->qid.path) != Qdata && TYPE(c->qid.path) != Qctl) 
		error(Eperm); 
	ac = astar[BOARD(c->qid.path)]->c + CHAN(c->qid.path); 
 
	convM2D(dp, &d); 
	d.mode &= 0666; 
	ac->perm = d.mode; 
1994/1106    
} 
1994/1113    
 
1997/0327    
Dev astardevtab = { 
1997/0408    
	'G', 
	"astar", 
 
1997/0327    
	astarreset, 
	devinit, 
	astarattach, 
	devclone, 
	astarwalk, 
	astarstat, 
	astaropen, 
	devcreate, 
	astarclose, 
	astarread, 
	devbread, 
	astarwrite, 
	devbwrite, 
	devremove, 
	astarwstat, 
}; 
 
1994/1114    
/* 
 *  get output going 
 */ 
static void 
1994/1117    
astaroutput(Astarchan *ac) 
1994/1114    
{ 
	Astar *a = ac->a; 
1994/1115    
	CCB *ccb = ac->ccb; 
	uchar buf[256]; 
	uchar *rp, *wp, *bp, *ep, *p, *e; 
1994/1114    
	int n; 
 
1994/1116    
	if(a->needpage) 
		setpage(a, 0); 
1994/1115    
	ep = a->addr; 
	rp = ep + LEUS(ccb->outrp); 
	wp = ep + LEUS(ccb->outwp); 
	bp = ep + LEUS(ccb->outbase); 
	ep = ep + LEUS(ccb->outlim); 
1994/1114    
	for(;;){ 
1994/1115    
		n = rp - wp - 1; 
		if(n < 0) 
			n += ep - bp + 1; 
		if(n == 0) 
			break; 
		if(n > sizeof(buf)) 
			n = sizeof(buf); 
		n = qconsume(ac->oq, buf, n); 
		if(n <= 0) 
			break; 
1994/1116    
		if(a->needpage) 
			setpage(a, bp - a->addr); 
1994/1115    
		e = buf + n; 
		for(p = buf; p < e;){ 
			*wp++ = *p++; 
			if(wp > ep) 
				wp = bp; 
		} 
1994/1116    
		if(a->needpage) 
			setpage(a, 0); 
1994/1115    
		ccb->outwp = LEUS(wp - a->addr); 
1994/1114    
	} 
} 
1997/0327    
 
1994/1114    
static void 
1999/0629    
astarkick(void *v) 
1994/1114    
{ 
1999/0629    
	Astarchan *ac; 
 
	ac = v; 
1994/1114    
	ilock(&ac->a->pagelock); 
1994/1117    
	astaroutput(ac); 
1994/1114    
	iunlock(&ac->a->pagelock); 
} 
 
/* 
1994/1115    
 *  process input 
 */ 
static void 
astarinput(Astarchan *ac) 
{ 
	Astar *a = ac->a; 
	CCB *ccb = ac->ccb; 
	uchar buf[256]; 
	uchar *rp, *wp, *bp, *ep, *p, *e; 
	int n; 
 
1994/1116    
	if(a->needpage) 
		setpage(a, 0); 
1994/1115    
	ep = a->addr; 
	rp = ep + LEUS(ccb->inrp); 
	wp = ep + LEUS(ccb->inwp); 
	bp = ep + LEUS(ccb->inbase); 
	ep = ep + LEUS(ccb->inlim); 
	for(;;){ 
		n = wp - rp; 
		if(n == 0) 
			break; 
		if(n < 0) 
			n += ep - bp + 1; 
		if(n > sizeof(buf)) 
			n = sizeof(buf); 
1994/1116    
		if(a->needpage) 
			setpage(a, bp - a->addr); 
1994/1115    
		e = buf + n; 
		for(p = buf; p < e;){ 
			*p++ = *rp++; 
			if(rp > ep) 
				rp = bp; 
		} 
1997/0919    
		if(ac->opens == 0 || qproduce(ac->iq, buf, n) < 0) 
			break;	/* flow controlled or not open */ 
1994/1116    
		if(a->needpage) 
			setpage(a, 0); 
		ccb->inrp = LEUS(rp - a->addr); 
1994/1115    
	} 
1994/1116    
	if(a->needpage) 
		setpage(a, 0); 
1994/1115    
} 
 
/* 
1994/1116    
 *  get flow controlled input going again 
 */ 
static void 
1999/0629    
astarkickin(void *v) 
1994/1116    
{ 
1999/0629    
	Astarchan *ac; 
 
	ac = v; 
1994/1116    
	ilock(&ac->a->pagelock); 
	astarinput(ac); 
	iunlock(&ac->a->pagelock); 
} 
 
1999/0315    
static void 
astarmodemchange(Astarchan *ac) 
{ 
	Astar *a = ac->a; 
	int mstat; 
 
	if(a->needpage) 
		setpage(a, 0); 
	mstat = LEUS(ac->ccb->mstat); 
	if(ac->hup_dsr && ac->dsr == 1 && (mstat & Cdsrstat) == 0 
	|| ac->hup_dcd && ac->dcd == 1 && (mstat & Cdcdstat) == 0){ 
		qhangup(ac->iq, nil); 
		qhangup(ac->oq, nil); 
	} 
	ac->dsr = mstat & Cdsrstat; 
	ac->dcd = mstat & Cdcdstat; 
} 
 
1994/1116    
/* 
1994/1114    
 *  handle an interrupt 
 */ 
static void 
astarintr(Ureg *ur, void *arg) 
{ 
	Astar *a = arg; 
	Astarchan *ac; 
1997/0917    
	ulong globvec, vec, invec, outvec, errvec, mvec, cmdvec; 
1998/0109    
	int c, status; 
1994/1114    
 
1998/0109    
 
1994/1114    
	USED(ur); 
1994/1121    
	if(a->running == 0) 
1998/0109    
		panic("#G%d: interrupt but cp not running\n", a->id); 
1994/1121    
 
1994/1114    
	lock(&a->pagelock); 
1994/1116    
	if(a->needpage) 
		setpage(a, 0); 
1994/1114    
 
	/* get causes */ 
1997/0917    
	globvec = LEUS(xchgw(&a->gcb->serv, 0)); 
	USED(globvec); 
1994/1114    
	invec = LEUS(xchgw(&a->gcb->inserv, 0)); 
	outvec = LEUS(xchgw(&a->gcb->outserv, 0)); 
	errvec = LEUS(xchgw(&a->gcb->errserv, 0)); 
	mvec = LEUS(xchgw(&a->gcb->modemserv, 0)); 
	cmdvec = LEUS(xchgw(&a->gcb->cmdserv, 0)); 
 
	/* reenable interrupts */ 
1998/0109    
	if(a->pci){ 
		/* 
		 * Only the PCI doorbell interrupt is expected. 
		 */ 
		status = inl(a->port+PCIstatus); 
		if((status & 0x0810E000) != 0x00002000) 
			print("#G%d: unexpected interrupt %uX\n", a->id, status); 
		if(status & 0x00002000) 
			outl(a->port+PCIdoorbell1, 1); 
	} 
1994/1115    
	a->gcb->cmd2 = LEUS(Gintack); 
1994/1114    
 
	/* service interrupts */ 
	ac = a->c; 
1994/1115    
	for(vec = invec; vec; vec >>= 1){ 
		if(vec&1) 
			astarinput(ac); 
1994/1114    
		ac++; 
	} 
	ac = a->c; 
1994/1115    
	for(vec = outvec; vec; vec >>= 1){ 
1994/1114    
		if(vec&1) 
1994/1117    
			astaroutput(ac); 
1994/1114    
		ac++; 
	} 
	ac = a->c; 
1994/1115    
	for(vec = cmdvec; vec; vec >>= 1){ 
1994/1114    
		if(vec&1) 
			wakeup(&ac->r); 
1999/0315    
		ac++; 
	} 
	ac = a->c; 
	for(vec = mvec; vec; vec >>= 1){ 
		if(vec&1) 
			astarmodemchange(ac); 
1994/1121    
		ac++; 
	} 
	ac = a->c; 
	for(vec = errvec; vec; vec >>= 1){ 
		c = LEUS(ac->ccb->errstat); 
		if(c & Cframing) 
			ac->framing++; 
		if(c & Coverrun) 
			ac->overrun++; 
1994/1114    
		ac++; 
	} 
	unlock(&a->pagelock); 
} 


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