## diffname pc/devlm78.c 1999/0708 ## diff -e /dev/null /n/emeliedump/1999/0708/sys/src/brazil/pc/devlm78.c 0a /* * Device Driver for National Semiconductor lm78 */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "interp.h" #include #include "runt.h" enum { /* Define the memory locations, registers, * and bit patterns for the nslm78 chip */ /* Define Address Register Port 0x05 */ ADDRESS_PORT = 0x05, /* Define Addresses of the various Registers in lm78 */ CONFIG_REG = 0x40, INTR_STATUS_REG1 = 0x41, INTR_STATUS_REG2 = 0x42, SMI_MASK_REG1 = 0x43, SMI_MASK_REG2 = 0x44, NMI_MASK_REG1 = 0x45, NMI_MASK_REG2 = 0x46, VID_FAN_REG = 0x47, SERIAL_BUS_ADDR_REG = 0x48, CHIP_RESET = 0x49, VALUE_RAM_BASE_1 = 0x20, VALUE_RAM_BASE_2 = 0x60, VALUE_RAM_LIMIT_2B = 0x6B, VALUE_RAM_LIMIT_2E = 0x7D, ARRAY_SIZE = (VALUE_RAM_LIMIT_2E - VALUE_RAM_LIMIT_2B) + 1, /* Define Data Register Port 0x06 */ DATA_PORT = 0x06, /* Define bit patterns for Configuration Register */ ONE_BIT = 0x01, START_MONITOR = ONE_BIT, SMI_ENABLE = (ONE_BIT<<1), NMI_IRQ_ENABLE = (ONE_BIT<<2), INT_CLEAR = (ONE_BIT<<3), RESET = (ONE_BIT<<4), NMI_IRQ_SELECT = (ONE_BIT<<5), INITIALIZE = (ONE_BIT<<7), /* For now, we are not interested in handling the interrupts. */ /* No bit patterns are defined for those interrupt registers */ /* Do not plan to use Serial Bus Address */ /* Define Chip Reset/ID Register for lm78 */ CHIP_RESET_REG = 0x49, /* Do not plan to use POST RAM (Power On Self Test) */ /* VALUE RAM Addresses for the Readings and Watchlog Limits */ IN0_RD = 0x60, IN1_RD = 0x61, IN2_RD = 0x62, IN3_RD = 0x63, IN4_RD = 0x64, IN5_RD = 0x65, IN6_RD = 0x66, TEMP_RD = 0x67, FAN1_RD = 0x68, FAN2_RD = 0x69, FAN3_RD = 0x6A, IN0_H = 0x6B, IN0_L = 0x6C, IN1_H = 0x6D, IN1_L = 0x6E, IN2_H = 0x6F, IN2_L = 0x70, IN3_H = 0x71, IN3_L = 0x72, IN4_H = 0x73, IN4_L = 0x74, IN5_H = 0x75, IN5_L = 0x76, IN6_H = 0x77, IN6_L = 0x78, TEMP_H = 0x79, TEMP_L = 0x7A, FAN1_CNT = 0x7B, FAN2_CNT = 0x7C, FAN3_CNT = 0x7D }; enum { Qdir, Qtemp, Qfan1, Qfan2, Qfan3, Qvolt1, Qvolt2, Qvolt3, Qvolt4, Qvolt5, Qvolt6, Qvolt7, Qalert, }; Dirtab lm78tab[]={ "temp", {Qtemp, 0}, 0, 0666, "fan1", {Qfan1, 0}, 0, 0666, "fan2", {Qfan2, 0}, 0, 0666, "fan3", {Qfan3, 0}, 0, 0666, "volt1", {Qvolt1, 0}, 0, 0666, "volt2", {Qvolt2, 0}, 0, 0666, "volt3", {Qvolt3, 0}, 0, 0666, "volt4", {Qvolt4, 0}, 0, 0666, "volt5", {Qvolt5, 0}, 0, 0666, "volt6", {Qvolt6, 0}, 0, 0666, "volt7", {Qvolt7, 0}, 0, 0666, "alert", {Qalert, 0}, 0, 0666, }; #define Nlm78tab nelem(lm78tab) #define RAM_SIZE 30 #define NFIELD 2 #define NBUFSIZE 128 #define N_DOT_PLACE 3 ulong miBASE; /* lm78 base address */ static int array_RAM[RAM_SIZE]; static int FanPulsesPerRev[] = { 0, 2, 2, 2 }; static int VoltageScale[] = { 0, 16, 16, 27, 60, 60, 16, 27 }; /* per CPV5000 lm78 Access */ /* volt1 for 3.3 v */ /* volt2 for cpu v (2.7 v) */ /* volt3 for 5.0 v */ /* volt4 for 12 v */ /* volt5 for -12 v */ static int default_val[] = { 250, 187, 250, 125, 222, 148, 250, 167, 250, 167, 250, 187, 222, 148, 35, 40, 219, 218, 217 }; /* voltages and fan speeds are converted to scales */ void write_routine(int value, int ival); static void lm78reset(void) /* Reset the lm78 Chip */ { } static void lm78detach(void) { } static int power(int x, int n) { int i, p; p = 1; for (i = 1; i <= n; ++i) p = p * x; return p; } static void write_ram (void) { int i; outb(miBASE+ADDRESS_PORT, VALUE_RAM_LIMIT_2B); for (i=0; i < ARRAY_SIZE; i++) { outb(miBASE+DATA_PORT, default_val[i]); } return; } static void set_intr_mask_regs(void) { write_routine(0xe0, SMI_MASK_REG1); write_routine(0x7f, SMI_MASK_REG2); /* mask the interrupt status bits */ write_routine(0xff, NMI_MASK_REG1); write_routine(0x7f, NMI_MASK_REG2); return; } static void start_monitor(int conf_reg_content ) { conf_reg_content |= START_MONITOR; conf_reg_content &= ~INT_CLEAR ; conf_reg_content &= ~INITIALIZE ; outb( miBASE+ADDRESS_PORT, CONFIG_REG); outb( miBASE+DATA_PORT, conf_reg_content); return; } static int read_vid(void) { int i,x; x = splhi(); outb( miBASE+ADDRESS_PORT, 0x47); /* tell the chip, we want to */ /* read VID */ i = inb(miBASE+DATA_PORT); splx(x); return i; } enum { IntelVendID= 0x8086, PiixBridgeID= 0x122E, Piix3BridgeID= 0x7000, Piix4BridgeID= 0x7110, PCSC= 0x78, /* programmable chip select control register */ PCSC8bytes= 0x01, }; int readpcilm78(void) { int pcs; Pcidev *p; p = nil; while((p = pcimatch(p, IntelVendID, 0)) != nil){ switch(p->did){ case PiixBridgeID: case Piix3BridgeID: case Piix4BridgeID: break; default: continue; } break; } if(p == nil) return -1; pcs = pcicfgr16(p, PCSC); if(pcs & 3) { /* already enabled */ miBASE = pcs & ~3; return 0; } /* enable the chip, use default address 0x50 */ pcicfgw16(p, PCSC, 0x50|PCSC8bytes); pcs = pcicfgr16(p, PCSC); miBASE = pcs & ~3; return 0; } static void lm78init(void) { int config_reg_content; if (readpcilm78() == -1) error("lm78 Not Initialized\n"); outb( miBASE+ADDRESS_PORT, CONFIG_REG); config_reg_content = inb(miBASE+DATA_PORT); /* Read in the config reg content */ config_reg_content |= INITIALIZE; /* After Power on the config_reg */ /* has value 0000 1000 */ /* For reset with all interrupt */ /* disabled, the config_reg is */ /* to 1000 1000 */ outb( miBASE+ADDRESS_PORT, CONFIG_REG); outb( miBASE+DATA_PORT, config_reg_content); write_ram(); /* write to WATCHDOG RAM the default values */ read_vid(); set_intr_mask_regs(); start_monitor(config_reg_content); } static Chan* lm78attach(char *spec) { return devattach('L', spec); } static Chan* lm78clone(Chan* c, Chan* nc) { return devclone(c, nc); } static int lm78walk(Chan* c, char* name) { return devwalk(c, name, lm78tab, Nlm78tab, devgen); } static void lm78stat(Chan* c, char* db) { devstat(c, db, lm78tab, Nlm78tab, devgen); } static Chan* lm78open(Chan* c, int omode) { return devopen(c, omode, lm78tab, Nlm78tab, devgen); } static void lm78create(Chan* c, char* name, int omode, ulong perm) { USED(c, name, omode, perm); error(Eperm); } static void lm78remove(Chan* c) { USED(c); error(Eperm); } static void lm78wstat(Chan* c, char* dp) { USED(c, dp); error(Eperm); } static void lm78close(Chan* c) { USED(c); } static int value_f(int f, int n_digit) { int i, dvalue; dvalue = 0; for (i = n_digit; i >= 1; i--) { dvalue += (f%10) * power(10, N_DOT_PLACE-i); f /= 10; } return dvalue; } static int aatof(char * str_ptr) { int i, f; char *p; char *q; i = strtol(str_ptr, &p, 10); if (p == str_ptr) error ("no digits\n"); if (*p == 0) return (i * 1000); f = strtol(p+1, &q,10); /* do the part after the period */ if (q > p+N_DOT_PLACE+1) error("more than three digits after period\n"); if (q == p+1) return (i*1000); if (q == p+2) return (i*1000 + value_f( f, 1)); if (q == p+3) return (i*1000 + value_f( f, 2)); if (q == p+4) return (i*1000 + value_f( f, 3)); } void reverse(char s[]) { int c, i, j; for (i = 0, j = strlen(s) -1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } static void itoreal(int n, char s[], int dot_place) { int i, sign; if ((sign =n) < 0) n = -n; i = 0; do { if (i != dot_place) { s[i++] = n % 10 + '0' ; n /= 10; } else s[i++] = '.'; } while (n >0); if ( (sign > 0 ) && sign < power(10, dot_place)) { s[i++] = '.'; }; if ( (sign < 0 ) && (-sign < power(10, dot_place))) { s[i++] = '.'; s[i++] = '-'; }; if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); } static int convert_to_temp(int val) { if (val == 0xff) return 0; if (val >= 0xc9) return ( -((~val & 0177) + 1)); return val; } static int rpm_to_count(char* rpm, int index) { int n; n = 1350000/(FanPulsesPerRev[index] * aatof(rpm)/1000); if (n > 255) error(Ebadarg); return n; } static int convert_to_rpm(int val, int index ) { if ((val==255) || (val == 0)) return (0); else return(1350000/(FanPulsesPerRev[index] * val)); } static char* convert_to_volt(int val, int index) { int i; char *vstring = malloc(12); if (vstring == 0) error("no memory"); i = val * VoltageScale[index]; itoreal(i, vstring, N_DOT_PLACE); return vstring; } static int voltage_to_scale( char *volt, int index) { int n; n = aatof(volt) / VoltageScale[index]; if (n > 255) error(Ebadarg); else return n; } static int read_routine(int ivalue) { int x, iv; x = splhi(); /* turn off all maskable interrupts */ outb(miBASE+ADDRESS_PORT, ivalue); iv = inb(miBASE+DATA_PORT ); splx(x); return iv; } static long lm78read(Chan* c, void* a, long n, ulong offset) { int value, lo, hi, fannum, v_num; int f_value, f_hi, f_lo, intr1, intr2; char *v_str, *v_hi, *v_lo; char buf[NBUFSIZE]; USED(offset); v_str = nil; v_hi = nil; v_lo = nil; f_hi = 0; switch(c->qid.path & ~CHDIR){ case Qdir: return devdirread(c,a,n,lm78tab, Nlm78tab,devgen); case Qtemp: /* read temperature from RAM and pass it back via *a */ f_value = convert_to_temp(read_routine(TEMP_RD)); f_hi = convert_to_temp(read_routine(TEMP_H)); f_lo = convert_to_temp(read_routine(TEMP_L)); break; case Qfan1: fannum = 1; value = read_routine(FAN1_RD); f_value = convert_to_rpm(value, fannum); lo = read_routine(FAN1_CNT); f_lo = convert_to_rpm(lo, fannum); break; case Qfan2: fannum = 2; value = read_routine(FAN2_RD); f_value = convert_to_rpm(value, fannum); lo = read_routine(FAN2_CNT); f_lo = convert_to_rpm(lo, fannum); break; case Qfan3: fannum = 3; value = read_routine(FAN3_RD); f_value = convert_to_rpm(value, fannum); lo = read_routine(FAN3_CNT); f_lo = convert_to_rpm(lo, fannum); break; default: switch(c->qid.path & ~CHDIR){ case Qvolt1: v_num = 1; value = read_routine(IN0_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN0_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN0_L); v_lo = convert_to_volt(lo, v_num); break; case Qvolt2: v_num = 2; value = read_routine(IN1_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN1_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN1_L); v_lo = convert_to_volt(lo, v_num); break; case Qvolt3: v_num = 3; value = read_routine(IN2_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN2_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN2_L); v_lo = convert_to_volt(lo, v_num); break; case Qvolt4: v_num = 4; value = read_routine(IN3_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN3_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN3_L); v_lo = convert_to_volt(lo, v_num); break; case Qvolt5: v_num = 5; value = read_routine(IN4_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN4_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN4_L); v_lo = convert_to_volt(lo, v_num); break; case Qvolt6: v_num =6; value = read_routine(IN5_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN5_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN5_L); v_lo = convert_to_volt(lo, v_num); break; case Qvolt7: v_num = 7; value = read_routine(IN6_RD); v_str = convert_to_volt(value, v_num); hi = read_routine(IN6_H); v_hi = convert_to_volt(hi, v_num); lo = read_routine(IN6_L); v_lo = convert_to_volt(lo, v_num); break; case Qalert: /* read interrupt status registers */ /* delay(15*100); */ intr1 = read_routine(INTR_STATUS_REG1); intr2 = read_routine(INTR_STATUS_REG2); intr1 &= 0x001F; intr2 &= 0x001F; n = sprint(buf, "%d", intr1); return readstr(offset, a, n, buf); /* deliver data to address a */ default: error(Ebadarg); } /* get ready to send to kernel */ sprint(buf, "%s %s %s", v_str, v_lo, v_hi); free(v_str); free(v_hi); free(v_lo); return readstr(offset, a, n, buf); } n = sprint(buf, "%d %d %d", f_value, f_lo, f_hi); return readstr(offset, a, n, buf); /* deliver data to address a */ } void write_routine(int value, int ival) { int x; x = splhi(); /* turn off all maskable interrupts */ /* take the input from *a convert to int */ /* and write it to the RAM */ outb( miBASE+ADDRESS_PORT, ival); outb( miBASE+DATA_PORT, value); splx(x); return; } int tempvalue( char *ptr) { int temp_digit; char *p; temp_digit = strtol(ptr, &p, 10); if (p == ptr) error(Ebadarg); if (temp_digit > 125) error(Ebadarg); return temp_digit; } static Block* lm78bread(Chan* c, long n, ulong offset) { return devbread(c, n, offset); } static long lm78write(Chan* c, char* a, long n, ulong offset) { int nf, fan_num, v_num; char *field[NFIELD], buf[NBUFSIZE]; USED(offset); if(n > sizeof(buf)-1) n = sizeof(buf)-1; memmove(buf, a, n); buf[n] = '\0'; nf = parsefields(buf, field, NFIELD, " \t"); USED(nf); switch(c->qid.path & ~CHDIR){ case Qtemp: write_routine(tempvalue(field[1]), TEMP_H); delay(1000); write_routine(tempvalue(field[0]), TEMP_L); break; case Qfan1: fan_num = 1; write_routine(rpm_to_count(field[0], fan_num), FAN1_CNT); break; case Qfan2: fan_num = 2; write_routine(rpm_to_count(field[0], fan_num), FAN2_CNT); break; case Qfan3: fan_num = 3; write_routine(rpm_to_count(field[0], fan_num), FAN3_CNT); break; case Qvolt1: v_num = 1; write_routine(voltage_to_scale(field[1], v_num), IN0_H); write_routine(voltage_to_scale(field[0], v_num), IN0_L); break; case Qvolt2: v_num = 2; write_routine(voltage_to_scale(field[1], v_num), IN1_H); write_routine(voltage_to_scale(field[0], v_num), IN1_L); break; case Qvolt3: v_num = 3; write_routine(voltage_to_scale(field[1], v_num), IN2_H); write_routine(voltage_to_scale(field[0], v_num), IN2_L); break; case Qvolt4: v_num = 4; write_routine(voltage_to_scale(field[1], v_num), IN3_H); write_routine(voltage_to_scale(field[0], v_num), IN3_L); break; case Qvolt5: v_num = 5; write_routine(voltage_to_scale(field[1], v_num), IN4_H); write_routine(voltage_to_scale(field[0], v_num), IN4_L); break; case Qvolt6: v_num = 6; write_routine(voltage_to_scale(field[1], v_num), IN5_H); write_routine(voltage_to_scale(field[0], v_num), IN5_L); break; case Qvolt7: v_num = 7; write_routine(voltage_to_scale(field[1], v_num), IN6_H); write_routine(voltage_to_scale(field[0], v_num), IN6_L); break; default: error(Ebadarg); } return n; } static long lm78bwrite(Chan* c, Block* bp, ulong offset) { return devbwrite(c, bp, offset); } Dev lm78devtab = { 'L', "lm78", lm78reset, lm78init, lm78attach, lm78detach, lm78clone, lm78walk, lm78stat, lm78open, lm78create, lm78close, lm78read, lm78bread, lm78write, lm78bwrite, lm78remove, lm78wstat, }; . ## diffname pc/devlm78.c 1999/0709 ## diff -e /n/emeliedump/1999/0708/sys/src/brazil/pc/devlm78.c /n/emeliedump/1999/0709/sys/src/brazil/pc/devlm78.c 269,274c /* this bridge uses the SMbus */ case Piix4PMID: return -1: } } return -1; . 262,267c /* enable the chip, use default address 0x50 */ pcicfgw16(p, PCSC, 0x50|PCSC8bytes); pcs = pcicfgr16(p, PCSC); miBASE = pcs & ~3; return 0; . 250,260c /* these bridges have pretty easy access to the lm78 */ case PiixID: case Piix3ID: pcs = pcicfgr16(p, PCSC); if(pcs & 3) { /* already enabled */ miBASE = pcs & ~3; return 0; } . 236a Piix4PMID= 0x7113, /* PIIX4 power management function */ . 233,235c PiixID= 0x122E, Piix3ID= 0x7000, . ## diffname pc/devlm78.c 1999/0715 ## diff -e /n/emeliedump/1999/0709/sys/src/brazil/pc/devlm78.c /n/emeliedump/1999/0715/sys/src/brazil/pc/devlm78.c 791,793c devbwrite, devremove, devwstat, . 789c devbread, . 786c devcreate, . 781,782c devclone, . 778c devreset, . 776c 'T', . 772c error(Eperm); return 0; . 770c lm78write(Chan *c, void *a, long n, vlong offset) . 766c return 0; . 712,764c error(Eperm); . 561,710d 531,559c return devdirread(c, a, n, lm78dir, nelem(lm78dir), devgen); . 529a . 517,528d 515c lm78read(Chan *c, void *a, long n, vlong offset) . 347,513d 343,345c Linelen= 25, }; . 340,341c enum . 336,337d 334c lm78close(Chan*) . 330c return devopen(c, omode, lm78dir, nelem(lm78dir), devgen); . 322,324c lm78stat(Chan* c, char* dp) { devstat(c, dp, lm78dir, nelem(lm78dir), devgen); . 318c return devwalk(c, name, lm78dir, nelem(lm78dir), devgen); . 315c int . 312c return devattach('T', spec); . 310c lm78attach(char* spec) . 305,306c lm78smbus = piix4smbus(); if(lm78smbus != nil) print("found piix4 smbus, base %lud\n", lm78smbus->base); . 277,303d 161,275c void . 141,159c extern SMBus* piix4smbus(void); . 139c SMBus *lm78smbus; . 133,137d 119,131c static Dirtab lm78dir[] = { "temp", { Qtemp, 0 }, 0, 0444, . 106,116d 2,103c enum { . 0a #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" . ## diffname pc/devlm78.c 1999/0725 ## diff -e /n/emeliedump/1999/0715/sys/src/brazil/pc/devlm78.c /n/emeliedump/1999/0725/sys/src/brazil/pc/devlm78.c 105a . 90,91c lm78reset, devinit, . 82c 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; } . 73,74c 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; . 69a off = offset; switch(c->qid.path & ~CHDIR){ . 68c uchar *va = a; int off, e; . 33a static int probed; if(lm78.ifc == None) error(Enodev); if(probed == 0){ if(lm78probe() < 0) error(Enodev); probed = 1; } . 26,28c 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; } } . 24c lm78reset(void) . 22a // 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 . 20a static struct { QLock; int ifc; // serial interface SMBus *smbus; // parallel interface int port; } lm78; . 19c // interface type enum { None= 0, Smbus, Parallel, }; . 16c "lm78vram", { Qlm78vram, 0 }, 0, 0444, . 12c Qlm78vram, . 10c // 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 { . ## diffname pc/devlm78.c 1999/0726 ## diff -e /n/emeliedump/1999/0725/sys/src/brazil/pc/devlm78.c /n/emeliedump/1999/0726/sys/src/brazil/pc/devlm78.c 266,268c lm78wrreg(Rvalue+off, *va++); . 257,261d 234,236c *va++ = lm78rdreg(Rvalue+off); . 225,229d 171,178d 169c lm78enable(); . 122c // figure out what kind of interface we could have . 107d 105c lm78.probed = 1; . 103c 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)); . 99,100c uchar config; if(lm78.ifc == None) error(Enodev); if(lm78.probed == 0){ // make sure its really there . 96,97c // 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) . 93c qunlock(&lm78); poperror(); return val; . 90,91c lm78.smbus->transact(lm78.smbus, SMBrecv, Serialaddr, 0, &val); break; case Parallel: setreg(reg); val = inb(lm78.port+Rpdata); break; default: error(Enodev); break; . 86a if(waserror()){ qunlock(&lm78); nexterror(); } qlock(&lm78); . 85c uchar val; . 79c qunlock(&lm78); poperror(); . 77c break; case Parallel: setreg(reg); outb(lm78.port+Rpdata, val); break; default: error(Enodev); break; . 73a if(waserror()){ qunlock(&lm78); nexterror(); } qlock(&lm78); . 71c static void . 69a // 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"); } . 58,65c int probed; int ifc; // which interface is connected SMBus *smbus; // serial interface int port; // parallel interface . 20a 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), . 18a // parallel access registers Rpaddr= 0x5, Bbusy= (1<<7), Rpdata= 0x6, . 10,13c // 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. . ## diffname pc/devlm78.c 1999/0728 ## diff -e /n/emeliedump/1999/0726/sys/src/brazil/pc/devlm78.c /n/emeliedump/1999/0728/sys/src/brazil/pc/devlm78.c 175c pprint("Rvidfan %2.2ux\n", lm78rdreg(Rconfig), lm78rdreg(Rvidfan)); . 172d