pc, pc64: provide access to embedded controller with #P/ec file
This commit is contained in:
parent
b18a641397
commit
bcb67353c1
9 changed files with 205 additions and 2 deletions
|
@ -8,6 +8,7 @@ arch \- architecture-specific information and control
|
|||
.B /dev/acpitbls
|
||||
.B /dev/archctl
|
||||
.B /dev/cputype
|
||||
.B /dev/ec
|
||||
.B /dev/ioalloc
|
||||
.B /dev/iob
|
||||
.B /dev/iol
|
||||
|
@ -128,6 +129,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
|
||||
return a concatenation of system ACPI tables. Each table
|
||||
|
|
|
@ -453,6 +453,30 @@ enumprt(void *dot, void *)
|
|||
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)
|
||||
{
|
||||
|
@ -589,6 +613,9 @@ Foundapic:
|
|||
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();
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ enum {
|
|||
Qiow,
|
||||
Qiol,
|
||||
Qmsr,
|
||||
Qec,
|
||||
Qbase,
|
||||
|
||||
Qmax = 16,
|
||||
|
@ -62,7 +63,8 @@ static Dirtab archdir[Qmax] = {
|
|||
"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 @@ static long
|
|||
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 @@ archread(Chan *c, void *a, long n, vlong offset)
|
|||
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;
|
||||
|
||||
|
@ -486,6 +501,15 @@ archwrite(Chan *c, void *a, long n, vlong offset)
|
|||
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:
|
||||
if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
|
||||
return fn(c, a, n, offset);
|
||||
|
|
138
sys/src/9/pc/ec.c
Normal file
138
sys/src/9/pc/ec.c
Normal file
|
@ -0,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;
|
||||
}
|
|
@ -30,6 +30,9 @@ int dmainit(int, int);
|
|||
#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*);
|
||||
|
|
|
@ -85,6 +85,7 @@ misc
|
|||
archacpi mp apic squidboy
|
||||
archmp mp apic squidboy
|
||||
mtrr
|
||||
ec
|
||||
|
||||
uarti8250
|
||||
uartisa
|
||||
|
|
|
@ -87,6 +87,7 @@ misc
|
|||
archacpi mp apic squidboy
|
||||
archmp mp apic squidboy
|
||||
mtrr
|
||||
ec
|
||||
|
||||
sdaoe
|
||||
sdide pci sdscsi
|
||||
|
|
|
@ -30,6 +30,9 @@ int dmainit(int, int);
|
|||
#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*);
|
||||
|
|
|
@ -85,6 +85,7 @@ misc
|
|||
archacpi mp apic squidboy
|
||||
archmp mp apic squidboy
|
||||
mtrr
|
||||
ec
|
||||
|
||||
# sdaoe
|
||||
sdide pci sdscsi
|
||||
|
|
Loading…
Reference in a new issue