#include <sys/param.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <dev/ic/mc146818reg.h>
#define NVRAM_CSUM_START (MC_NVRAM_START + 2)
#define NVRAM_CSUM_END (MC_NVRAM_START + 31)
#define NVRAM_CSUM_LOC (MC_NVRAM_START + 32)
#define NVRAM_SIZE (128 - MC_NVRAM_START)
void nvramattach(int);
int nvramopen(dev_t dev, int flag, int mode, struct proc *p);
int nvramclose(dev_t dev, int flag, int mode, struct proc *p);
int nvramread(dev_t dev, struct uio *uio, int flags);
int nvram_csum_valid(void);
int nvram_get_byte(int byteno);
static int nvram_initialized;
void
nvramattach(int num)
{
if (num > 1)
return;
if (nvram_initialized || nvram_csum_valid()) {
#ifdef NVRAM_DEBUG
printf("nvram: initialized\n");
#endif
nvram_initialized = 1;
}
}
int
nvramopen(dev_t dev, int flag, int mode, struct proc *p)
{
if ((minor(dev) != 0) || (!nvram_initialized))
return (ENXIO);
if ((flag & FWRITE))
return (EPERM);
return (0);
}
int
nvramclose(dev_t dev, int flag, int mode, struct proc *p)
{
return (0);
}
int
nvramread(dev_t dev, struct uio *uio, int flags)
{
u_char buf[NVRAM_SIZE];
off_t pos = uio->uio_offset;
u_char *tmp;
size_t count = ulmin(sizeof(buf), uio->uio_resid);
int ret;
if (!nvram_initialized)
return (ENXIO);
if (uio->uio_offset < 0)
return (EINVAL);
if (uio->uio_resid == 0)
return (0);
#ifdef NVRAM_DEBUG
printf("attempting to read %zu bytes at offset %lld\n", count, pos);
#endif
for (tmp = buf; count-- > 0 && pos < NVRAM_SIZE; ++pos, ++tmp)
*tmp = nvram_get_byte(pos);
#ifdef NVRAM_DEBUG
printf("nvramread read %td bytes (%s)\n", (tmp - buf), tmp);
#endif
ret = uiomove(buf, (tmp - buf), uio);
uio->uio_offset += uio->uio_resid;
return (ret);
}
int
nvram_get_byte(int byteno)
{
if (!nvram_initialized)
return (ENXIO);
return (mc146818_read(NULL, byteno + MC_NVRAM_START) & 0xff);
}
int
nvram_csum_valid(void)
{
u_short csum = 0;
u_short csumexpect;
int nreg;
for (nreg = NVRAM_CSUM_START; nreg <= NVRAM_CSUM_END; nreg++)
csum += mc146818_read(NULL, nreg);
csumexpect = mc146818_read(NULL, NVRAM_CSUM_LOC) << 8 |
mc146818_read(NULL, NVRAM_CSUM_LOC + 1);
#ifdef NVRAM_DEBUG
printf("nvram: checksum is %x, expecting %x\n", (csum & 0xffff),
csumexpect);
#endif
return ((csum & 0xffff) == csumexpect);
}