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

1999/0725/pc/devlm78.c (diff list | history)

pc/devlm78.c on 1999/0715
1999/0715    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
#include "ureg.h" 
#include "../port/error.h" 
1999/0708    
 
1999/0725    
// this driver assumes that noone has changed the serial address 
// of the device.  if they have, there's no way we can figure it 
// out -- presotto 
 
enum 
{ 
	// address of chip on serial interface 
	Serialaddr=	0x2d, 
 
	// internal register addresses 
	Rconfig=	0x40, 
	Ristat1=	0x41, 
	Ristat2=	0x42, 
	Rsmimask1=	0x43, 
	Rsmimask2=	0x44, 
	Rnmimask1=	0x45, 
	Rnmimask2=	0x46, 
	Rvidfan=	0x47,		// set fan counter, and read voltage level 
	 Mvid=		 0x0f, 
	 Mfan=		 0xf0, 
	Raddr=		0x48,		// address used on serial bus 
	Rresetid=	0x49,		// chip reset and ID register 
	Rpost=		0x00,		// start of post ram 
	Rvalue=		0x20,		// start of value ram 
 
	VRsize=		0x20,		// size of value ram 
}; 
 
enum 
{ 
1999/0708    
	Qdir, 
1999/0725    
	Qlm78vram, 
1999/0708    
}; 
 
1999/0715    
static Dirtab lm78dir[] = { 
1999/0725    
	"lm78vram",		{ Qlm78vram, 0 },		0,	0444, 
1999/0708    
}; 
 
1999/0725    
// interface type 
enum 
{ 
	None=	0, 
	Smbus, 
	Parallel, 
}; 
1999/0708    
 
1999/0725    
static struct { 
	QLock; 
 
	int 	ifc; 
 
	// serial interface 
	SMBus	*smbus; 
 
	// parallel interface 
	int	port; 
} lm78; 
 
1999/0715    
extern SMBus*	piix4smbus(void); 
1999/0708    
 
1999/0725    
// routines that actually touch the device 
static int 
lm78wrreg(int reg, uchar val) 
{ 
	switch(lm78.ifc){ 
	case Smbus: 
		lm78.smbus->transact(lm78.smbus, SMBbytewrite, Serialaddr, reg, &val); 
		return 0; 
	} 
	return -1; 
} 
 
static int 
lm78rdreg(int reg) 
{ 
	uchar rv; 
 
	switch(lm78.ifc){ 
	case Smbus: 
		lm78.smbus->transact(lm78.smbus, SMBsend, Serialaddr, reg, nil); 
		lm78.smbus->transact(lm78.smbus, SMBrecv, Serialaddr, 0, &rv); 
		return rv; 
	} 
	return -1; 
} 
 
static int 
lm78probe(void) 
{ 
	switch(lm78.ifc){ 
	case Smbus: 
		if(lm78rdreg(Raddr) != Serialaddr){ 
			lm78.ifc = None; 
			break; 
		} 
		return 0; 
	} 
	return -1; 
} 
 
enum 
{ 
	IntelVendID=	0x8086, 
	PiixID=		0x122E, 
	Piix3ID=	0x7000, 
 
	Piix4PMID=	0x7113,		// PIIX4 power management function 
 
	PCSC=		0x78,		// programmable chip select control register 
	PCSC8bytes=	0x01, 
}; 
 
// figure out what kind of interface and if there's an lm78 there 
1999/0715    
void 
1999/0725    
lm78reset(void) 
1999/0708    
{ 
1999/0725    
	int pcs; 
	Pcidev *p; 
 
	lm78.ifc = None; 
	p = nil; 
	while((p = pcimatch(p, IntelVendID, 0)) != nil){ 
		switch(p->did){ 
		// these bridges use the PCSC to map the lm78 into port space. 
		// for this case the lm78's CS# select is connected to the PIIX's 
		// PCS# output and the bottom 3 bits of address are passed to the 
		// LM78's A0-A2 inputs. 
		case PiixID: 
		case Piix3ID: 
			pcs = pcicfgr16(p, PCSC); 
			if(pcs & 3) { 
				/* already enabled */ 
				lm78.port = pcs & ~3; 
				lm78.ifc = Parallel; 
				return;	 
			} 
 
			// enable the chip, use default address 0x50 
			pcicfgw16(p, PCSC, 0x50|PCSC8bytes); 
			pcs = pcicfgr16(p, PCSC); 
			lm78.port = pcs & ~3; 
			lm78.ifc = Parallel; 
			return; 
 
		// this bridge puts the lm78's serial interface on the smbus 
		case Piix4PMID: 
			lm78.smbus = piix4smbus(); 
			if(lm78.smbus == nil) 
				continue; 
			print("found piix4 smbus, base %lud\n", lm78.smbus->base); 
			lm78.ifc = Smbus; 
			return; 
		} 
	} 
1999/0708    
} 
 
