On Fri, 20 Jul 2001, pradeep wrote:

> How do I go about writting an SMBUS user level program , even I am not
> able to find the spec, where can I get it,can any one pls help me.

Suravee, a summer intern here, has found a URL for SMBUS. Suravee can you
post this.

Here is a simple program that reads SMBUS. You need to change some address
parameters (IOPORT for SMBUS) but this thing has worked in the past. I
think we last used it on VIA, but it came from someone who forget to put
their name in it. Basically you patch some of the IO base parameters and
it should work. (I think this might have started with one of the OpenBIOS
guys but I'm not sure. Always put your name in your code :-)




#include <stdio.h>
#include <errno.h>

#include <sys/io.h>

#define cli() __asm__ __volatile__ ("cli" : : : "memory")
#define sti() __asm__ __volatile__ ("sti" : : : "memory")

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

struct pci_ops {
        int (*read_byte)(u8 bus, int devfn, int where, u8 *val);
        int (*read_word)(u8 bus, int devfn, int where, u16 *val);
        int (*read_dword)(u8 bus, int devfn, int where, u32 *val);
        int (*write_byte)(u8 bus, int devfn, int where, u8 val);
        int (*write_word)(u8 bus, int devfn, int where, u16 val);
        int (*write_dword)(u8 bus, int devfn, int where, u32 val);
};

/*
 * Functions for accessing PCI configuration space with type 1 accesses
 */

#define CONFIG_CMD(bus,devfn, where)   (0x80000000 | (bus << 16) | (devfn << 8) | 
(where & ~3))

static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, u8 
*value)
{
        outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
        *value = inb(0xCFC + (where&3));
        return 0;
}

static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, u16 
*value)
{
        outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
        *value = inw(0xCFC + (where&2));
        return 0;
}

static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, u32 
*value)
{
        outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
        *value = inl(0xCFC);
        return 0;
}

static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, u8 
value)
{
        outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
        outb(value, 0xCFC + (where&3));
        return 0;
}

static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, u16 
value)
{
        outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
        outw(value, 0xCFC + (where&2));
        return 0;
}

static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, u32 
value)
{
        outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
        outl(value, 0xCFC);
        return 0;
}

#undef CONFIG_CMD

const struct pci_ops pci_direct_conf1 = {
        pci_conf1_read_config_byte,
        pci_conf1_read_config_word,
        pci_conf1_read_config_dword,
        pci_conf1_write_config_byte,
        pci_conf1_write_config_word,
        pci_conf1_write_config_dword
};


const struct pci_ops *conf = &pci_direct_conf1;

u32 PciReadDword(u8 bus, int devfn, int reg)
{
        u32 val;
        conf->read_dword(bus, devfn, reg, &val);
        return val;
}

u16 PciReadWord(u8 bus, int devfn, int reg)
{
        u16 val;
        conf->read_word(bus, devfn, reg, &val);
        return val;
}

u8 PciReadByte(u8 bus, int devfn, int reg)
{
        u8 val;
        conf->read_byte(bus, devfn, reg, &val);
        return val;
}

void PciWriteDword(u8 bus, int devfn, int reg, u32 val)
{
        conf->write_dword(bus, devfn, reg, val);
}

void PciWriteWord(u8 bus, int devfn, int reg, u16 val)
{
        conf->write_word(bus, devfn, reg, val);
}

void PciWriteByte(u8 bus, int devfn, int reg, u8 val)
{
        conf->write_byte(bus, devfn, reg, val);
}

void pci_setup(void)
{
#if 0
        int fd;
        void *addr;
        fd = open("/dev/mem", O_RDWR);
        if (fd < 0 ) {
                fprintf(stderr, "Can't open /dev/mem!\n");
                exit(1);
        }
        addr = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, xxx);
#endif

        return;
}
void pci_dump(u8 bus, int devfn)
{
        int i;
        unsigned char byte;
        for(i = 0; i < (64 *4); i++) {
                byte = PciReadByte(bus, devfn, i);
                printf("%c", byte);
        }
        exit(0);
}

/* d == 13 == 8 + 4 + 1 */
#define SMBUS_BUS 0
#define SMBUS_DEVFN  ((18 << 3) + 3)
#if 0
#define SMBUS_MEM_DEVICE_1 (0xa << 3)
#endif
#define SMBUS_MEM_DEVICE_1 (0x50)

static struct smbus_info{
        unsigned base;
        unsigned char enable;
        unsigned short func_enable;
} smbus;


