Logo Search packages:      
Sourcecode: xmbmon version File versions  Download package

smbus_piix4.c

/* SMB handling routines for PIIX4, by YRS 2001.08.
      Information on how to access SMBus is provided
      by ":p araffin.(Yoneya)", MANY THANKS!!

      Common to PIIX4, ICHx, VIA686/VT8233

      SMBus IO method:

      smb_base  : Base Address
      addr      : Slave Device Address
      cmd       : Command Register 

      Note that SMBus Slave Device Address is totall 1byte data,
      whose upper 7bits is for address and the lowest bit for read (=1)
      and for write (=0).
      The input "addr" in the following routines is this 1byte data,
      where the lowest bit can be either 0 or 1.

            7             0
           +-+-+-+-+-+-+-+-+
           | Slave addr. |f|    f = 0 for write, =1 for read.
           +-+-+-+-+-+-+-+-+

      Do not confuse "Slave address" which is "addr(here)"/2!

 */

#ifdef SMB_DEBUG
extern int debug_flag;
#include <stdio.h>
#endif

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>

#include "smbuses.h"
#include "io_cpu.h"

#define LSB       0x01

#define LOOP_COUNT      0x2000

/* command address */
#define SMBHSTS   0x0
#define SMBHCTRL  0x2
#define SMBHCMD   0x3
#define SMBHADDR  0x4
#define SMBHDATA0 0x5
#define SMBHDATA1 0x6

/* status flag */
#define SMBHSTS_FAILED  0x10  /* failed bus transaction */
#define SMBHSTS_COLLID  0x08  /* bus collision */
#define SMBHSTS_ERROR   0x04  /* device error */
#define SMBHSTS_DONE    0x02  /* command completed */
#define SMBHSTS_BUSY    0x01  /* host busy */
#define SMBHSTS_CLEAR   (SMBHSTS_FAILED|SMBHSTS_COLLID|\
                                          SMBHSTS_ERROR|SMBHSTS_DONE)   /* clear status */

/* control command number */
#define SMBHCTRL_START  0x40  /* start command */
#define SMBHCTRL_BYTE   0x08  /* byte I/O */
#define SMBHCTRL_WORD   0x0C  /* word I/O */
#define SMBHCTRL_KILL   0x02  /* stop the current transaction */
#define SMBHCTRL_ENABLE 0x01  /* enable interrupts */


static int readbyte(int smb_base, int addr, int cmd)
{
      u_char dat, saddr = 2*(addr/2);
      int i;

top:
      OUTb((u_short) smb_base, SMBHSTS_CLEAR); WAIT; WAIT;
      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            OUTb((u_short) smb_base, dat); WAIT; WAIT;
            if (!(dat & (SMBHSTS_COLLID | SMBHSTS_BUSY)))
                  goto step;
            if (!(dat & SMBHSTS_BUSY))
                  break;
      }
      OUTb((u_short) (smb_base + SMBHCTRL), SMBHCTRL_KILL); WAIT; WAIT;

step:
      OUTb((u_short) (smb_base + SMBHADDR), (saddr | LSB)); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCMD), (u_char) cmd); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCTRL),
            (SMBHCTRL_START | SMBHCTRL_BYTE)); WAIT; WAIT;

      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            if (dat & SMBHSTS_COLLID) {
#ifdef SMB_DEBUG
if (debug_flag > 1)
fprintf(stderr, "\n   OH! collision! = 0x%02X\n", dat);
#endif
                  goto top;
            }
            if (!(dat & SMBHSTS_BUSY) && (dat & (SMBHSTS_DONE | SMBHSTS_ERROR)))
                  break;
      }
#ifdef SMB_DEBUG
if (debug_flag > 1)
fprintf(stderr, "   Readbyte: flag = 0x%02X, loop#:%04d", dat, i);
#endif
      if (dat & SMBHSTS_DONE) {
            dat = INb((u_short) (smb_base + SMBHDATA0)); WAIT; WAIT;
            return (dat & 0xFF);
      } else
            return -1;
}