static Chan* 
1999/0715    
lm78attach(char* spec) 
1999/0708    
{ 
1999/0725    
	static int probed; 
 
	if(lm78.ifc == None) 
		error(Enodev); 
 
	if(probed == 0){ 
		if(lm78probe() < 0) 
			error(Enodev); 
		probed = 1; 
	} 
1999/0715    
	return devattach('T', spec); 
1999/0708    
} 
 
1999/0715    
int 
1999/0708    
lm78walk(Chan* c, char* name) 
{ 
1999/0715    
	return devwalk(c, name, lm78dir, nelem(lm78dir), devgen); 
1999/0708    
} 
 
static void 
1999/0715    
lm78stat(Chan* c, char* dp) 
{ 
	devstat(c, dp, lm78dir, nelem(lm78dir), devgen); 
1999/0708    
} 
 
static Chan* 
lm78open(Chan* c, int omode) 
{ 
1999/0715    
	return devopen(c, omode, lm78dir, nelem(lm78dir), devgen); 
1999/0708    
} 
 
static void 
1999/0715    
lm78close(Chan*) 
1999/0708    
{ 
} 
 
1999/0715    
enum 
1999/0708    
{ 
1999/0715    
	Linelen= 25, 
}; 
1999/0708    
 
static long 
1999/0715    
lm78read(Chan *c, void *a, long n, vlong offset) 
1999/0708    
{ 
1999/0725    
	uchar *va = a; 
	int off, e; 
1999/0715    
 
1999/0725    
	off = offset; 
 
	switch(c->qid.path & ~CHDIR){ 
1999/0708    
	case Qdir: 
1999/0715    
		return devdirread(c, a, n, lm78dir, nelem(lm78dir), devgen); 
1999/0708    
 
1999/0725    
	case Qlm78vram: 
		if(off >=  VRsize) 
			return 0; 
		if(waserror()){ 
			qunlock(&lm78); 
			nexterror(); 
		} 
		qlock(&lm78); 
		e = off + n; 
		if(e > VRsize) 
			e = VRsize; 
		for(; off < e; off++) 
			*va++ = lm78rdreg(off); 
		qunlock(&lm78); 
		poperror(); 
		return va - (uchar*)a; 
1999/0708    
	} 
1999/0715    
	return 0; 
1999/0708    
} 
 
static long 
1999/0715    
lm78write(Chan *c, void *a, long n, vlong offset) 
1999/0708    
{ 
1999/0725    
	uchar *va = a; 
	int off, e; 
 
	off = offset; 
 
	switch(c->qid.path){ 
	default: 
		error(Eperm); 
 
	case Qlm78vram: 
		if(off >=  VRsize) 
			return 0; 
		if(waserror()){ 
			qunlock(&lm78); 
			nexterror(); 
		} 
		qlock(&lm78); 
		e = off + n; 
		if(e > VRsize) 
			e = VRsize; 
		for(; off < e; off++) 
			lm78wrreg(off, *va++); 
		qunlock(&lm78); 
		poperror(); 
		return va - (uchar*)a; 
	} 
1999/0715    
	return 0; 
1999/0708    
} 
 
Dev lm78devtab = { 
1999/0715    
	'T', 
1999/0708    
	"lm78", 
1999/0715    
 
1999/0725    
	lm78reset, 
	devinit, 
1999/0708    
	lm78attach, 
1999/0715    
	devclone, 
1999/0708    
	lm78walk, 
	lm78stat, 
	lm78open, 
1999/0715    
	devcreate, 
1999/0708    
	lm78close, 
	lm78read, 
1999/0715    
	devbread, 
1999/0708    
	lm78write, 
1999/0715    
	devbwrite, 
	devremove, 
	devwstat, 
1999/0708    
}; 
1999/0725    
 


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