Charles.Forsyth20060303644188019 years agoHistory
368 lines · 5.4 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"io.h" enum {	// Ziatech 5512 Digital I/O ASIC register info	PortSelect =	0xE7,	Port =		0xE1,	 DQ =		1<<0,	 CLK =		1<<1,	 RST =		1<<2,	 TL =		1<<3,	 TH =		1<<4, 	// ds1620 Masks	Mread =		0xA0,	Mwrite =	0, 	// ds1620 Registers	Rtemp =		0x0A,	Rcounter =	0x00,	Rslope = 	0x09,	Rhi =		0x01,	Rlo =		0x02,	Rconfig =	0x0C,	 Cdone =	1<<7,	// conversion done	 Cthf =		1<<6,	// temp >= Rhi	 Ctlf =		1<<5,	// temp <= Rlo	 Cnvb =		1<<4,	// e^2 nvram busy (write may take up to 10ms)	 Ccpu =		1<<1,	// cpu use (0=clk starts conversion when rst lo)	 C1shot =	1<<0,	// perform one conversion then stop 	// ds1620 Commands	Startconv =	0xEE,	Stopconv =	0x22, 	ALOTEMP = 	0,	AHITEMP =	1,}; #define send(v)	outb(Port, v); delay(1)#define recv()	(!(inb(Port) & 1)) enum {	Qdir = 0,	Qtemp,	Qalarm,}; Dirtab ds1620tab[]={	"temp",		{Qtemp, 0},	0,	0666,	"alarm",	{Qalarm, 0},	0,	0444,}; typedef struct Temp Temp;struct Temp{	Lock;	int lo;	int cur;	int hi; 	int alo;	int ahi;	int atime;	Queue *aq;}; static Temp t; static voidsendreg(int r){	int d, i; 	r = ~r;	for(i=0;i<8;i++) {		d = (r >> i) & 1;		send(CLK|d);		send(d);		send(CLK);	}} static intds1620rdreg(int r, int nb){	int i, s; 	s = splhi(); 	outb(PortSelect, 0);	send(RST|CLK);	sendreg(r|Mread);	r = 0;	for(i=0; i < nb; i++) {		r |= recv() << i;		delay(1);		send(0);		send(CLK);	}	send(RST); 	splx(s);	return r;} static voidds1620wrreg(int r, int v, int nb){	int d, i, s; 	s = splhi(); 	outb(PortSelect, 0);	send(RST|CLK);	sendreg(r|Mwrite);	v = ~v;	for(i=0; i < nb; i++) {		d = (v >> i) & 1;		send(CLK|d);		send(0);		send(CLK);	}	send(RST); 	splx(s);} static voidds1620cmd(int r){	int s; 	s = splhi();	outb(PortSelect, 0);	send(RST|CLK);	sendreg(r);	send(RST);	splx(s);} static char*t2s(int t){	static char s[16]; 	sprint(s, "%4d.", t>>1);	if(t&1)		strcat(s, "5");	else		strcat(s, "0");	return s;} static ints2t(char *s){	int v;	char *p;	p = strchr(s, '.');	if(p != nil)		*p++ = '\0';	v = strtoul(s, nil, 0);	v <<= 1;	if(p != nil && *p != '\0' && *p >= '5')		v |= 1;	return v;} static voidalarm(int code, Temp *tt){	char buf[256], *end;	int s; 	s = seconds(); 	if(s - tt->atime < 60)		return;	tt->atime = s; 	end = buf;	end += sprint(buf, "(alarm) %8.8uX %uld temp ", code, seconds());	switch(code) {	case ALOTEMP:		end += sprint(end, "%s below threshold ", t2s(tt->lo));		end += sprint(end, "%s.\n", t2s(tt->alo));		break;	case AHITEMP:		end += sprint(end, "%s above threshold ", t2s(tt->hi));		end += sprint(end, "%s.\n", t2s(tt->ahi));		break;	} 	qproduce(tt->aq, buf, end-buf);} voidtmon(void *a){	int r;	Temp *t; 	t = a;	r = ds1620rdreg(Rtemp, 9);	lock(t);	t->lo = t->cur = t->hi = r;	unlock(t);	for(;;) {		tsleep(&up->sleep, return0, nil, 1000);		r = ds1620rdreg(Rtemp, 9);		lock(t);		t->cur = r;		if(r < t->lo)			t->lo = r;		if(r > t->hi)			t->hi = r;		if(t->lo < t->alo)			alarm(ALOTEMP, t);		if(t->hi > t->ahi)			alarm(AHITEMP, t);		unlock(t);	}	pexit("", 0);} static voidds1620init(void){	int r; 	t.aq = qopen(8*1024, Qmsg, nil, nil);	if(t.aq == nil)		error(Enomem); 	ds1620wrreg(Rconfig, Ccpu, 8);	// continuous sample mode	ds1620cmd(Startconv);	r = ds1620rdreg(Rtemp, 9);	t.alo = ds1620rdreg(Rlo, 9);		t.ahi = ds1620rdreg(Rhi, 9); 	print("#L: temp %s (c) ", t2s(r));	print("low threshold %s (c) ", t2s(t.alo));	print("high threshold %s (c)\n", t2s(t.ahi)); 	kproc("tempmon", tmon, &t, 0);} static Chan*ds1620attach(char *spec){	return devattach('L', spec);} static intds1620walk(Chan *c, char* name){	return devwalk(c, name, ds1620tab, nelem(ds1620tab), devgen);} static voidds1620stat(Chan *c, char* db){	ds1620tab[1].length = qlen(t.aq);	devstat(c, db, ds1620tab, nelem(ds1620tab), devgen);} static Chan*ds1620open(Chan *c, int omode){	return devopen(c, omode, ds1620tab, nelem(ds1620tab), devgen);} static voidds1620close(Chan*){} static longds1620read(Chan *c, void *a, long n, vlong offset){	Temp tt;	char buf[64];	char *s;	if(c->qid.path & CHDIR)		return devdirread(c, a, n, ds1620tab, nelem(ds1620tab), devgen);	buf[0] = 0;	switch(c->qid.path) {	case Qtemp:		lock(&t);		tt = t;		unlock(&t);		s = buf;		s+= sprint(s, "%s ", t2s(tt.lo));		s+= sprint(s, "%s ", t2s(tt.cur));		s+= sprint(s, "%s ", t2s(tt.hi));		s+= sprint(s, "%s ", t2s(tt.alo));		sprint(s, "%s", t2s(tt.ahi));		return readstr(offset, a, n, buf);	case Qalarm:		return qread(t.aq, a, n);	default:		error(Egreg);		return 0;	}} static longds1620write(Chan *c, void *a, long n, vlong){	char buf[64];	char *f[2];	int lo, hi;	int nf; 	if(c->qid.path & CHDIR)		error(Eperm); 	if(c->qid.path == Qtemp) {		if(n >= sizeof(buf))			n = sizeof(buf)-1;		memmove(buf, a, n);		buf[n] = '\0';		nf = getfields(buf, f, 2, 1, " \t");		if(nf != 2)			error(Ebadarg);		lo = s2t(f[0]);		hi = s2t(f[1]);		lock(&t);		t.alo = lo;		t.ahi = hi;		t.atime = 0;		ds1620wrreg(Rlo, lo, 9);		delay(1);		ds1620wrreg(Rhi, hi, 9);		unlock(&t);		return n;	} else		error(Eio);	return 0; } Dev ds1620devtab = {	'L',	"ds1620",	devreset,	ds1620init,	ds1620attach,	devdetach,	devclone,	ds1620walk,	ds1620stat,	ds1620open,	devcreate,	ds1620close,	ds1620read,	devbread,	ds1620write,	devbwrite,	devremove,	devwstat,};