Merge pull request #617 from richardg867/temp
SMBus framework + Winbond W83781D hardware monitor
This commit is contained in:
35
src/hwm.c
Normal file
35
src/hwm.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Common functions for hardware monitor chips.
|
||||
*
|
||||
* Version: @(#)hwm.c 1.0.0 2020/03/22
|
||||
*
|
||||
* Author: RichardG, <richardg867@gmail.com>
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include "hwm.h"
|
||||
|
||||
|
||||
hwm_values_t hwm_values;
|
||||
|
||||
|
||||
void
|
||||
hwm_set_values(hwm_values_t new_values)
|
||||
{
|
||||
hwm_values = new_values;
|
||||
}
|
||||
|
||||
|
||||
hwm_values_t*
|
||||
hwm_get_values()
|
||||
{
|
||||
return &hwm_values;
|
||||
}
|
38
src/hwm.h
Normal file
38
src/hwm.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for the hardware monitor chips.
|
||||
*
|
||||
* Version: @(#)hwm.h 1.0.0 2020/03/21
|
||||
*
|
||||
* Author: RichardG, <richardg867@gmail.com>
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#ifndef EMU_HWM_H
|
||||
# define EMU_HWM_H
|
||||
|
||||
|
||||
#define VDIV(v, r1, r2) (((v) * (r2)) / ((r1) + (r2)))
|
||||
|
||||
|
||||
typedef struct _hwm_values_ {
|
||||
uint16_t fans[4];
|
||||
uint8_t temperatures[4];
|
||||
uint8_t voltages[8];
|
||||
} hwm_values_t;
|
||||
|
||||
|
||||
extern void hwm_set_values(hwm_values_t new_values);
|
||||
extern hwm_values_t* hwm_get_values();
|
||||
|
||||
|
||||
extern const device_t w83781d_device;
|
||||
extern const device_t as99127f_device;
|
||||
|
||||
|
||||
#endif /*EMU_HWM_H*/
|
482
src/hwm_w83781d.c
Normal file
482
src/hwm_w83781d.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Emulation of the Winbond W83781D hardware monitoring chip.
|
||||
*
|
||||
* Version: @(#)hwm_w83781d.c 1.0.0 2020/03/21
|
||||
*
|
||||
* Author: RichardG, <richardg867@gmail.com>
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "86box.h"
|
||||
#include "device.h"
|
||||
#include "86box_io.h"
|
||||
#include "smbus.h"
|
||||
#include "hwm.h"
|
||||
|
||||
|
||||
#define W83781D_SMBUS 0x10000
|
||||
#define W83781D_AS99127F 0x20000
|
||||
#define W83781D_VENDOR_ID ((dev->local & W83781D_AS99127F) ? 0x12C3 : 0x5CA3)
|
||||
|
||||
#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a)))
|
||||
#define W83781D_RPM_TO_REG(r, d) CLAMP(1350000 / (r * d), 1, 255)
|
||||
#define W83781D_TEMP_TO_REG(t) ((t) * 8) << 5
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t local;
|
||||
hwm_values_t* values;
|
||||
|
||||
uint8_t regs[64];
|
||||
uint8_t regs_bank1[6];
|
||||
uint8_t regs_bank2[6];
|
||||
uint8_t addr_register;
|
||||
uint8_t data_register;
|
||||
|
||||
uint8_t smbus_addr_main;
|
||||
uint8_t smbus_addr_temp2;
|
||||
uint8_t smbus_addr_temp3;
|
||||
uint8_t hbacs;
|
||||
uint8_t active_bank;
|
||||
} w83781d_t;
|
||||
|
||||
|
||||
static uint8_t w83781d_isa_read(uint16_t port, void *priv);
|
||||
static uint8_t w83781d_smbus_read_byte(uint8_t addr, void *priv);
|
||||
static uint8_t w83781d_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t w83781d_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint8_t w83781d_read(w83781d_t *dev, uint8_t reg, uint8_t bank);
|
||||
static void w83781d_isa_write(uint16_t port, uint8_t val, void *priv);
|
||||
static void w83781d_smbus_write_byte(uint8_t addr, uint8_t val, void *priv);
|
||||
static void w83781d_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void w83781d_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static uint8_t w83781d_write(w83781d_t *dev, uint8_t reg, uint8_t val, uint8_t bank);
|
||||
static void w83781d_reset(w83781d_t *dev, uint8_t initialization);
|
||||
|
||||
|
||||
static void
|
||||
w83781d_remap(w83781d_t *dev)
|
||||
{
|
||||
if (!(dev->local & W83781D_SMBUS)) return;
|
||||
|
||||
smbus_removehandler(0x00, 0x80,
|
||||
w83781d_smbus_read_byte, w83781d_smbus_read_byte_cmd, w83781d_smbus_read_word_cmd, NULL,
|
||||
w83781d_smbus_write_byte, w83781d_smbus_write_byte_cmd, w83781d_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
if (dev->smbus_addr_main) smbus_sethandler(dev->smbus_addr_main, 1,
|
||||
w83781d_smbus_read_byte, w83781d_smbus_read_byte_cmd, w83781d_smbus_read_word_cmd, NULL,
|
||||
w83781d_smbus_write_byte, w83781d_smbus_write_byte_cmd, w83781d_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
if (dev->smbus_addr_temp2) smbus_sethandler(dev->smbus_addr_temp2, 1,
|
||||
w83781d_smbus_read_byte, w83781d_smbus_read_byte_cmd, w83781d_smbus_read_word_cmd, NULL,
|
||||
w83781d_smbus_write_byte, w83781d_smbus_write_byte_cmd, w83781d_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
if (dev->smbus_addr_temp3) smbus_sethandler(dev->smbus_addr_temp3, 1,
|
||||
w83781d_smbus_read_byte, w83781d_smbus_read_byte_cmd, w83781d_smbus_read_word_cmd, NULL,
|
||||
w83781d_smbus_write_byte, w83781d_smbus_write_byte_cmd, w83781d_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
w83781d_isa_read(uint16_t port, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
uint8_t ret = 0xFF;
|
||||
|
||||
switch (port - (dev->local & 0xFFFF)) {
|
||||
case 0x0:
|
||||
ret = dev->addr_register & 0x7F;
|
||||
break;
|
||||
case 0x1:
|
||||
ret = w83781d_read(dev, dev->addr_register, dev->active_bank);
|
||||
|
||||
if (dev->active_bank == 0 &&
|
||||
(dev->addr_register == 0x41 || dev->addr_register == 0x43 || dev->addr_register == 0x45 || dev->addr_register == 0x56 ||
|
||||
(dev->addr_register >= 0x60 && dev->addr_register < 0x7F))) {
|
||||
/* auto-increment registers */
|
||||
dev->addr_register++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
w83781d_smbus_read_byte(uint8_t addr, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
|
||||
return w83781d_read(dev, dev->addr_register, 0);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
w83781d_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
|
||||
return w83781d_read(dev, cmd, 0);
|
||||
}
|
||||
|
||||
|
||||
static uint16_t
|
||||
w83781d_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
uint8_t rethi = 0;
|
||||
uint8_t retlo = 0;
|
||||
uint8_t bank = 0;
|
||||
|
||||
if (addr == dev->smbus_addr_temp2 || addr == dev->smbus_addr_temp3) {
|
||||
if (addr == dev->smbus_addr_temp2)
|
||||
bank = 2;
|
||||
else
|
||||
bank = 3;
|
||||
|
||||
switch (cmd & 0x3) {
|
||||
case 0x0:
|
||||
rethi = w83781d_read(dev, 0x50, bank);
|
||||
retlo = w83781d_read(dev, 0x51, bank);
|
||||
break;
|
||||
case 0x1:
|
||||
rethi = retlo = w83781d_read(dev, 0x52, bank);
|
||||
break;
|
||||
case 0x2:
|
||||
rethi = w83781d_read(dev, 0x53, bank);
|
||||
retlo = w83781d_read(dev, 0x54, bank);
|
||||
break;
|
||||
case 0x3:
|
||||
rethi = w83781d_read(dev, 0x55, bank);
|
||||
retlo = w83781d_read(dev, 0x56, bank);
|
||||
break;
|
||||
}
|
||||
|
||||
return (retlo << 8) | rethi; /* byte-swapped for some reason */
|
||||
}
|
||||
|
||||
return w83781d_read(dev, cmd, bank);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
w83781d_read(w83781d_t *dev, uint8_t reg, uint8_t bank)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
|
||||
if ((reg >> 4) == 0x5 && bank != 0) {
|
||||
/* bank-switched temperature registers */
|
||||
if (bank == 1)
|
||||
ret = dev->regs_bank1[reg - 0x50];
|
||||
else
|
||||
ret = dev->regs_bank2[reg - 0x50];
|
||||
} else {
|
||||
/* regular registers */
|
||||
if (reg == 0x4F) /* special case for two-byte vendor ID register */
|
||||
ret = dev->hbacs ? (W83781D_VENDOR_ID >> 8) : (W83781D_VENDOR_ID & 0xFF);
|
||||
else if (reg >= 0x60) /* read auto-increment value RAM registers from their non-auto-increment locations */
|
||||
ret = dev->regs[reg - 0x40];
|
||||
else
|
||||
ret = dev->regs[reg - 0x20];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
w83781d_isa_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
|
||||
switch (port - (dev->local & 0xFFFF)) {
|
||||
case 0x0:
|
||||
dev->addr_register = val & 0x7F;
|
||||
break;
|
||||
case 0x1:
|
||||
w83781d_write(dev, dev->addr_register, val, dev->active_bank);
|
||||
|
||||
if (dev->active_bank == 0 &&
|
||||
(dev->addr_register == 0x41 || dev->addr_register == 0x43 || dev->addr_register == 0x45 || dev->addr_register == 0x56 ||
|
||||
(dev->addr_register >= 0x60 && dev->addr_register < 0x7F))) {
|
||||
/* auto-increment registers */
|
||||
dev->addr_register++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
w83781d_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
|
||||
dev->addr_register = val;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
w83781d_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
|
||||
w83781d_write(dev, cmd, val, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
w83781d_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
uint8_t valhi = (val >> 8);
|
||||
uint8_t vallo = (val & 0xFF);
|
||||
uint8_t bank = 0;
|
||||
|
||||
if (addr == dev->smbus_addr_temp2 || addr == dev->smbus_addr_temp3) {
|
||||
if (addr == dev->smbus_addr_temp2)
|
||||
bank = 2;
|
||||
else
|
||||
bank = 3;
|
||||
|
||||
switch (cmd & 0x3) {
|
||||
case 0x0:
|
||||
w83781d_write(dev, 0x50, valhi, bank);
|
||||
w83781d_write(dev, 0x51, vallo, bank);
|
||||
break;
|
||||
case 0x1:
|
||||
w83781d_write(dev, 0x52, vallo, bank);
|
||||
break;
|
||||
case 0x2:
|
||||
w83781d_write(dev, 0x53, valhi, bank);
|
||||
w83781d_write(dev, 0x54, vallo, bank);
|
||||
break;
|
||||
case 0x3:
|
||||
w83781d_write(dev, 0x55, valhi, bank);
|
||||
w83781d_write(dev, 0x56, vallo, bank);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
w83781d_write(dev, cmd, vallo, bank);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
w83781d_write(w83781d_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
|
||||
{
|
||||
uint8_t remap = 0;
|
||||
|
||||
if ((reg >> 4) == 0x5 && bank != 0) {
|
||||
/* bank-switched temperature registers */
|
||||
switch (reg) {
|
||||
case 0x50: case 0x51:
|
||||
/* read-only registers */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bank == 1)
|
||||
dev->regs_bank1[reg - 0x50] = val;
|
||||
else
|
||||
dev->regs_bank2[reg - 0x50] = val;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* regular registers */
|
||||
switch (reg) {
|
||||
case 0x41: case 0x42: case 0x4F: case 0x58:
|
||||
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A:
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A:
|
||||
/* read-only registers */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (reg >= 0x60) /* write auto-increment value RAM registers to their non-auto-increment locations */
|
||||
dev->regs[reg - 0x40] = val;
|
||||
else
|
||||
dev->regs[reg - 0x20] = val;
|
||||
|
||||
switch (reg) {
|
||||
case 0x40:
|
||||
if (val >> 7) {
|
||||
/* INITIALIZATION bit set: reset all registers except main SMBus address */
|
||||
w83781d_reset(dev, 1);
|
||||
}
|
||||
break;
|
||||
case 0x47:
|
||||
/* update FAN1/FAN2 values to match the new divisor */
|
||||
dev->regs[0x08] = W83781D_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x27] >> 4) & 0x3));
|
||||
dev->regs[0x09] = W83781D_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x27] >> 6) & 0x3));
|
||||
break;
|
||||
case 0x48:
|
||||
if (dev->local & W83781D_SMBUS) {
|
||||
dev->smbus_addr_main = (dev->regs[0x28] & 0x7F);
|
||||
remap = 1;
|
||||
}
|
||||
break;
|
||||
case 0x4A:
|
||||
if (dev->local & W83781D_SMBUS) {
|
||||
/* DIS_T2 and DIS_T3 bits can disable those interfaces */
|
||||
if ((dev->regs[0x2A] >> 3) & 0x1)
|
||||
dev->smbus_addr_temp2 = 0x00;
|
||||
else
|
||||
dev->smbus_addr_temp2 = 0x48 + (dev->regs[0x2A] & 0x7);
|
||||
if (dev->regs[0x2A] >> 7)
|
||||
dev->smbus_addr_temp3 = 0x00;
|
||||
else
|
||||
dev->smbus_addr_temp3 = 0x48 + ((dev->regs[0x2A] >> 4) & 0x7);
|
||||
remap = 1;
|
||||
}
|
||||
break;
|
||||
case 0x4B:
|
||||
/* update FAN3 value to match the new divisor */
|
||||
dev->regs[0x0A] = W83781D_RPM_TO_REG(dev->values->fans[2], 1 << ((dev->regs[0x2B] >> 6) & 0x3));
|
||||
break;
|
||||
case 0x4E:
|
||||
dev->hbacs = (dev->regs[0x2E] & 0x80);
|
||||
/* FIXME: Winbond's datasheet does not specify how BANKSEL[0:2] work */
|
||||
if (dev->regs[0x2E] & 0x1)
|
||||
dev->active_bank = 0;
|
||||
else if (dev->regs[0x2E] & 0x2)
|
||||
dev->active_bank = 1;
|
||||
else if (dev->regs[0x2E] & 0x4)
|
||||
dev->active_bank = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (remap)
|
||||
w83781d_remap(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
w83781d_reset(w83781d_t *dev, uint8_t initialization)
|
||||
{
|
||||
memset(dev->regs, 0, 64);
|
||||
memset(dev->regs_bank1, 0, 6);
|
||||
memset(dev->regs_bank2, 0, 6);
|
||||
|
||||
/* WARNING: Array elements are register - 0x20. */
|
||||
uint8_t i;
|
||||
for (i = 0; i <= 6; i++)
|
||||
dev->regs[i] = dev->values->voltages[i];
|
||||
dev->regs[0x07] = dev->values->temperatures[0];
|
||||
for (i = 0; i <= 2; i++)
|
||||
dev->regs[0x08 + i] = W83781D_RPM_TO_REG(dev->values->fans[i], 2);
|
||||
dev->regs[0x20] = 0x01;
|
||||
dev->regs[0x26] = 0x40;
|
||||
dev->regs[0x27] = 0x50;
|
||||
if (dev->local & W83781D_SMBUS) {
|
||||
if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */
|
||||
dev->smbus_addr_main = 0x2D;
|
||||
dev->regs[0x28] = dev->smbus_addr_main;
|
||||
dev->regs[0x2A] = 0x01;
|
||||
dev->smbus_addr_temp2 = 0x48 + (dev->regs[0x2A] & 0x7);
|
||||
dev->smbus_addr_temp3 = 0x48 + ((dev->regs[0x2A] >> 4) & 0x7);
|
||||
} else {
|
||||
dev->regs[0x28] = 0x00;
|
||||
dev->regs[0x2A] = 0x88;
|
||||
dev->smbus_addr_temp2 = dev->smbus_addr_temp3 = 0x00;
|
||||
}
|
||||
dev->regs[0x29] = 0x02;
|
||||
dev->regs[0x2B] = 0x44;
|
||||
dev->regs[0x2C] = 0x01;
|
||||
dev->regs[0x2D] = 0x15;
|
||||
dev->regs[0x2E] = 0x80;
|
||||
dev->hbacs = (dev->regs[0x2E] & 0x80);
|
||||
dev->regs[0x2F] = W83781D_VENDOR_ID >> 8;
|
||||
dev->regs[0x37] = 0x80;
|
||||
dev->regs[0x38] = (dev->local & W83781D_AS99127F) ? 0x31 : 0x10;
|
||||
|
||||
/* WARNING: Array elements are register - 0x50. */
|
||||
uint16_t temp;
|
||||
temp = W83781D_TEMP_TO_REG(dev->values->temperatures[1]);
|
||||
dev->regs_bank1[0x0] = temp >> 8;
|
||||
dev->regs_bank1[0x1] = temp & 0xFF;
|
||||
dev->regs_bank1[0x3] = 0x4B;
|
||||
dev->regs_bank1[0x5] = 0x50;
|
||||
temp = W83781D_TEMP_TO_REG(dev->values->temperatures[2]);
|
||||
dev->regs_bank2[0x0] = temp >> 8;
|
||||
dev->regs_bank2[0x1] = temp & 0xFF;
|
||||
dev->regs_bank2[0x3] = 0x4B;
|
||||
dev->regs_bank2[0x5] = 0x50;
|
||||
|
||||
w83781d_remap(dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
w83781d_close(void *priv)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) priv;
|
||||
|
||||
uint16_t isa_io = dev->local & 0xFFFF;
|
||||
if (isa_io)
|
||||
io_removehandler(isa_io, 2, w83781d_isa_read, NULL, NULL, w83781d_isa_write, NULL, NULL, dev);
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
w83781d_init(const device_t *info)
|
||||
{
|
||||
w83781d_t *dev = (w83781d_t *) malloc(sizeof(w83781d_t));
|
||||
memset(dev, 0, sizeof(w83781d_t));
|
||||
|
||||
dev->local = info->local;
|
||||
dev->values = hwm_get_values();
|
||||
w83781d_reset(dev, 0);
|
||||
|
||||
uint16_t isa_io = dev->local & 0xFFFF;
|
||||
if (isa_io)
|
||||
io_sethandler(isa_io, 2, w83781d_isa_read, NULL, NULL, w83781d_isa_write, NULL, NULL, dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
const device_t w83781d_device = {
|
||||
"Winbond W83781D Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
0x295 | W83781D_SMBUS,
|
||||
w83781d_init, w83781d_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ASUS rebadged version of the W83781D.
|
||||
* Some claim it's SMBus-only, yet the BIOS clearly reads most values over ISA,
|
||||
* except TEMP3 (CPU Temperature) which is read over SMBus.
|
||||
*/
|
||||
const device_t as99127f_device = {
|
||||
"ASUS AS99127F Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
0x295 | W83781D_SMBUS | W83781D_AS99127F,
|
||||
w83781d_init, w83781d_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
153
src/intel_piix.c
153
src/intel_piix.c
@@ -46,6 +46,7 @@
|
||||
#include "hdc_ide_sff8038i.h"
|
||||
#include "zip.h"
|
||||
#include "machine.h"
|
||||
#include "smbus.h"
|
||||
#include "piix.h"
|
||||
|
||||
|
||||
@@ -87,11 +88,12 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t stat, ctl, cmd, addr,
|
||||
uint8_t stat, next_stat, ctl, cmd, addr,
|
||||
data0, data1,
|
||||
index,
|
||||
data[32];
|
||||
} smbus_t;
|
||||
pc_timer_t command_timer;
|
||||
} piix_smbus_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
@@ -107,7 +109,7 @@ typedef struct
|
||||
sff8038i_t *bm[2];
|
||||
ddma_t ddma[2];
|
||||
power_t power;
|
||||
smbus_t smbus;
|
||||
piix_smbus_t smbus;
|
||||
nvr_t * nvr;
|
||||
} piix_t;
|
||||
|
||||
@@ -457,17 +459,145 @@ power_update_io_mapping(piix_t *dev)
|
||||
|
||||
|
||||
static uint8_t
|
||||
smbus_reg_read(uint16_t addr, void *p)
|
||||
smbus_reg_read(uint16_t addr, void *priv)
|
||||
{
|
||||
piix_t *dev = (piix_t *) priv;
|
||||
uint8_t ret = 0x00;
|
||||
|
||||
switch (addr - dev->smbus_io_base) {
|
||||
case 0x00:
|
||||
ret = dev->smbus.stat;
|
||||
break;
|
||||
case 0x02:
|
||||
dev->smbus.index = 0;
|
||||
ret = dev->smbus.ctl;
|
||||
break;
|
||||
case 0x03:
|
||||
ret = dev->smbus.cmd;
|
||||
break;
|
||||
case 0x04:
|
||||
ret = dev->smbus.addr;
|
||||
break;
|
||||
case 0x05:
|
||||
ret = dev->smbus.data0;
|
||||
break;
|
||||
case 0x06:
|
||||
ret = dev->smbus.data1;
|
||||
break;
|
||||
case 0x07:
|
||||
ret = dev->smbus.data[dev->smbus.index++];
|
||||
if (dev->smbus.index > 31)
|
||||
dev->smbus.index = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// pclog("smbus_reg_read %02x %02x\n", addr - dev->smbus_io_base, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
smbus_reg_write(uint16_t addr, uint8_t val, void *p)
|
||||
smbus_reg_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
piix_t *dev = (piix_t *) priv;
|
||||
uint8_t smbus_addr;
|
||||
uint8_t smbus_read;
|
||||
uint16_t temp;
|
||||
|
||||
// pclog("smbus_reg_write %02x %02x\n", addr - dev->smbus_io_base, val);
|
||||
|
||||
dev->smbus.next_stat = 0;
|
||||
switch (addr - dev->smbus_io_base) {
|
||||
case 0x00:
|
||||
/* some status bits are reset by writing 1 to them */
|
||||
for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr = smbus_addr << 1) {
|
||||
if (val & smbus_addr)
|
||||
dev->smbus.stat = dev->smbus.stat & ~smbus_addr;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
dev->smbus.ctl = val & ~(0x40); /* START always reads 0 */
|
||||
if (val & 0x40) { /* dispatch command if START is set */
|
||||
smbus_addr = (dev->smbus.addr >> 1);
|
||||
if (!smbus_has_device(smbus_addr)) {
|
||||
/* raise DEV_ERR if no device is at this address */
|
||||
dev->smbus.next_stat = 0x4;
|
||||
break;
|
||||
}
|
||||
smbus_read = (dev->smbus.addr & 0x01);
|
||||
|
||||
switch ((val >> 2) & 0x7) {
|
||||
case 0x0: /* quick R/W */
|
||||
dev->smbus.next_stat = 0x2;
|
||||
break;
|
||||
case 0x1: /* byte R/W */
|
||||
if (smbus_read)
|
||||
dev->smbus.data0 = smbus_read_byte(smbus_addr);
|
||||
else
|
||||
smbus_write_byte(smbus_addr, dev->smbus.data0);
|
||||
dev->smbus.next_stat = 0x2;
|
||||
break;
|
||||
case 0x2: /* byte data R/W */
|
||||
if (smbus_read)
|
||||
dev->smbus.data0 = smbus_read_byte_cmd(smbus_addr, dev->smbus.cmd);
|
||||
else
|
||||
smbus_write_byte_cmd(smbus_addr, dev->smbus.cmd, dev->smbus.data0);
|
||||
dev->smbus.next_stat = 0x2;
|
||||
break;
|
||||
case 0x3: /* word data R/W */
|
||||
if (smbus_read) {
|
||||
temp = smbus_read_word_cmd(smbus_addr, dev->smbus.cmd);
|
||||
dev->smbus.data0 = (temp & 0xFF);
|
||||
dev->smbus.data1 = (temp >> 8);
|
||||
} else {
|
||||
temp = (dev->smbus.data1 << 8) | dev->smbus.data0;
|
||||
smbus_write_word_cmd(smbus_addr, dev->smbus.cmd, temp);
|
||||
}
|
||||
dev->smbus.next_stat = 0x2;
|
||||
break;
|
||||
case 0x5: /* block R/W */
|
||||
if (smbus_read)
|
||||
dev->smbus.data0 = smbus_read_block_cmd(smbus_addr, dev->smbus.cmd, dev->smbus.data);
|
||||
else
|
||||
smbus_write_block_cmd(smbus_addr, dev->smbus.cmd, dev->smbus.data, dev->smbus.data0);
|
||||
dev->smbus.next_stat = 0x2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
dev->smbus.cmd = val;
|
||||
break;
|
||||
case 0x04:
|
||||
dev->smbus.addr = val;
|
||||
break;
|
||||
case 0x05:
|
||||
dev->smbus.data0 = val;
|
||||
break;
|
||||
case 0x06:
|
||||
dev->smbus.data1 = val;
|
||||
break;
|
||||
case 0x07:
|
||||
dev->smbus.data[dev->smbus.index++] = val;
|
||||
if (dev->smbus.index > 31)
|
||||
dev->smbus.index = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->smbus.next_stat) {
|
||||
dev->smbus.stat = 0x1;
|
||||
timer_disable(&dev->smbus.command_timer);
|
||||
timer_set_delay_u64(&dev->smbus.command_timer, 10 * TIMER_USEC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
smbus_inter(void *priv)
|
||||
{
|
||||
piix_t *dev = (piix_t *) priv;
|
||||
dev->smbus.stat = dev->smbus.next_stat;
|
||||
}
|
||||
|
||||
|
||||
@@ -1173,6 +1303,19 @@ static void
|
||||
/* Bit 2: 0 = On-board audio absent, 1 = On-board audio present. */
|
||||
dev->board_config[1] = 0x64;
|
||||
|
||||
smbus_init();
|
||||
dev->smbus.stat = 0;
|
||||
dev->smbus.ctl = 0;
|
||||
dev->smbus.cmd = 0;
|
||||
dev->smbus.addr = 0;
|
||||
dev->smbus.data0 = 0;
|
||||
dev->smbus.data1 = 0;
|
||||
dev->smbus.index = 0;
|
||||
int i;
|
||||
for (i = 0; i < 32; i++)
|
||||
dev->smbus.data[i] = 0;
|
||||
timer_add(&dev->smbus.command_timer, smbus_inter, dev, 0);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,9 @@
|
||||
#include "piix.h"
|
||||
#include "sio.h"
|
||||
#include "sst_flash.h"
|
||||
#include "hwm.h"
|
||||
#include "video.h"
|
||||
#include "cpu.h"
|
||||
#include "machine.h"
|
||||
|
||||
|
||||
@@ -166,6 +168,33 @@ machine_at_p2bls_init(const machine_t *model)
|
||||
device_add(&w83977ef_device);
|
||||
device_add(&sst_flash_39sf020_device);
|
||||
|
||||
hwm_values_t machine_hwm = {
|
||||
{ /* fan speeds */
|
||||
3000, /* Chassis */
|
||||
3000, /* CPU */
|
||||
3000, /* Power */
|
||||
0
|
||||
}, { /* temperatures */
|
||||
30, /* MB */
|
||||
0, /* unused */
|
||||
27, /* CPU */
|
||||
0
|
||||
}, { /* voltages (divisors other than 16 = unclear how that number was achieved) */
|
||||
2800 / 16, /* VCORE (2.8V by default) */
|
||||
0, /* unused */
|
||||
3300 / 16, /* +3.3V */
|
||||
5000 / 27, /* +5V */
|
||||
VDIV(12000, 28, 10) / 16, /* +12V (with 28K/10K resistor divider suggested in the W83781D datasheet) */
|
||||
12000 / 55, /* -12V */
|
||||
5000 / 24, /* -5V */
|
||||
0
|
||||
}
|
||||
};
|
||||
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2D)
|
||||
machine_hwm.voltages[0] = 2050 / 16; /* set lower VCORE (2.05V) for Deschutes */
|
||||
hwm_set_values(machine_hwm);
|
||||
device_add(&as99127f_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
410
src/smbus.c
Normal file
410
src/smbus.c
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implement SMBus (System Management Bus) and its operations.
|
||||
*
|
||||
* Version: @(#)smbus.c 1.0.0 2020/03/21
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "86box.h"
|
||||
#include "smbus.h"
|
||||
|
||||
|
||||
#define NADDRS 128 /* SMBus supports 128 addresses */
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
|
||||
typedef struct _smbus_ {
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv);
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv);
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv);
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv);
|
||||
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv);
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv);
|
||||
|
||||
void *priv;
|
||||
|
||||
struct _smbus_ *prev, *next;
|
||||
} smbus_t;
|
||||
|
||||
int smbus_initialized = 0;
|
||||
smbus_t *smbus[NADDRS], *smbus_last[NADDRS];
|
||||
|
||||
#define ENABLE_SMBUS_LOG 1
|
||||
#ifdef ENABLE_SMBUS_LOG
|
||||
int smbus_do_log = ENABLE_SMBUS_LOG;
|
||||
|
||||
|
||||
static void
|
||||
smbus_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (smbus_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define smbus_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ENABLE_SMBUS_LOG
|
||||
static uint8_t smbus_null_read_byte(uint8_t addr, void *priv) { smbus_log("SMBus: read_byte(%02x)\n", addr); return(0xff); }
|
||||
static uint8_t smbus_null_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) { smbus_log("SMBus: read_byte_cmd(%02x, %02x)\n", addr, cmd); return(0xff); }
|
||||
static uint16_t smbus_null_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) { smbus_log("SMBus: read_word_cmd(%02x, %02x)\n", addr, cmd); return(0xffff); }
|
||||
static uint8_t smbus_null_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv) { smbus_log("SMBus: read_block_cmd(%02x, %02x)\n", addr, cmd); return(0x00); };
|
||||
static void smbus_null_write_byte(uint8_t addr, uint8_t val, void *priv) { smbus_log("SMBus: write_byte(%02x, %02x)\n", addr, val); }
|
||||
static void smbus_null_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) { smbus_log("SMBus: write_byte_cmd(%02x, %02x, %02x)\n", addr, cmd, val); }
|
||||
static void smbus_null_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) { smbus_log("SMBus: write_word_cmd(%02x, %02x, %04x)\n", addr, cmd, val); }
|
||||
static void smbus_null_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) { smbus_log("SMBus: write_block_cmd(%02x, %02x, %02x)\n", addr, cmd, len); }
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
smbus_init(void)
|
||||
{
|
||||
int c;
|
||||
smbus_t *p, *q;
|
||||
|
||||
if (!smbus_initialized) {
|
||||
for (c=0; c<NADDRS; c++)
|
||||
smbus[c] = smbus_last[c] = NULL;
|
||||
smbus_initialized = 1;
|
||||
}
|
||||
|
||||
for (c=0; c<NADDRS; c++) {
|
||||
if (smbus_last[c]) {
|
||||
/* Address c has at least one handler. */
|
||||
p = smbus_last[c];
|
||||
/* After this loop, p will have the pointer to the first handler. */
|
||||
while (p) {
|
||||
q = p->prev;
|
||||
free(p);
|
||||
p = q;
|
||||
}
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SMBUS_LOG
|
||||
/* smbus[c] should be the only handler, pointing at the NULL catch handler. */
|
||||
p = (smbus_t *) malloc(sizeof(smbus_t));
|
||||
memset(p, 0, sizeof(smbus_t));
|
||||
smbus[c] = smbus_last[c] = p;
|
||||
p->next = NULL;
|
||||
p->prev = NULL;
|
||||
p->read_byte = smbus_null_read_byte;
|
||||
p->read_byte_cmd = smbus_null_read_byte_cmd;
|
||||
p->read_word_cmd = smbus_null_read_word_cmd;
|
||||
p->read_block_cmd = smbus_null_read_block_cmd;
|
||||
p->write_byte = smbus_null_write_byte;
|
||||
p->write_byte_cmd = smbus_null_write_byte_cmd;
|
||||
p->write_word_cmd = smbus_null_write_word_cmd;
|
||||
p->write_block_cmd = smbus_null_write_block_cmd;
|
||||
p->priv = NULL;
|
||||
#else
|
||||
/* smbus[c] should be NULL. */
|
||||
smbus[c] = smbus_last[c] = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
smbus_sethandler(uint8_t base, int size,
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv),
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv),
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv),
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
|
||||
void *priv)
|
||||
{
|
||||
int c;
|
||||
smbus_t *p, *q = NULL;
|
||||
|
||||
for (c = 0; c < size; c++) {
|
||||
p = smbus_last[base + c];
|
||||
q = (smbus_t *) malloc(sizeof(smbus_t));
|
||||
memset(q, 0, sizeof(smbus_t));
|
||||
if (p) {
|
||||
p->next = q;
|
||||
q->prev = p;
|
||||
} else {
|
||||
smbus[base + c] = q;
|
||||
q->prev = NULL;
|
||||
}
|
||||
|
||||
q->read_byte = read_byte;
|
||||
q->read_byte_cmd = read_byte_cmd;
|
||||
q->read_word_cmd = read_word_cmd;
|
||||
q->read_block_cmd = read_block_cmd;
|
||||
|
||||
q->write_byte = write_byte;
|
||||
q->write_byte_cmd = write_byte_cmd;
|
||||
q->write_word_cmd = write_word_cmd;
|
||||
q->write_block_cmd = write_block_cmd;
|
||||
|
||||
q->priv = priv;
|
||||
q->next = NULL;
|
||||
|
||||
smbus_last[base + c] = q;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
smbus_removehandler(uint8_t base, int size,
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv),
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv),
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv),
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
|
||||
void *priv)
|
||||
{
|
||||
int c;
|
||||
smbus_t *p;
|
||||
|
||||
for (c = 0; c < size; c++) {
|
||||
p = smbus[base + c];
|
||||
if (!p)
|
||||
continue;
|
||||
while(p) {
|
||||
if ((p->read_byte == read_byte) && (p->read_byte_cmd == read_byte_cmd) &&
|
||||
(p->read_word_cmd == read_word_cmd) && (p->read_block_cmd == read_block_cmd) &&
|
||||
(p->write_byte == write_byte) && (p->write_byte_cmd == write_byte_cmd) &&
|
||||
(p->write_word_cmd == write_word_cmd) && (p->write_block_cmd == write_block_cmd) &&
|
||||
(p->priv == priv)) {
|
||||
if (p->prev)
|
||||
p->prev->next = p->next;
|
||||
else
|
||||
smbus[base + c] = p->next;
|
||||
if (p->next)
|
||||
p->next->prev = p->prev;
|
||||
else
|
||||
smbus_last[base + c] = p->prev;
|
||||
free(p);
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
smbus_handler(int set, uint8_t base, int size,
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv),
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv),
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv),
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
|
||||
void *priv)
|
||||
{
|
||||
if (set)
|
||||
smbus_sethandler(base, size, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv);
|
||||
else
|
||||
smbus_removehandler(base, size, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv);
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
smbus_has_device(uint8_t addr)
|
||||
{
|
||||
return(!!smbus[addr]);
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
smbus_read_byte(uint8_t addr)
|
||||
{
|
||||
uint8_t ret = 0xff;
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
p = smbus[addr];
|
||||
if (p) {
|
||||
while(p) {
|
||||
if (p->read_byte) {
|
||||
ret &= p->read_byte(addr, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
smbus_read_byte_cmd(uint8_t addr, uint8_t cmd)
|
||||
{
|
||||
uint8_t ret = 0xff;
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
p = smbus[addr];
|
||||
if (p) {
|
||||
while(p) {
|
||||
if (p->read_byte_cmd) {
|
||||
ret &= p->read_byte_cmd(addr, cmd, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
smbus_read_word_cmd(uint8_t addr, uint8_t cmd)
|
||||
{
|
||||
uint16_t ret = 0xffff;
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
p = smbus[addr];
|
||||
if (p) {
|
||||
while(p) {
|
||||
if (p->read_word_cmd) {
|
||||
ret &= p->read_word_cmd(addr, cmd, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
smbus_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
p = smbus[addr];
|
||||
if (p) {
|
||||
while(p) {
|
||||
if (p->read_block_cmd) {
|
||||
ret = MAX(ret, p->read_block_cmd(addr, cmd, data, p->priv));
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
smbus_write_byte(uint8_t addr, uint8_t val)
|
||||
{
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
if (smbus[addr]) {
|
||||
p = smbus[addr];
|
||||
while(p) {
|
||||
if (p->write_byte) {
|
||||
p->write_byte(addr, val, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val)
|
||||
{
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
if (smbus[addr]) {
|
||||
p = smbus[addr];
|
||||
while(p) {
|
||||
if (p->write_byte_cmd) {
|
||||
p->write_byte_cmd(addr, cmd, val, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val)
|
||||
{
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
if (smbus[addr]) {
|
||||
p = smbus[addr];
|
||||
while(p) {
|
||||
if (p->write_word_cmd) {
|
||||
p->write_word_cmd(addr, cmd, val, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
smbus_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len)
|
||||
{
|
||||
smbus_t *p;
|
||||
int found = 0;
|
||||
|
||||
p = smbus[addr];
|
||||
if (p) {
|
||||
while(p) {
|
||||
if (p->write_block_cmd) {
|
||||
p->write_block_cmd(addr, cmd, data, len, p->priv);
|
||||
found++;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
67
src/smbus.h
Normal file
67
src/smbus.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for the SMBus handler.
|
||||
*
|
||||
* Version: @(#)smbus.h 1.0.0 2020/03/21
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#ifndef EMU_SMBUS_H
|
||||
# define EMU_SMBUS_H
|
||||
|
||||
|
||||
extern void smbus_init(void);
|
||||
|
||||
extern void smbus_sethandler(uint8_t base, int size,
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv),
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv),
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv),
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
|
||||
void *priv);
|
||||
|
||||
extern void smbus_removehandler(uint8_t base, int size,
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv),
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv),
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv),
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
|
||||
void *priv);
|
||||
|
||||
extern void smbus_handler(int set, uint8_t base, int size,
|
||||
uint8_t (*read_byte)(uint8_t addr, void *priv),
|
||||
uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv),
|
||||
uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, void *priv),
|
||||
void (*write_byte)(uint8_t addr, uint8_t val, void *priv),
|
||||
void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
|
||||
void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
|
||||
void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
|
||||
void *priv);
|
||||
|
||||
extern uint8_t smbus_has_device(uint8_t addr);
|
||||
extern uint8_t smbus_read_byte(uint8_t addr);
|
||||
extern uint8_t smbus_read_byte_cmd(uint8_t addr, uint8_t cmd);
|
||||
extern uint16_t smbus_read_word_cmd(uint8_t addr, uint8_t cmd);
|
||||
extern uint8_t smbus_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data);
|
||||
extern void smbus_write_byte(uint8_t addr, uint8_t val);
|
||||
extern void smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val);
|
||||
extern void smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val);
|
||||
extern void smbus_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len);
|
||||
|
||||
|
||||
#endif /*EMU_SMBUS_H*/
|
@@ -597,7 +597,7 @@ MCHOBJ := machine.o machine_table.o \
|
||||
m_at_286_386sx.o m_at_386dx_486.o \
|
||||
m_at_socket4_5.o m_at_socket7_s7.o
|
||||
|
||||
DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \
|
||||
DEVOBJ := bugger.o hwm.o hwm_w83781d.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \
|
||||
sio_acc3221.o \
|
||||
sio_fdc37c66x.o sio_fdc37c669.o \
|
||||
sio_fdc37c93x.o \
|
||||
@@ -605,6 +605,7 @@ DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \
|
||||
sio_w83787f.o \
|
||||
sio_w83877f.o sio_w83977f.o \
|
||||
sio_um8669f.o \
|
||||
smbus.o \
|
||||
keyboard.o \
|
||||
keyboard_xt.o keyboard_at.o \
|
||||
gameport.o \
|
||||
|
@@ -602,7 +602,7 @@ MCHOBJ := machine.o machine_table.o \
|
||||
m_at_286_386sx.o m_at_386dx_486.o \
|
||||
m_at_socket4_5.o m_at_socket7_s7.o
|
||||
|
||||
DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \
|
||||
DEVOBJ := bugger.o hwm.o hwm_w83781d.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \
|
||||
sio_acc3221.o \
|
||||
sio_fdc37c66x.o sio_fdc37c669.o \
|
||||
sio_fdc37c93x.o \
|
||||
@@ -610,6 +610,7 @@ DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \
|
||||
sio_w83787f.o \
|
||||
sio_w83877f.o sio_w83977f.o \
|
||||
sio_um8669f.o \
|
||||
smbus.o \
|
||||
keyboard.o \
|
||||
keyboard_xt.o keyboard_at.o \
|
||||
gameport.o \
|
||||
|
Reference in New Issue
Block a user