static int readword(int smb_base, int addr, int cmd)
{
      u_char dat, saddr = 2*(addr/2);
      int i;

top:
      OUTb((u_short) smb_base, SMBHSTS_CLEAR); WAIT; WAIT;
      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            OUTb((u_short) smb_base, dat); WAIT; WAIT;
            if (!(dat & (SMBHSTS_COLLID | SMBHSTS_BUSY)))
                  goto step;
            if (!(dat & SMBHSTS_BUSY))
                  break;
      }
      OUTb((u_short) (smb_base + SMBHCTRL), SMBHCTRL_KILL); WAIT; WAIT;

step:
      OUTb((u_short) (smb_base + SMBHADDR), (saddr | LSB)); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCMD), (u_char) cmd); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCTRL),
            (SMBHCTRL_START | SMBHCTRL_WORD)); WAIT; WAIT;

      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            if (dat & SMBHSTS_COLLID)
                  goto top;
            if (!(dat & SMBHSTS_BUSY) && (dat & (SMBHSTS_DONE | SMBHSTS_ERROR)))
                  break;
      }
      if (dat & SMBHSTS_DONE) {
            i = INb((u_short) (smb_base + SMBHDATA1)); WAIT; WAIT;
            dat = INb((u_short) (smb_base + SMBHDATA0)); WAIT; WAIT;
            return (((i << 8) + dat) & 0xFFFF);
      } else
            return -1;
}

static int writebyte(int smb_base, int addr, int cmd, int value)
{
      u_char dat, saddr = 2*(addr/2);
      int i;

      OUTb((u_short) smb_base, SMBHSTS_CLEAR); WAIT; WAIT;
      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            OUTb((u_short) smb_base, dat); WAIT; WAIT;
            if (!(dat & (SMBHSTS_COLLID | SMBHSTS_BUSY)))
                  goto step;
            if (!(dat & SMBHSTS_BUSY))
                  break;
      }
      OUTb((u_short) (smb_base + SMBHCTRL), SMBHCTRL_KILL); WAIT; WAIT;

step:
      OUTb((u_short) (smb_base + SMBHADDR), saddr); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCMD), (u_char) cmd); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHDATA0), (u_char) value); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCTRL),
            (SMBHCTRL_START | SMBHCTRL_BYTE)); WAIT; WAIT;

      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            if (!(dat & SMBHSTS_BUSY) && (dat & (SMBHSTS_DONE | SMBHSTS_ERROR)))
                  break;
      }
      if (dat & SMBHSTS_DONE)
            return 0;
      else
            return -1;
}

static int writeword(int smb_base, int addr, int cmd, int value)
{
      u_char dat, saddr = 2*(addr/2);
      int i;

      OUTb((u_short) smb_base, SMBHSTS_CLEAR); WAIT; WAIT;
      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            OUTb((u_short) smb_base, dat); WAIT; WAIT;
            if (!(dat & (SMBHSTS_COLLID | SMBHSTS_BUSY)))
                  goto step;
            if (!(dat & SMBHSTS_BUSY))
                  break;
      }
      OUTb((u_short) (smb_base + SMBHCTRL), SMBHCTRL_KILL); WAIT; WAIT;

step:
      OUTb((u_short) (smb_base + SMBHADDR), saddr); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCMD), (u_char) cmd); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHDATA0), (u_char) (value & 0xFF)); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHDATA1), (u_char) (value >> 8)); WAIT; WAIT;
      OUTb((u_short) (smb_base + SMBHCTRL),
            (SMBHCTRL_START | SMBHCTRL_WORD)); WAIT; WAIT;

      for (i = 0; i < LOOP_COUNT; ++i) {
            dat = INb((u_short) smb_base); WAIT; WAIT;
            if (!(dat & SMBHSTS_BUSY) && (dat & (SMBHSTS_DONE | SMBHSTS_ERROR)))
                  break;
      }
      if (dat & SMBHSTS_DONE)
            return 0;
      else
            return -1;
}

struct smbus_io smbus_piix4 = {
      readbyte, readword, writebyte, writeword
};

Generated by  Doxygen 1.6.0   Back to index