#include <u.h>#include <libc.h>#include <aml.h> #include "acpi.h" struct Gas { uchar space; uchar bw; uchar bo; uchar size; uchar addr[8];}; struct Ecdt { struct Gas ec_cmd; struct Gas ec_data; uchar uid[4]; uchar gpe; uchar id[1];}; struct ec { int cmd; int data; int ready;} ec; enum { /* status bits */ OutBufFull = 0x01, InBufFull = 0x02, DataIsCmd = 0x08, Burst = 0x10, SciEvt = 0x20, SmiEvt = 0x40, /* commands */ EcRead = 0x80, EcWrite = 0x81, EcBurstEn = 0x82, EcBurstDis = 0x83, EcQuery = 0x84,}; static uchar inb(int off){ uvlong val; amlio(IoSpace, 'R', &val, 1, off); return val;} static voidoutb(int off, uchar v){ uvlong val; val = v; amlio(IoSpace, 'W', &val, 1, off);} static voidacpiec_wait(uchar mask, uchar val){ uchar stat; while((stat = inb(ec.cmd) & mask) != val) { //if (stat & Burst) amldelay(1); }} static ucharacpiec_read_data(void){ acpiec_wait(OutBufFull, OutBufFull); return inb(ec.data);} static voidacpiec_write_data(uchar val){ acpiec_wait(InBufFull, 0); outb(ec.data, val);} static voidacpiec_write_cmd(uchar val){ acpiec_wait(InBufFull, 0); outb(ec.cmd, val);} static ucharacpiec_read(uchar addr){ if (!ec.ready) return 0; acpiec_write_cmd(EcRead); acpiec_write_data(addr); return acpiec_read_data();} static voidacpiec_write(uchar addr, uvlong val){ int i; uchar *v = (uchar*)&val; if (!ec.ready) return; for(i = 0; i < sizeof(uvlong); i++) { acpiec_write_cmd(EcWrite); acpiec_write_data(addr + i); // ? acpiec_write_data(v[i]); }} intecread(Amlio *io, void *p, int, int addr){ //print("ecread addr:%d len:%d\n", (int)io->off + addr, len); *(uchar*)p = acpiec_read(io->off + addr); return 1;} intecwrite(Amlio *io, void *p, int, int addr){ if(((Fileio*)io->aux)->dummy) { *(char*)p = 0; return -1; } print("ecwrite addr = %d\n", addr); uvlong val = *(uvlong*)p; acpiec_write(io->off + addr, val); return 1;} static intacpiec_getreg(unsigned char *buf, int size, int *type, int *addr){ enum { ResTypeMask = 0x80, ResLengthMask = 0x07, ResTypeIoPort = 0x47, ResTypeEndTag = 0x79 }; enum { SystemIoSpace = 1 }; int len, hlen; if (size <= 0) return 0; if (*buf & ResTypeMask) { /* large resource */ if (size < 3) return 1; len = (int)buf[1] + 256 * (int)buf[2]; hlen = 3; } else { /* small resource */ len = buf[0] & ResLengthMask; hlen = 1; } if (*buf != ResTypeIoPort) return 0; if (size < hlen + len) return 0; *type = SystemIoSpace; *addr = (int)buf[2] + 256 * (int)buf[3]; return (hlen + len);} voidacpiec_init(void *dot, void *tbl){ void *m; char *buf; void *p; int gpe; int rv, size, t; int ec_sc, ec_data; struct Ecdt *ecdt = tbl; struct Amlio *io; if(ec.ready) return; /* we need port I/O working */ if ((io = calloc(1, sizeof(*io))) == nil) sysfatal("failed to alloc port i/o"); io->space = IoSpace; if(amlmapio(io) == -1) sysfatal("Cannot map I/O space"); if(ecdt != nil) { ecdt = (struct Ecdt*)tbl; ec_sc = get64(ecdt->ec_cmd.addr); ec_data = get64(ecdt->ec_data.addr); gpe = ecdt->gpe; goto done; } if((m = amlwalk(dot, "_GPE")) == 0) { print("ec: no _GPE\n"); return; } if(amleval(m, "", &p) < 0) { print("ec: _GPE not working\n"); return; } gpe = amlint(amlval(p)); if((m = amlwalk(dot, "_CRS")) == 0) { print("ec: no _CRS\n"); return; } if(amleval(m, "", &buf) < 0) { print("ec: _CRS not working\n"); return; } if(amltag(buf) != 'b') { print("ec: unknown _CRS type\n"); return; } size = amllen(buf); rv = acpiec_getreg(amlval(buf), size, &t, &ec_data); //print("getreg: rv=%d t=%d ec_data=0x%x\n", rv, t, ec_data); buf += rv; size -= rv; rv = acpiec_getreg(amlval(buf), size, &t, &ec_sc); //print("getreg: rv=%d t=%d ec_sc=0x%x\n", rv, t, ec_sc); buf += rv; size -= rv; if(size != 2 || *buf != 0x79) { print("no crs endtag\n"); } /* register */ enum { RegTypeEC = 3 }; if((m = amlwalk(dot, "_REG")) == 0) { print("ec: no _REG\n"); return; } if(amleval(m, "ii", RegTypeEC, 1, nil) < 0) { print("ec: _REG not working\n"); return; } done:/* if(ioalloc(ec_data, 1, 0, "ec_data") < 0) print("ec: ec_data port space in use"); if(ioalloc(ec_sc, 1, 0, "ec_sc") < 0) print("ec: ec_sc port space in use"); */ print("ec: status: %d gpe: %d data: 0x%x s/c: 0x%x \n", inb(ec_sc), gpe, ec_data, ec_sc); ec.cmd = ec_sc; ec.data = ec_data; ec.ready = 1;}
#include <u.h>
#include <libc.h>
#include <aml.h>
#include "acpi.h"
struct Gas {
uchar space;
uchar bw;
uchar bo;
uchar size;
uchar addr[8];
};
struct Ecdt {
struct Gas ec_cmd;
struct Gas ec_data;
uchar uid[4];
uchar gpe;
uchar id[1];
};
struct ec {
int cmd;
int data;
int ready;
} ec;
enum {
/* status bits */
OutBufFull = 0x01,
InBufFull = 0x02,
DataIsCmd = 0x08,
Burst = 0x10,
SciEvt = 0x20,
SmiEvt = 0x40,
/* commands */
EcRead = 0x80,
EcWrite = 0x81,
EcBurstEn = 0x82,
EcBurstDis = 0x83,
EcQuery = 0x84,
};
static uchar
inb(int off){
uvlong val;
amlio(IoSpace, 'R', &val, 1, off);
return val;
}
static void
outb(int off, uchar v){
uvlong val;
val = v;
amlio(IoSpace, 'W', &val, 1, off);
}
static void
acpiec_wait(uchar mask, uchar val)
{
uchar stat;
while((stat = inb(ec.cmd) & mask) != val) {
//if (stat & Burst)
amldelay(1);
}
}
static uchar
acpiec_read_data(void)
{
acpiec_wait(OutBufFull, OutBufFull);
return inb(ec.data);
}
static void
acpiec_write_data(uchar val)
{
acpiec_wait(InBufFull, 0);
outb(ec.data, val);
}
static void
acpiec_write_cmd(uchar val)
{
acpiec_wait(InBufFull, 0);
outb(ec.cmd, val);
}
static uchar
acpiec_read(uchar addr)
{
if (!ec.ready)
return 0;
acpiec_write_cmd(EcRead);
acpiec_write_data(addr);
return acpiec_read_data();
}
static void
acpiec_write(uchar addr, uvlong val)
{
int i;
uchar *v = (uchar*)&val;
if (!ec.ready)
return;
for(i = 0; i < sizeof(uvlong); i++) {
acpiec_write_cmd(EcWrite);
acpiec_write_data(addr + i); // ?
acpiec_write_data(v[i]);
}
}
int
ecread(Amlio *io, void *p, int, int addr){
//print("ecread addr:%d len:%d\n", (int)io->off + addr, len);
*(uchar*)p = acpiec_read(io->off + addr);
return 1;
}
int
ecwrite(Amlio *io, void *p, int, int addr){
if(((Fileio*)io->aux)->dummy) {
*(char*)p = 0;
return -1;
}
print("ecwrite addr = %d\n", addr);
uvlong val = *(uvlong*)p;
acpiec_write(io->off + addr, val);
return 1;
}
static int
acpiec_getreg(unsigned char *buf, int size, int *type, int *addr)
{
enum { ResTypeMask = 0x80, ResLengthMask = 0x07,
ResTypeIoPort = 0x47, ResTypeEndTag = 0x79 };
enum { SystemIoSpace = 1 };
int len, hlen;
if (size <= 0)
return 0;
if (*buf & ResTypeMask) {
/* large resource */
if (size < 3)
return 1;
len = (int)buf[1] + 256 * (int)buf[2];
hlen = 3;
} else {
/* small resource */
len = buf[0] & ResLengthMask;
hlen = 1;
}
if (*buf != ResTypeIoPort)
return 0;
if (size < hlen + len)
return 0;
*type = SystemIoSpace;
*addr = (int)buf[2] + 256 * (int)buf[3];
return (hlen + len);
}
void
acpiec_init(void *dot, void *tbl)
{
void *m;
char *buf;
void *p;
int gpe;
int rv, size, t;
int ec_sc, ec_data;
struct Ecdt *ecdt = tbl;
struct Amlio *io;
if(ec.ready)
return;
/* we need port I/O working */
if ((io = calloc(1, sizeof(*io))) == nil)
sysfatal("failed to alloc port i/o");
io->space = IoSpace;
if(amlmapio(io) == -1)
sysfatal("Cannot map I/O space");
if(ecdt != nil) {
ecdt = (struct Ecdt*)tbl;
ec_sc = get64(ecdt->ec_cmd.addr);
ec_data = get64(ecdt->ec_data.addr);
gpe = ecdt->gpe;
goto done;
}
if((m = amlwalk(dot, "_GPE")) == 0) {
print("ec: no _GPE\n");
return;
}
if(amleval(m, "", &p) < 0) {
print("ec: _GPE not working\n");
return;
}
gpe = amlint(amlval(p));
if((m = amlwalk(dot, "_CRS")) == 0) {
print("ec: no _CRS\n");
return;
}
if(amleval(m, "", &buf) < 0) {
print("ec: _CRS not working\n");
return;
}
if(amltag(buf) != 'b') {
print("ec: unknown _CRS type\n");
return;
}
size = amllen(buf);
rv = acpiec_getreg(amlval(buf), size, &t, &ec_data);
//print("getreg: rv=%d t=%d ec_data=0x%x\n", rv, t, ec_data);
buf += rv;
size -= rv;
rv = acpiec_getreg(amlval(buf), size, &t, &ec_sc);
//print("getreg: rv=%d t=%d ec_sc=0x%x\n", rv, t, ec_sc);
buf += rv;
size -= rv;
if(size != 2 || *buf != 0x79) {
print("no crs endtag\n");
}
/* register */
enum { RegTypeEC = 3 };
if((m = amlwalk(dot, "_REG")) == 0) {
print("ec: no _REG\n");
return;
}
if(amleval(m, "ii", RegTypeEC, 1, nil) < 0) {
print("ec: _REG not working\n");
return;
}
done:
/* if(ioalloc(ec_data, 1, 0, "ec_data") < 0)
print("ec: ec_data port space in use");
if(ioalloc(ec_sc, 1, 0, "ec_sc") < 0)
print("ec: ec_sc port space in use"); */
print("ec: status: %d gpe: %d data: 0x%x s/c: 0x%x \n",
inb(ec_sc), gpe, ec_data, ec_sc);
ec.cmd = ec_sc;
ec.data = ec_data;
ec.ready = 1;
}