void smbus_setup(void)
{
 top:
        smbus.base = PciReadDword(SMBUS_BUS, SMBUS_DEVFN, 0x90);
        smbus.enable = PciReadByte(SMBUS_BUS, SMBUS_DEVFN, 0xD2);
        smbus.func_enable = PciReadWord(SMBUS_BUS, SMBUS_DEVFN, 0x4);
        printf("smbus.base = %08x\n", smbus.base);
        printf("smbus.enable = %02x\n", smbus.enable);
        printf("smbus.func_enable = %04x\n", smbus.func_enable);
        if (!(smbus.enable & 1)) {
                PciWriteDword(SMBUS_BUS, SMBUS_DEVFN, 0x90, 0x1000 | 1);
                PciWriteByte(SMBUS_BUS, SMBUS_DEVFN, 0xD2, (0x4 << 1) | 0x1);
                PciWriteWord(SMBUS_BUS, SMBUS_DEVFN, 0x4, 1);
                goto top;
        }
        smbus.base &= ~1;
        printf("smbus.base = %08x\n", smbus.base);
        printf("smbus.enable = %02x\n", smbus.enable);
        printf("smbus.func_enable = %04x\n", smbus.func_enable);
}

#define SMBHSTSTAT 0
#define SMBHSTCTL  2
#define SMBHSTCMD  3
#define SMBHSTADD  4
#define SMBHSTDAT0 5
#define SMBHSTDAT1 6
#define SMBBLKDAT  7

void smbus_wait_until_ready(void)
{
        while((inb(smbus.base + SMBHSTSTAT) & 1) == 1) {
                /* nop */
        }
}
void smbus_wait_until_done(void)
{
        unsigned char byte;
        do {
                byte = inb(smbus.base + SMBHSTSTAT);
        }
        while((byte &1) == 1);
        while( (byte & (~1)) == 0) {
                byte = inb(smbus.base + SMBHSTSTAT);
        }
}

int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
{
        unsigned char host_control_register;
        unsigned char host_status_register;
        unsigned char byte;
        cli();
        /* save old state */
        host_control_register = inb(smbus.base + SMBHSTCTL);

#if 1
        smbus_wait_until_ready();
#endif

        /* setup transaction */
        /* disable interrupts */
        outb(inb(smbus.base + SMBHSTCTL) & (~1), smbus.base + SMBHSTCTL);
        /* set the device I'm talking too */
        outb(((device & 0x7f) << 1) | 1, smbus.base + SMBHSTADD);
        /* set the command/address... */
        outb(address & 0xFF, smbus.base + SMBHSTCMD);
        /* set up for a byte data read */
        outb((inb(smbus.base + SMBHSTCTL) & 0xE3) | (0x2 << 2), smbus.base + 
SMBHSTCTL);

        /* clear any lingering errors, so the transaction will run */
        outb(inb(smbus.base + SMBHSTSTAT), smbus.base + SMBHSTSTAT);

        /* clear the data byte...*/
        outb(0, smbus.base + SMBHSTDAT0);

        /* start the command */
        outb((inb(smbus.base + SMBHSTCTL) | 0x40), smbus.base + SMBHSTCTL);

        /* poll for transaction completion */
        smbus_wait_until_done();

        host_status_register = inb(smbus.base + SMBHSTSTAT);

        /* read results of transaction */
        byte = inb(smbus.base + SMBHSTDAT0);

        /* restore old state */
        outb(host_control_register, smbus.base + SMBHSTCTL);
        sti();
        *result = byte;
        return host_status_register != 0x02;
}

int main(int argc, char **argv)
{
        unsigned char buffer[256];
        int i, j;
        int status;
        iopl(3);
        pci_setup();
#if 0
        pci_dump(SMBUS_BUS, SMBUS_DEVFN);
#endif
        smbus_setup();

        for(j = 0; j < 4; j++) {
                status = 0;
                printf("bank: %d\n", j);
                for(i = 0; (i < 256) && (status == 0); i++) {
                        if ((i &0x0f)  == 0) {
                                printf("\n");
                        }
                        status = smbus_read_byte(SMBUS_MEM_DEVICE_1 +j, i, &buffer[i]);
                        if (status != 0) {
                                printf("bad device\n");
                                continue;
                        }
                        printf("0x%02x ", buffer[i]);
                }
        }
        printf("\n");
        return 0;
}



Reply via email to