jehanne/sys/src/kern/amd64/ec.c

175 lines
2.5 KiB
C

/*
* 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 uint8_t
ecrr(int reg)
{
return inb(ec.port[reg]);
}
static void
ecwr(int reg, uint8_t val)
{
outb(ec.port[reg], val);
}
static int
ecwait(uint8_t mask, uint8_t 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());
return -1;
}
int
ecread(uint8_t addr)
{
int r;
r = -1;
lock(&ec);
if(!ec.init)
goto out;
if(ecwait(IBF, 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(uint8_t addr, uint8_t val)
{
int r;
r = -1;
lock(&ec);
if(!ec.init)
goto out;
if(ecwait(IBF, 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;
}
static long
ecarchread(Chan* _, void *a, long n, int64_t off)
{
int port, v;
uint8_t *p;
if(off < 0 || off >= 256)
return 0;
if(off+n > 256)
n = 256 - off;
p = a;
for(port = off; port < off+n; port++){
if((v = ecread(port)) < 0)
error(Eio);
*p++ = v;
}
return n;
}
static long
ecarchwrite(Chan* _, void *a, long n, int64_t off)
{
int port;
uint8_t *p;
if(off < 0 || off+n > 256)
error(Ebadarg);
p = a;
for(port = off; port < off+n; port++)
if(ecwrite(port, *p++) < 0)
error(Eio);
return n;
}
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);
addarchfile("ec", 0660, ecarchread, ecarchwrite);
return 0;
}