From fb4ee5c29d7c0f10ac90abdb902f652f5bad9d17 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 26 Jul 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-07-26 --- pc/devlm78.c | 153 ++++++++++++++++++++++++++++++++---------------- pc/piix4smbus.c | 23 ++++---- 2 files changed, 113 insertions(+), 63 deletions(-) diff --git a/pc/devlm78.c b/pc/devlm78.c index bdcd58564bc9249f5507581556f4270c57493d89..b13c8b6c92ac86b809aec4c5c1759f1607440811 100644 --- a/pc/devlm78.c +++ b/pc/devlm78.c @@ -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; diff --git a/pc/piix4smbus.c b/pc/piix4smbus.c index 58489aa7eed44c59f6da75fe36ad2514e82deca3..bf44528bb1b863ab24b972b6631472d1eda46e57 100644 --- a/pc/piix4smbus.c +++ b/pc/piix4smbus.c @@ -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