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

1990/0227/power/devbit.c (diff list | history)

power/devbit.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
#include	"devtab.h" 
 
#include	"io.h" 
 
typedef struct Bitmsg Bitmsg; 
struct Bitmsg 
{ 
	ulong	cmd; 
	ulong	addr; 
	ulong	count; 
	ulong	result; 
}; 
 
static struct 
{ 
	QLock; 
	int	open; 
	Bitmsg	msg; 
	char	buf[10*1024]; 
}bit; 
 
#define	BITADDR	((Bitmsg**)(KZERO+0x7C)) 
#define	BITINTR	((char*)(UNCACHED|0x17c12001)) 
 
enum 
{ 
	RESET, 
	READ, 
	WRITE, 
}; 
 
void 
bitsend(ulong cmd, void *addr, ulong count) 
{ 
	bit.msg.cmd = cmd; 
	bit.msg.addr = (ulong)addr; 
	bit.msg.count = count; 
	if(*BITADDR) 
		panic("bitsend"); 
	*BITADDR = &bit.msg; 
	wbflush(); 
	*BITINTR = 0x20; 
} 
 
void 
bitsync(void) 
{ 
	while(*BITADDR) 
		; 
} 
 
void 
bitreset(void) 
{ 
	*BITADDR = 0; 
	qlock(&bit); 
	qunlock(&bit); 
} 
 
void 
bitinit(void) 
{ 
} 
 
Chan* 
bitattach(char *spec) 
{ 
	return devattach('b', spec); 
} 
 
Chan* 
bitclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int	  
bitwalk(Chan *c, char *name) 
{ 
	if(c->qid != CHDIR) 
		return 0; 
	if(strcmp(name, "bit") == 0){ 
		c->qid = 1; 
		return 1; 
	} 
	return 0; 
} 
 
void	  
bitstat(Chan *c, char *dp) 
{ 
	print("bitstat\n"); 
	error(0, Egreg); 
} 
 
Chan* 
bitopen(Chan *c, int omode) 
{ 
	if(c->qid!=1 || omode!=ORDWR) 
		error(0, Eperm); 
	qlock(&bit); 
	if(bit.open){ 
		qunlock(&bit); 
print("multiple bit open\n"); 
		error(0, Einuse); 
	} 
	bitsync(); 
	bitsend(RESET, 0, 0); 
	bitsync(); 
	bit.open = 1; 
	qunlock(&bit); 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void	  
bitcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	error(0, Eperm); 
} 
 
void	  
bitclose(Chan *c) 
{ 
	qlock(&bit); 
	bit.open = 0; 
	qunlock(&bit); 
} 
 
/* 
 * Read and write use physical addresses if they can, which they usually can. 
 * Most I/O is from devmnt, which has local buffers.  Therefore just check 
 * that buf is in KSEG0 and is at an even address.  The only killer is that 
 * DMA counts from the bit device are mod 256, so devmnt must use oversize 
 * buffers. 
 */ 
 
long	  
bitread(Chan *c, void *buf, long n) 
{ 
	switch(c->qid){ 
	case 1: 
		if(n > sizeof bit.buf) 
			error(0, Egreg); 
		qlock(&bit); 
		if((((ulong)buf)&(KSEGM|3)) == KSEG0){ 
			bitsend(READ, buf, n); 
			bitsync(); 
		}else{ 
			bitsend(READ, bit.buf, n); 
			bitsync(); 
			memcpy(buf, bit.buf, n); 
		} 
		n = bit.msg.result; 
		qunlock(&bit); 
		return n; 
	} 
	error(0, Egreg); 
	return 0; 
} 
 
long	  
bitwrite(Chan *c, void *buf, long n) 
{ 
	switch(c->qid){ 
	case 1: 
		if(n > sizeof bit.buf) 
			error(0, Egreg); 
		qlock(&bit); 
		if((((ulong)buf)&(KSEGM|3)) == KSEG0){ 
			bitsend(WRITE, buf, n); 
			bitsync(); 
		}else{ 
			memcpy(bit.buf, buf, n); 
			bitsend(WRITE, bit.buf, n); 
			bitsync(); 
		} 
		qunlock(&bit); 
		return n; 
	} 
	error(0, Egreg); 
	return 0; 
} 
 
void	  
bitremove(Chan *c) 
{ 
	error(0, Eperm); 
} 
 
void	  
bitwstat(Chan *c, char *dp) 
{ 
	error(0, Eperm); 
} 
 
void 
bituserstr(Error *e, char *buf) 
{ 
	consuserstr(e, buf); 
} 
 
void	  
biterrstr(Error *e, char *buf) 
{ 
	rooterrstr(e, buf); 
} 


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