~kris/9p

9hist

fb4ee5c29d7c0f10ac90abdb902f652f5bad9d17 — David du Colombier 27 years ago c8a2f94
Plan 9 from Bell Labs 1999-07-26
2 files changed, 113 insertions(+), 63 deletions(-)

M pc/devlm78.c
M pc/piix4smbus.c
M pc/devlm78.c => pc/devlm78.c +101 -52
@@ 7,17 7,31 @@
#include "ureg.h"
#include "../port/error.h"

// 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

// this driver doesn't implement the management interrupts.  we
// leave the LM78 interrupts set to whatever the BIOS did.  we do
// allow reading and writing the the readouts and alarm values.
// Read(2)ing or write(2)ing at offset 0x0-0x1f, is
// equivalent to reading or writing lm78 registers 0x20-0x3f.
enum
{
	// address of chip on serial interface
	Serialaddr=	0x2d,

	// parallel access registers
	Rpaddr=		0x5,
	 Bbusy=		 (1<<7),
	Rpdata=		0x6,

	// internal register addresses
	Rconfig=	0x40,
	 Bstart=	 (1<<0),
	 Bsmiena=	 (1<<1),
	 Birqena=	 (1<<2),
	 Bintclr=	 (1<<3),
	 Breset=	 (1<<4),
	 Bnmi=		 (1<<5),	// if set, use nmi, else irq
	 Bpowbypass=	 (1<<6),
	 Binit=		 (1<<7),
	Ristat1=	0x41,
	Ristat2=	0x42,
	Rsmimask1=	0x43,


@@ 55,56 69,113 @@ enum

static struct {
	QLock;

	int 	ifc;

	// serial interface
	SMBus	*smbus;

	// parallel interface
	int	port;
	int	probed;
	int 	ifc;	// which interface is connected
	SMBus	*smbus;	// serial interface
	int	port;	// parallel interface
} lm78;

extern SMBus*	piix4smbus(void);

// wait for device to become quiescent and then set the
// register address
static void
setreg(int reg)
{
	int tries;

	for(tries = 0; tries < 1000000; tries++)
		if((inb(lm78.port+Rpaddr) & Bbusy) == 0){
			outb(lm78.port+Rpaddr, reg);
			return;
		}
	error("lm78 broken");
}

// routines that actually touch the device
static int
static void
lm78wrreg(int reg, uchar val)
{
	if(waserror()){
		qunlock(&lm78);
		nexterror();
	}
	qlock(&lm78);

	switch(lm78.ifc){
	case Smbus:
		lm78.smbus->transact(lm78.smbus, SMBbytewrite, Serialaddr, reg, &val);
		return 0;
		break;
	case Parallel:
		setreg(reg);
		outb(lm78.port+Rpdata, val);
		break;
	default:
		error(Enodev);
		break;
	}
	return -1;

	qunlock(&lm78);
	poperror();
}

static int
lm78rdreg(int reg)
{
	uchar rv;
	uchar val;

	if(waserror()){
		qunlock(&lm78);
		nexterror();
	}
	qlock(&lm78);

	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;
		lm78.smbus->transact(lm78.smbus, SMBrecv, Serialaddr, 0, &val);
		break;
	case Parallel:
		setreg(reg);
		val = inb(lm78.port+Rpdata);
		break;
	default:
		error(Enodev);
		break;
	}
	return -1;

	qunlock(&lm78);
	poperror();
	return val;
}

static int
lm78probe(void)
// start the chip monitoring but don't change any smi
// interrupts and/or alarms that the BIOS may have set up.
//
// this isn't locked because it's thought to be idempotent
static void
lm78enable(void)
{
	switch(lm78.ifc){
	case Smbus:
	uchar config;

	if(lm78.ifc == None)
		error(Enodev);

	if(lm78.probed == 0){
		// make sure its really there
		if(lm78rdreg(Raddr) != Serialaddr){
			lm78.ifc = None;
			break;
			error(Enodev);
		} else {
			// start the sampling
			config = lm78rdreg(Rconfig);
pprint("config before %2.2ux\n", config);
			config = (config | Bstart) & ~(Bintclr|Binit);
			lm78wrreg(Rconfig, config);
pprint("config after %2.2ux\n", lm78rdreg(Rconfig));
		}
		return 0;
		lm78.probed = 1;
	}
	return -1;
}

enum


@@ 119,7 190,7 @@ enum
	PCSC8bytes=	0x01,
};

// figure out what kind of interface and if there's an lm78 there
// figure out what kind of interface we could have
void
lm78reset(void)
{


@@ 166,16 237,8 @@ lm78reset(void)
static Chan*
lm78attach(char* spec)
{
	static int probed;

	if(lm78.ifc == None)
		error(Enodev);
	lm78enable();

	if(probed == 0){
		if(lm78probe() < 0)
			error(Enodev);
		probed = 1;
	}
	return devattach('T', spec);
}



@@ 222,18 285,11 @@ lm78read(Chan *c, void *a, long n, vlong offset)
	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();
			*va++ = lm78rdreg(Rvalue+off);
		return va - (uchar*)a;
	}
	return 0;


@@ 254,18 310,11 @@ lm78write(Chan *c, void *a, long n, vlong offset)
	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();
			lm78wrreg(Rvalue+off, *va++);
		return va - (uchar*)a;
	}
	return 0;

M pc/piix4smbus.c => pc/piix4smbus.c +12 -11
@@ 80,7 80,8 @@ static struct
static void
transact(SMBus *s, int type, int addr, int cmd, uchar *data)
{
	int tries;
	int tries, status;
	char err[ERRLEN];

	if(type < 0 || type > nelem(proto))
		panic("piix4smbus: illegal transaction type %d", type);


@@ 106,8 107,8 @@ transact(SMBus *s, int type, int addr, int cmd, uchar *data)
			sched();
		}
		if(tries >= 1000000){
			print("SMBus status: %2.2ux", inb(s->base+Hoststatus));
			error("SMBus broken1");
			snprint(err, sizeof(err), "SMBus jammed: %2.2ux", inb(s->base+Hoststatus));
			error(err);
		}
	}



@@ 125,22 126,22 @@ transact(SMBus *s, int type, int addr, int cmd, uchar *data)
			break;
		}
	}
	 

	// reset the completion bit and start transaction
	outb(s->base+Hoststatus, Host_complete);
print("before %2.2ux\n", inb(s->base+Hoststatus));
	// reset the completion/error bits and start transaction
	outb(s->base+Hoststatus, Failed|Bus_error|Dev_error|Host_complete);
	outb(s->base+Hostcontrol, Start|proto[type].proto);
print("after %2.2ux\n", inb(s->base+Hoststatus));

	// wait for completion
	for(tries = 0; tries < 1000000; tries++){
		if(inb(s->base+Hoststatus) & Host_complete)
		status = inb(s->base+Hoststatus);
		if(status & (Failed|Bus_error|Dev_error|Host_complete))
			break;
		sched();
	}
	if(tries >= 1000000){
		print("SMBus status: %2.2ux", inb(s->base+Hoststatus));
		error("SMBus broken2");
	if((status & Host_complete) == 0){
		snprint(err, sizeof(err), "SMBus request failed: %2.2ux", status);
		error(err);
	}

	// get results