ref: bcb67353c1ae559d6f91ab0669a06db52000b15d
parent: b18a6413975a0a8d06e6d310072a0ff90b1ed541
author: cinap_lenrek <[email protected]>
date: Sun Nov 9 19:04:37 EST 2014
pc, pc64: provide access to embedded controller with #P/ec file
--- a/sys/man/3/arch
+++ b/sys/man/3/arch
@@ -8,6 +8,7 @@
.B /dev/acpitbls
.B /dev/archctl
.B /dev/cputype
+.B /dev/ec
.B /dev/ioalloc
.B /dev/iob
.B /dev/iol
@@ -127,6 +128,10 @@
Reads and writes to
.I msr
go to the P4/P6/Core/Core2/AMD64 MSRs.
+.PP
+Reads and writes to
+.I ec
+transfer bytes from and to the embedded controller.
.PP
Reads from
.I acpitbls
--- a/sys/src/9/pc/archacpi.c
+++ b/sys/src/9/pc/archacpi.c
@@ -453,6 +453,30 @@
return 1;
}
+static int
+enumec(void *dot, void *)
+{
+ int cmdport, dataport;
+ uchar *b;
+ void *x;
+ char *id;
+
+ b = nil;
+ id = eisaid(amlval(amlwalk(dot, "^_HID")));
+ if(id == nil || strcmp(id, "PNP0C09") != 0)
+ return 1;
+ if((x = amlwalk(dot, "^_CRS")) == nil)
+ return 1;
+ if(amleval(x, "", &b) < 0 || amltag(b) != 'b' || amllen(b) < 16)
+ return 1;
+ if(b[0] != 0x47 || b[8] != 0x47) /* two i/o port descriptors */
+ return 1;
+ dataport = b[0+2] | b[0+3]<<8;
+ cmdport = b[8+2] | b[8+3]<<8;
+ ecinit(cmdport, dataport);
+ return 1;
+}
+
static void
acpiinit(void)
{
@@ -588,6 +612,9 @@
/* add identity mapped legacy isa interrupts */
for(i=0; i<16; i++)
addirq(i, BusISA, 0, i, 0);
+
+ /* find embedded controller */
+ amlenum(amlroot, "_HID", enumec, nil);
/* free the AML interpreter */
amlexit();
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -34,6 +34,7 @@
Qiow,
Qiol,
Qmsr,
+ Qec,
Qbase,
Qmax = 16,
@@ -62,7 +63,8 @@
"iob", { Qiob, 0 }, 0, 0660,
"iow", { Qiow, 0 }, 0, 0660,
"iol", { Qiol, 0 }, 0, 0660,
- "msr", { Qmsr, 0}, 0, 0660,
+ "msr", { Qmsr, 0 }, 0, 0660,
+ "ec", { Qec, 0 }, 0, 0660,
};
Lock archwlock; /* the lock is only for changing archdir */
int narchdir = Qbase;
@@ -361,7 +363,7 @@
archread(Chan *c, void *a, long n, vlong offset)
{
char *buf, *p;
- int port;
+ int port, v;
ushort *sp;
ulong *lp;
vlong *vp;
@@ -407,6 +409,19 @@
error(Ebadarg);
return n;
+ case Qec:
+ if(offset >= 256)
+ error(Ebadarg);
+ if(offset+n > 256)
+ n = 256 - offset;
+ p = a;
+ for(port = offset; port < offset+n; port++){
+ if((v = ecread(port)) < 0)
+ error(Eio);
+ *p++ = v;
+ }
+ return n;
+
case Qioalloc:
break;
@@ -484,6 +499,15 @@
for(port = offset; port < offset+n; port += 8)
if(wrmsr(port, *vp++) < 0)
error(Ebadarg);
+ return n;
+
+ case Qec:
+ if(offset+n > 256)
+ error(Ebadarg);
+ p = a;
+ for(port = offset; port < offset+n; port++)
+ if(ecwrite(port, *p++) < 0)
+ error(Eio);
return n;
default:
--- /dev/null
+++ b/sys/src/9/pc/ec.c
@@ -1,0 +1,138 @@
+/*
+ * embedded controller (usually at ports 0x66/0x62)
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum {
+ /* registers */
+ EC_SC = 0,
+ EC_DATA,
+
+ /* Embedded Controller Status, EC_SC (R) */
+ OBF = 1<<0,
+ IBF = 1<<1,
+ CMD = 1<<3,
+ BURST = 1<<4,
+ SCI_EVT = 1<<5,
+ SMI_EVT = 1<<6,
+
+ /* Embedded Controller Command Set */
+ RD_EC = 0x80,
+ WR_EC = 0x81,
+ BE_EC = 0x82,
+ BD_EC = 0x83,
+ QR_EC = 0x84,
+};
+
+static struct {
+ Lock;
+ int init;
+ int port[2]; /* EC_SC and EC_DATA */
+} ec;
+
+static uchar
+ecrr(int reg)
+{
+ return inb(ec.port[reg]);
+}
+static void
+ecwr(int reg, uchar val)
+{
+ outb(ec.port[reg], val);
+}
+
+static int
+ecwait(uchar mask, uchar val)
+{
+ int i, s;
+
+ s = 0;
+ for(i=0; i<1000; i++){
+ s = ecrr(EC_SC);
+ if((s & mask) == val)
+ return 0;
+ delay(1);
+ }
+ print("ec: wait timeout status=%x pc=%#p\n", s, getcallerpc(&mask));
+ return -1;
+}
+
+int
+ecinit(int cmdport, int dataport)
+{
+ print("ec: cmd %X, data %X\n", cmdport, dataport);
+
+ if(ioalloc(cmdport, 1, 0, "ec.sc") < 0){
+ print("ec: cant allocate cmd port %X\n", cmdport);
+ return -1;
+ }
+ if(ioalloc(dataport, 1, 0, "ec.data") < 0){
+ print("ec: cant allocate data port %X\n", dataport);
+ iofree(cmdport);
+ return -1;
+ }
+
+ lock(&ec);
+ ec.port[EC_SC] = cmdport;
+ ec.port[EC_DATA] = dataport;
+ ec.init = 1;
+ unlock(&ec);
+
+ return 0;
+}
+
+int
+ecread(uchar addr)
+{
+ int r;
+
+ r = -1;
+ lock(&ec);
+ if(!ec.init)
+ goto out;
+ if(ecwait(BURST|CMD, 0))
+ goto out;
+ ecwr(EC_SC, RD_EC);
+ if(ecwait(IBF, 0))
+ goto out;
+ ecwr(EC_DATA, addr);
+ if(ecwait(OBF, OBF))
+ goto out;
+ r = ecrr(EC_DATA);
+ ecwait(OBF, 0);
+out:
+ unlock(&ec);
+ return r;
+}
+
+int
+ecwrite(uchar addr, uchar val)
+{
+ int r;
+
+ r = -1;
+ lock(&ec);
+ if(!ec.init)
+ goto out;
+ if(ecwait(BURST|CMD, 0))
+ goto out;
+ ecwr(EC_SC, WR_EC);
+ if(ecwait(IBF, 0))
+ goto out;
+ ecwr(EC_DATA, addr);
+ if(ecwait(IBF, 0))
+ goto out;
+ ecwr(EC_DATA, val);
+ if(ecwait(IBF, 0))
+ goto out;
+ r = 0;
+out:
+ unlock(&ec);
+ return r;
+}
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -30,6 +30,9 @@
#define DMALOOP 2
long dmasetup(int, void*, long, int);
void dumpmcregs(void);
+int ecinit(int cmdport, int dataport);
+int ecread(uchar addr);
+int ecwrite(uchar addr, uchar val);
#define evenaddr(x) /* x86 doesn't care */
void fpclear(void);
void fpenv(FPsave*);
--- a/sys/src/9/pc/pccpuf
+++ b/sys/src/9/pc/pccpuf
@@ -85,6 +85,7 @@
archacpi mp apic squidboy
archmp mp apic squidboy
mtrr
+ ec
uarti8250
uartisa
--- a/sys/src/9/pc/pcf
+++ b/sys/src/9/pc/pcf
@@ -87,6 +87,7 @@
archacpi mp apic squidboy
archmp mp apic squidboy
mtrr
+ ec
sdaoe
sdide pci sdscsi
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -30,6 +30,9 @@
#define DMALOOP 2
long dmasetup(int, void*, long, int);
void dumpmcregs(void);
+int ecinit(int cmdport, int dataport);
+int ecread(uchar addr);
+int ecwrite(uchar addr, uchar val);
#define evenaddr(x) /* x86 doesn't care */
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -85,6 +85,7 @@
archacpi mp apic squidboy
archmp mp apic squidboy
mtrr
+ ec
# sdaoe
sdide pci sdscsi