PIIX4 update

It compiles now for 2.0 kernels; I hope it still compiles for 2.1 kernels :-)

Changes:
* The non-BIOS PCI interface was introduced in kernel 2.1.54, so I changed
  all #ifdef statements to use that kernel as starting point
* I integrated everything in piix4.h into piix4.c; as no other module will
  ever need to know about anything PIIX4-specific, we do not need a
  separate header file (same went for lm78.c and lm75.c)
* In piix4_setup, both the 2.0 and 2.1 versions continue seeking for PCI
  devices until they have found 'function 3' of the PIIX4. This is the
  'function' we need for SMBus access.
* At some places in piix4_setup, even for 2.1 kernels the PCI BIOS code was
  used. This was seemingly needed, probably because the wrong 'function'
  was accessed. I have removed this; if there are troubles with the PIIX4 on
  kernels newer than 2.1.53, we need to introduce it again.
* Renamed global things to start uniformly with piix4_
* Changed printk statements to start with piix4.o:
* Pasted in missing part of piix4_access
* No need to lock the adapter on access; this is already done by the
  smbus_access function in smbus.c. I corrected a locking bug there too,
  by the way.
* Added a few include files needed by 2.0 at least
* Replaced the call to schedule_timeout() in piix4_do_pause with the old
  code; schedule_timeout seems to be defined nowhere?!? Phil, was this
  your addition, and if so, what should it read?


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@34 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Frodo Looijaard committed 1998-12-05 00:47:22 +00:00
1 parent 831fd5e911
commit f18d210815
10 files changed
+430 -322

No files matched your search

+165 -117
View File
@@ -18,26 +18,57 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Note: New PCI (non-BIOS) interface introduced in 2.1.54! */
/* Note: we assume there can only be one PIIX4, with one SMBus interface */
#include <linux/module.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include "smbus.h"
#include "version.h"
#include "compat.h"
#include "piix4.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
#include <linux/bios32.h>
#endif
/* PIIX4 SMBus address offsets */
#define SMBHSTSTS (0 + piix4_smba)
#define SMBHSLVSTS (1 + piix4_smba)
#define SMBHSTCNT (2 + piix4_smba)
#define SMBHSTCMD (3 + piix4_smba)
#define SMBHSTADD (4 + piix4_smba)
#define SMBHSTDAT0 (5 + piix4_smba)
#define SMBHSTDAT1 (6 + piix4_smba)
#define SMBBLKDAT (7 + piix4_smba)
#define SMBSLVCNT (8 + piix4_smba)
#define SMBSHDWCMD (9 + piix4_smba)
#define SMBSLVEVT (0xA + piix4_smba)
#define SMBSLVDAT (0xC + piix4_smba)
/* PCI Address Constants */
#define SMBBA 0x090
#define SMBHSTCFG 0x0D2
#define SMBSLVC 0x0D3
#define SMBSHDW1 0x0D4
#define SMBSHDW2 0x0D5
#define SMBREV 0x0D6
/* Other settings */
#define MAX_TIMEOUT 500
#define ENABLE_INT9 0
static int piix4_init(void);
static int piix4_cleanup(void);
static int piix4_setup(void);
static s32 piix4_access(u8 addr, char read_write,
u8 command, int size, union smbus_data * data);
/* Internal functions */
static void do_pause( unsigned int amount );
static int SMBus_PIIX4_Transaction(void);
static void piix4_do_pause( unsigned int amount );
static int piix4_transaction(void);
#ifdef MODULE
extern int init_module(void);
@@ -46,62 +77,70 @@ extern int cleanup_module(void);
static struct smbus_adapter piix4_adapter;
static int piix4_initialized;
/* Global variables -- At least some of these may be modified/moved later */
static unsigned short PIIX4_smba = 0;
static struct semaphore smbus_piix4_sem = MUTEX;
static unsigned short piix4_smba = 0;
/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
Return -ENODEV if not found. */
/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
Note the differences between kernels with the old PCI BIOS interface and
newer kernels with the real PCI interface. In compat.h some things are
defined to make the transition easier. */
int piix4_setup(void)
{
int error_return=0;
unsigned char temp;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
struct pci_dev *PIIX4_dev;
#else
unsigned char PIIX4_bus, PIIX4_devfn;
int i,res;
#endif
/* First check whether we can access PCI at all */
if (pci_present() == 0) {
printk("SMBus: Error: No PCI-bus found!\n");
printk("piix4.o: Error: No PCI-bus found!\n");
error_return=-ENODEV;
} else {
goto END;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
/* Look for the PIIX4, function 3 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
/* Note: we keep on searching until we have found 'function 3' */
PIIX4_dev = NULL;
do
PIIX4_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
if(PIIX4_dev == NULL) {
#else
if(pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
0, &PIIX4_bus, &PIIX4_devfn)) {
#endif
printk("SMBus: Error: Can't detect PIIX4!\n");
error_return=-ENODEV;
} else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
/* For some reason, pci_read_config fails here sometimes! */
pcibios_read_config_word(PIIX4_dev->bus->number, PIIX4_dev->devfn | 3,
SMBBA, &PIIX4_smba);
#else
pci_read_config_word_united(PIIX4_dev, PIIX4_bus ,PIIX4_devfn | 3,
SMBBA,&PIIX4_smba);
#endif
PIIX4_smba &= 0xfff0;
if (check_region(PIIX4_smba, 8)) {
printk("PIIX4_smb region 0x%x already in use!\n",
PIIX4_smba);
error_return=-ENODEV;
} else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
pcibios_read_config_byte(PIIX4_dev->bus->number,
PIIX4_dev->devfn | 3, SMBHSTCFG, &temp);
#else
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn | 3,
SMBHSTCFG, &temp);
#endif
PCI_DEVICE_ID_INTEL_82371AB_0, PIIX4_dev);
while(PIIX4_dev && (PCI_FUNC(PIIX4_dev->devfn) != 3);
if(PIIX4_dev == NULL) {
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54) */
for (i = 0;
! (res = pcibios_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0,
i,&PIIX4_bus, &PIIX4_devfn)) &&
PCI_FUNC(PIIX4_devfn) != 3;
i++);
if (res) {
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54) */
printk("piix4.o: Error: Can't detect PIIX4, function 3!\n");
error_return=-ENODEV;
goto END;
}
/* Determine the address of the SMBus areas */
pci_read_config_word_united(PIIX4_dev, PIIX4_bus ,PIIX4_devfn,
SMBBA,&piix4_smba);
piix4_smba &= 0xfff0;
if (check_region(piix4_smba, 8)) {
printk("piix4.o: PIIX4_smb region 0x%x already in use!\n", piix4_smba);
error_return=-ENODEV;
goto END;
}
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
SMBHSTCFG, &temp);
#ifdef FORCE_PIIX4_ENABLE
/* This should never need to be done, but has been noted that
many Dell machines have the SMBus interface on the PIIX4
@@ -109,65 +148,57 @@ int piix4_setup(void)
done by the Bios! Don't complain if your hardware does weird
things after enabling this. :') Check for Bios updates before
resorting to this. */
if ((temp & 1) == 0) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
pcibios_write_config_byte(PIIX4_dev->bus->number, PIIX4_dev->devfn | 3,
SMBHSTCFG, temp | 1);
#else
pcibios_write_config_byte(PIIX4_bus, PIIX4_devfn | 3, SMBHSTCFG, temp | 1);
#endif
printk("SMBus: WARNING: PIIX4 SMBus interface has been FORCEFULLY ENABLED!!\n");
/* Update configuration value */
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn | 3, SMBHSTCFG, &temp);
/* Note: We test the bit again in the next 'if' just to be sure... */
}
#endif
if ((temp & 1) == 0) {
printk("SMBUS: Error: Host SMBus controller not enabled!\n");
piix4_initialized=0;
error_return=-ENODEV;
} else {
/* Everything is happy, let's grab the memory and set things up. */
request_region(PIIX4_smba, 8, "SMBus");
piix4_initialized=1;
}
#ifdef DEBUG
if ((temp & 0x0E) == 8)
printk("SMBUS: PIIX4 using Interrupt 9 for SMBus.\n");
else if ((temp & 0x0E) == 0)
printk("SMBUS: PIIX4 using Interrupt SMI# for SMBus.\n");
else
printk( "SMBUS: PIIX4: Illegal Interrupt configuration (or code out of date)!\n");
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
pcibios_read_config_byte(PIIX4_dev->bus->number,
PIIX4_dev->devfn | 3, SMBREV, &temp);
#else
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn | 3,
SMBREV, &temp);
#endif
printk("SMBUS: SMBREV = 0x%X\n",temp);
#endif
}
}
if (error_return)
printk("SMBus setup failed.\n");
#ifdef DEBUG
else
printk("PIIX4_smba = 0x%X\n",PIIX4_smba);
#endif
if ((temp & 1) == 0) {
pcibios_write_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
SMBHSTCFG, temp | 1);
printk("piix4.0: WARNING: PIIX4 SMBus interface has been FORCEFULLY "
"ENABLED!!\n");
/* Update configuration value */
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
SMBHSTCFG, &temp);
/* Note: We test the bit again in the next 'if' just to be sure... */
}
#endif /* FORCE_PIIX4_ENABLE */
if ((temp & 1) == 0) {
printk("SMBUS: Error: Host SMBus controller not enabled!\n");
error_return=-ENODEV;
goto END;
}
/* Everything is happy, let's grab the memory and set things up. */
request_region(piix4_smba, 8, "SMBus");
#ifdef DEBUG
if ((temp & 0x0E) == 8)
printk("piix4.o: PIIX4 using Interrupt 9 for SMBus.\n");
else if ((temp & 0x0E) == 0)
printk("piix4.o: PIIX4 using Interrupt SMI# for SMBus.\n");
else
printk("piix4.o: PIIX4: Illegal Interrupt configuration (or code out "
"of date)!\n");
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, SMBREV,
&temp);
printk("piix4.o: SMBREV = 0x%X\n",temp);
printk("piix4.o: PIIX4_smba = 0x%X\n",piix4_smba);
#endif /* DEBUG */
END:
return error_return;
}
/* Internally used pause function */
void do_pause( unsigned int amount )
void piix4_do_pause( unsigned int amount )
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(amount);
current->timeout = jiffies + amount;
schedule();
}
/* Another internally used function */
int SMBus_PIIX4_Transaction(void)
int piix4_transaction(void)
{
int temp;
int result=0;
@@ -176,17 +207,17 @@ int SMBus_PIIX4_Transaction(void)
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
#ifdef DEBUG
printk("SMBus: SMBus_Read: SMBus busy (%02x). Resetting... ",temp);
printk("piix4.o: SMBus busy (%02x). Resetting... ",temp);
#endif
outb_p(temp, SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
#ifdef DEBUG
printk("Failed! (%02x)\n",temp);
printk("piix4.o: Failed! (%02x)\n",temp);
#endif
return -1;
} else {
#ifdef DEBUG
printk("Successfull!\n");
printk("piix4.o: Successfull!\n");
#endif
}
}
@@ -195,20 +226,20 @@ int SMBus_PIIX4_Transaction(void)
outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
/* Wait for a fraction of a second! (See PIIX4 docs errata) */
do_pause(1);
piix4_do_pause(1);
/* Poll Host_busy bit */
temp=inb_p(SMBHSTSTS) & 0x01;
while (temp & (timeout++ < MAX_TIMEOUT)) {
/* Wait for a while and try again*/
do_pause(1);
piix4_do_pause(1);
temp = inb_p(SMBHSTSTS) & 0x01;
}
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
#ifdef DEBUG
printk("SMBus: SMBus_Read: SMBus Timeout!\n");
printk("piix4.o: SMBus Timeout!\n");
result = -1;
#endif
}
@@ -218,20 +249,21 @@ int SMBus_PIIX4_Transaction(void)
if (temp & 0x10) {
result = -1;
#ifdef DEBUG
printk("SMBus error: Failed bus transaction\n");
printk("piix4.o: Error: Failed bus transaction\n");
#endif
}
if (temp & 0x08) {
result = -1;
printk("SMBus error: Bus collision! SMBus may be locked until next hard reset. (sorry!)\n");
printk("piix4.o: Bus collision! SMBus may be locked until next hard
reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */
}
if (temp & 0x04) {
result = -1;
#ifdef DEBUG
printk("SMBus error: no response!\n");
printk("piix4.o: Error: no response!\n");
#endif
}
@@ -240,7 +272,7 @@ int SMBus_PIIX4_Transaction(void)
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
#ifdef DEBUG
printk("SMBus error: Failed reset at end of transaction (%02x)\n",temp);
printk("piix4.o: Failed reset at end of transaction (%02x)\n",temp);
#endif
}
return result;
@@ -252,8 +284,6 @@ s32 piix4_access(u8 addr, char read_write,
{
int i,len;
down(&smbus_piix4_sem);
outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
switch(size) {
@@ -296,16 +326,36 @@ s32 piix4_access(u8 addr, char read_write,
}
}
if (SMBus_PIIX4_Transaction()) { /* Error in transaction */
up(&smbus_piix4_sem);
if (piix4_transaction()) /* Error in transaction */
return -1;
}
if ((read_write == SMBUS_WRITE) || (size == SMBUS_QUICK)) {
up(&smbus_piix4_sem);
if ((read_write == SMBUS_WRITE) || (size == SMBUS_QUICK))
return 0;
switch(size) {
case SMBUS_BYTE: /* Where is the result put? I assume here it is in
SMBHSTDAT0 but it might just as well be in the
SMBHSTCMD. No clue in the docs */
data->byte = inb_p(SMBHSTDAT0);
break;
case SMBUS_BYTE_DATA:
data->byte = inb_p(SMBHSTDAT0);
break;
case SMBUS_WORD_DATA:
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
break;
case SMBUS_BLOCK_DATA:
data->block[0] = inb_p(SMBHSTDAT0);
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
for (i = 1; i <= data->block[0]; i++)
data->block[i] = inb_p(SMBBLKDAT);
break;
}
}
return 0;
}
int piix4_init(void)
@@ -352,10 +402,8 @@ int piix4_cleanup(void)
piix4_initialized=0;
}
if (piix4_initialized >= 1) {
if (piix4_initialized) {
release_region(PIIX4_smba, 8);
piix4_initialized=0;
}
release_region(piix4_smba, 8);
piix4_initialized=0;
}
return 0;
}
+26
View File
@@ -49,5 +49,31 @@
#define get_user_data(to,from) get_user(to,from)
#endif
/* If the new PCI interface is not present, fall back on the old PCI BIOS
interface. We also define some things to unite both interfaces. Not
very nice, but it works like a charm.
device is the 2.1 struct pci_dev, bus is the 2.0 bus number, dev is the
2.0 device/function code, com is the PCI command, and res is the result. */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
#define pci_present pcibios_present
#define pci_read_config_byte_united(device,bus,dev,com,res) \
pcibios_read_config_byte(bus,dev,com,res);
#define pci_read_config_word_united(device,bus,dev,com,res) \
pcibios_read_config_word(bus,dev,com,res);
#define pci_write_config_byte_united(device,bus,dev,com,res) \
pcibios_write_config_byte(bus,dev,com,res);
#define pci_write_config_word_united(device,bus,dev,com,res) \
pcibios_write_config_word(bus,dev,com,res);
#else
#define pci_read_config_byte_united(device,bus,dev,com,res) \
pci_read_config_byte(device,com,res);
#define pci_read_config_word_united(device,bus,dev,com,res) \
pci_read_config_word(device,com,res);
#define pci_write_config_byte_united(device,bus,dev,com,res) \
pci_write_config_byte(device,com,res);
#define pci_write_config_word_united(device,bus,dev,com,res) \
pci_write_config_byte(device,com,res);
#endif
#endif /* SENSORS_COMPAT_H */
+26
View File
@@ -49,5 +49,31 @@
#define get_user_data(to,from) get_user(to,from)
#endif
/* If the new PCI interface is not present, fall back on the old PCI BIOS
interface. We also define some things to unite both interfaces. Not
very nice, but it works like a charm.
device is the 2.1 struct pci_dev, bus is the 2.0 bus number, dev is the
2.0 device/function code, com is the PCI command, and res is the result. */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
#define pci_present pcibios_present
#define pci_read_config_byte_united(device,bus,dev,com,res) \
pcibios_read_config_byte(bus,dev,com,res);
#define pci_read_config_word_united(device,bus,dev,com,res) \
pcibios_read_config_word(bus,dev,com,res);
#define pci_write_config_byte_united(device,bus,dev,com,res) \
pcibios_write_config_byte(bus,dev,com,res);
#define pci_write_config_word_united(device,bus,dev,com,res) \
pcibios_write_config_word(bus,dev,com,res);
#else
#define pci_read_config_byte_united(device,bus,dev,com,res) \
pci_read_config_byte(device,com,res);
#define pci_read_config_word_united(device,bus,dev,com,res) \
pci_read_config_word(device,com,res);
#define pci_write_config_byte_united(device,bus,dev,com,res) \
pci_write_config_byte(device,com,res);
#define pci_write_config_word_united(device,bus,dev,com,res) \
pci_write_config_byte(device,com,res);
#endif
#endif /* SENSORS_COMPAT_H */
+4
View File
@@ -20,6 +20,8 @@
#ifndef SENSORS_SMBUS_H
#define SENSORS_SMBUS_H
#ifdef __KERNEL__
/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is
OK, earlier versions are not; later versions will probably give problems
too.
@@ -285,5 +287,7 @@ extern inline int smbus_write_block_data(struct i2c_adapter * adapter,
i2c_detach_client((struct i2c_client *) (clientptr))
#endif /* def __KERNEL__ */
#endif /* ndef SENSORS_SMBUS_H */
+7 -7
View File
@@ -74,21 +74,21 @@ s32 smbus_access (struct i2c_adapter * adapter, u8 addr, char read_write,
u8 command, int size, union smbus_data * data)
{
int res;
if (adapter->id & ALGO_SMBUS) {
#ifdef SPINLOCK
spin_lock_irqsave(&adapter->lock,adapter->lockflags);
spin_lock_irqsave(&adapter->lock,adapter->lockflags);
#else
down(&adapter->lock);
down(&adapter->lock);
#endif
if (adapter->id & ALGO_SMBUS)
res = ((struct smbus_adapter *) adapter) ->
smbus_access(addr,read_write,command,size,data);
else
res = smbus_access_i2c(adapter,addr,read_write,command,size,data);
#ifdef SPINLOCK
spin_unlock_irqrestore(&adapter->lock,adapter->lockflags);
spin_unlock_irqrestore(&adapter->lock,adapter->lockflags);
#else
up(&adapter->lock);
up(&adapter->lock);
#endif
} else
res = smbus_access_i2c(adapter,addr,read_write,command,size,data);
return res;
}
+26
View File
@@ -49,5 +49,31 @@
#define get_user_data(to,from) get_user(to,from)
#endif
/* If the new PCI interface is not present, fall back on the old PCI BIOS
interface. We also define some things to unite both interfaces. Not
very nice, but it works like a charm.
device is the 2.1 struct pci_dev, bus is the 2.0 bus number, dev is the
2.0 device/function code, com is the PCI command, and res is the result. */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
#define pci_present pcibios_present
#define pci_read_config_byte_united(device,bus,dev,com,res) \
pcibios_read_config_byte(bus,dev,com,res);
#define pci_read_config_word_united(device,bus,dev,com,res) \
pcibios_read_config_word(bus,dev,com,res);
#define pci_write_config_byte_united(device,bus,dev,com,res) \
pcibios_write_config_byte(bus,dev,com,res);
#define pci_write_config_word_united(device,bus,dev,com,res) \
pcibios_write_config_word(bus,dev,com,res);
#else
#define pci_read_config_byte_united(device,bus,dev,com,res) \
pci_read_config_byte(device,com,res);
#define pci_read_config_word_united(device,bus,dev,com,res) \
pci_read_config_word(device,com,res);
#define pci_write_config_byte_united(device,bus,dev,com,res) \
pci_write_config_byte(device,com,res);
#define pci_write_config_word_united(device,bus,dev,com,res) \
pci_write_config_byte(device,com,res);
#endif
#endif /* SENSORS_COMPAT_H */
+165 -117
View File
@@ -18,26 +18,57 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Note: New PCI (non-BIOS) interface introduced in 2.1.54! */
/* Note: we assume there can only be one PIIX4, with one SMBus interface */
#include <linux/module.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include "smbus.h"
#include "version.h"
#include "compat.h"
#include "piix4.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
#include <linux/bios32.h>
#endif
/* PIIX4 SMBus address offsets */
#define SMBHSTSTS (0 + piix4_smba)
#define SMBHSLVSTS (1 + piix4_smba)
#define SMBHSTCNT (2 + piix4_smba)
#define SMBHSTCMD (3 + piix4_smba)
#define SMBHSTADD (4 + piix4_smba)
#define SMBHSTDAT0 (5 + piix4_smba)
#define SMBHSTDAT1 (6 + piix4_smba)
#define SMBBLKDAT (7 + piix4_smba)
#define SMBSLVCNT (8 + piix4_smba)
#define SMBSHDWCMD (9 + piix4_smba)
#define SMBSLVEVT (0xA + piix4_smba)
#define SMBSLVDAT (0xC + piix4_smba)
/* PCI Address Constants */
#define SMBBA 0x090
#define SMBHSTCFG 0x0D2
#define SMBSLVC 0x0D3
#define SMBSHDW1 0x0D4
#define SMBSHDW2 0x0D5
#define SMBREV 0x0D6
/* Other settings */
#define MAX_TIMEOUT 500
#define ENABLE_INT9 0
static int piix4_init(void);
static int piix4_cleanup(void);
static int piix4_setup(void);
static s32 piix4_access(u8 addr, char read_write,
u8 command, int size, union smbus_data * data);
/* Internal functions */
static void do_pause( unsigned int amount );
static int SMBus_PIIX4_Transaction(void);
static void piix4_do_pause( unsigned int amount );
static int piix4_transaction(void);
#ifdef MODULE
extern int init_module(void);
@@ -46,62 +77,70 @@ extern int cleanup_module(void);
static struct smbus_adapter piix4_adapter;
static int piix4_initialized;
/* Global variables -- At least some of these may be modified/moved later */
static unsigned short PIIX4_smba = 0;
static struct semaphore smbus_piix4_sem = MUTEX;
static unsigned short piix4_smba = 0;
/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
Return -ENODEV if not found. */
/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
Note the differences between kernels with the old PCI BIOS interface and
newer kernels with the real PCI interface. In compat.h some things are
defined to make the transition easier. */
int piix4_setup(void)
{
int error_return=0;
unsigned char temp;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
struct pci_dev *PIIX4_dev;
#else
unsigned char PIIX4_bus, PIIX4_devfn;
int i,res;
#endif
/* First check whether we can access PCI at all */
if (pci_present() == 0) {
printk("SMBus: Error: No PCI-bus found!\n");
printk("piix4.o: Error: No PCI-bus found!\n");
error_return=-ENODEV;
} else {
goto END;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
/* Look for the PIIX4, function 3 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
/* Note: we keep on searching until we have found 'function 3' */
PIIX4_dev = NULL;
do
PIIX4_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
if(PIIX4_dev == NULL) {
#else
if(pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
0, &PIIX4_bus, &PIIX4_devfn)) {
#endif
printk("SMBus: Error: Can't detect PIIX4!\n");
error_return=-ENODEV;
} else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
/* For some reason, pci_read_config fails here sometimes! */
pcibios_read_config_word(PIIX4_dev->bus->number, PIIX4_dev->devfn | 3,
SMBBA, &PIIX4_smba);
#else
pci_read_config_word_united(PIIX4_dev, PIIX4_bus ,PIIX4_devfn | 3,
SMBBA,&PIIX4_smba);
#endif
PIIX4_smba &= 0xfff0;
if (check_region(PIIX4_smba, 8)) {
printk("PIIX4_smb region 0x%x already in use!\n",
PIIX4_smba);
error_return=-ENODEV;
} else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
pcibios_read_config_byte(PIIX4_dev->bus->number,
PIIX4_dev->devfn | 3, SMBHSTCFG, &temp);
#else
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn | 3,
SMBHSTCFG, &temp);
#endif
PCI_DEVICE_ID_INTEL_82371AB_0, PIIX4_dev);
while(PIIX4_dev && (PCI_FUNC(PIIX4_dev->devfn) != 3);
if(PIIX4_dev == NULL) {
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54) */
for (i = 0;
! (res = pcibios_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0,
i,&PIIX4_bus, &PIIX4_devfn)) &&
PCI_FUNC(PIIX4_devfn) != 3;
i++);
if (res) {
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54) */
printk("piix4.o: Error: Can't detect PIIX4, function 3!\n");
error_return=-ENODEV;
goto END;
}
/* Determine the address of the SMBus areas */
pci_read_config_word_united(PIIX4_dev, PIIX4_bus ,PIIX4_devfn,
SMBBA,&piix4_smba);
piix4_smba &= 0xfff0;
if (check_region(piix4_smba, 8)) {
printk("piix4.o: PIIX4_smb region 0x%x already in use!\n", piix4_smba);
error_return=-ENODEV;
goto END;
}
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
SMBHSTCFG, &temp);
#ifdef FORCE_PIIX4_ENABLE
/* This should never need to be done, but has been noted that
many Dell machines have the SMBus interface on the PIIX4
@@ -109,65 +148,57 @@ int piix4_setup(void)
done by the Bios! Don't complain if your hardware does weird
things after enabling this. :') Check for Bios updates before
resorting to this. */
if ((temp & 1) == 0) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
pcibios_write_config_byte(PIIX4_dev->bus->number, PIIX4_dev->devfn | 3,
SMBHSTCFG, temp | 1);
#else
pcibios_write_config_byte(PIIX4_bus, PIIX4_devfn | 3, SMBHSTCFG, temp | 1);
#endif
printk("SMBus: WARNING: PIIX4 SMBus interface has been FORCEFULLY ENABLED!!\n");
/* Update configuration value */
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn | 3, SMBHSTCFG, &temp);
/* Note: We test the bit again in the next 'if' just to be sure... */
}
#endif
if ((temp & 1) == 0) {
printk("SMBUS: Error: Host SMBus controller not enabled!\n");
piix4_initialized=0;
error_return=-ENODEV;
} else {
/* Everything is happy, let's grab the memory and set things up. */
request_region(PIIX4_smba, 8, "SMBus");
piix4_initialized=1;
}
#ifdef DEBUG
if ((temp & 0x0E) == 8)
printk("SMBUS: PIIX4 using Interrupt 9 for SMBus.\n");
else if ((temp & 0x0E) == 0)
printk("SMBUS: PIIX4 using Interrupt SMI# for SMBus.\n");
else
printk( "SMBUS: PIIX4: Illegal Interrupt configuration (or code out of date)!\n");
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
pcibios_read_config_byte(PIIX4_dev->bus->number,
PIIX4_dev->devfn | 3, SMBREV, &temp);
#else
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn | 3,
SMBREV, &temp);
#endif
printk("SMBUS: SMBREV = 0x%X\n",temp);
#endif
}
}
if (error_return)
printk("SMBus setup failed.\n");
#ifdef DEBUG
else
printk("PIIX4_smba = 0x%X\n",PIIX4_smba);
#endif
if ((temp & 1) == 0) {
pcibios_write_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
SMBHSTCFG, temp | 1);
printk("piix4.0: WARNING: PIIX4 SMBus interface has been FORCEFULLY "
"ENABLED!!\n");
/* Update configuration value */
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
SMBHSTCFG, &temp);
/* Note: We test the bit again in the next 'if' just to be sure... */
}
#endif /* FORCE_PIIX4_ENABLE */
if ((temp & 1) == 0) {
printk("SMBUS: Error: Host SMBus controller not enabled!\n");
error_return=-ENODEV;
goto END;
}
/* Everything is happy, let's grab the memory and set things up. */
request_region(piix4_smba, 8, "SMBus");
#ifdef DEBUG
if ((temp & 0x0E) == 8)
printk("piix4.o: PIIX4 using Interrupt 9 for SMBus.\n");
else if ((temp & 0x0E) == 0)
printk("piix4.o: PIIX4 using Interrupt SMI# for SMBus.\n");
else
printk("piix4.o: PIIX4: Illegal Interrupt configuration (or code out "
"of date)!\n");
pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, SMBREV,
&temp);
printk("piix4.o: SMBREV = 0x%X\n",temp);
printk("piix4.o: PIIX4_smba = 0x%X\n",piix4_smba);
#endif /* DEBUG */
END:
return error_return;
}
/* Internally used pause function */
void do_pause( unsigned int amount )
void piix4_do_pause( unsigned int amount )
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(amount);
current->timeout = jiffies + amount;
schedule();
}
/* Another internally used function */
int SMBus_PIIX4_Transaction(void)
int piix4_transaction(void)
{
int temp;
int result=0;
@@ -176,17 +207,17 @@ int SMBus_PIIX4_Transaction(void)
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
#ifdef DEBUG
printk("SMBus: SMBus_Read: SMBus busy (%02x). Resetting... ",temp);
printk("piix4.o: SMBus busy (%02x). Resetting... ",temp);
#endif
outb_p(temp, SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
#ifdef DEBUG
printk("Failed! (%02x)\n",temp);
printk("piix4.o: Failed! (%02x)\n",temp);
#endif
return -1;
} else {
#ifdef DEBUG
printk("Successfull!\n");
printk("piix4.o: Successfull!\n");
#endif
}
}
@@ -195,20 +226,20 @@ int SMBus_PIIX4_Transaction(void)
outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
/* Wait for a fraction of a second! (See PIIX4 docs errata) */
do_pause(1);
piix4_do_pause(1);
/* Poll Host_busy bit */
temp=inb_p(SMBHSTSTS) & 0x01;
while (temp & (timeout++ < MAX_TIMEOUT)) {
/* Wait for a while and try again*/
do_pause(1);
piix4_do_pause(1);
temp = inb_p(SMBHSTSTS) & 0x01;
}
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
#ifdef DEBUG
printk("SMBus: SMBus_Read: SMBus Timeout!\n");
printk("piix4.o: SMBus Timeout!\n");
result = -1;
#endif
}
@@ -218,20 +249,21 @@ int SMBus_PIIX4_Transaction(void)
if (temp & 0x10) {
result = -1;
#ifdef DEBUG
printk("SMBus error: Failed bus transaction\n");
printk("piix4.o: Error: Failed bus transaction\n");
#endif
}
if (temp & 0x08) {
result = -1;
printk("SMBus error: Bus collision! SMBus may be locked until next hard reset. (sorry!)\n");
printk("piix4.o: Bus collision! SMBus may be locked until next hard
reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */
}
if (temp & 0x04) {
result = -1;
#ifdef DEBUG
printk("SMBus error: no response!\n");
printk("piix4.o: Error: no response!\n");
#endif
}
@@ -240,7 +272,7 @@ int SMBus_PIIX4_Transaction(void)
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
#ifdef DEBUG
printk("SMBus error: Failed reset at end of transaction (%02x)\n",temp);
printk("piix4.o: Failed reset at end of transaction (%02x)\n",temp);
#endif
}
return result;
@@ -252,8 +284,6 @@ s32 piix4_access(u8 addr, char read_write,
{
int i,len;
down(&smbus_piix4_sem);
outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
switch(size) {
@@ -296,16 +326,36 @@ s32 piix4_access(u8 addr, char read_write,
}
}
if (SMBus_PIIX4_Transaction()) { /* Error in transaction */
up(&smbus_piix4_sem);
if (piix4_transaction()) /* Error in transaction */
return -1;
}
if ((read_write == SMBUS_WRITE) || (size == SMBUS_QUICK)) {
up(&smbus_piix4_sem);
if ((read_write == SMBUS_WRITE) || (size == SMBUS_QUICK))
return 0;
switch(size) {
case SMBUS_BYTE: /* Where is the result put? I assume here it is in
SMBHSTDAT0 but it might just as well be in the
SMBHSTCMD. No clue in the docs */
data->byte = inb_p(SMBHSTDAT0);
break;
case SMBUS_BYTE_DATA:
data->byte = inb_p(SMBHSTDAT0);
break;
case SMBUS_WORD_DATA:
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
break;
case SMBUS_BLOCK_DATA:
data->block[0] = inb_p(SMBHSTDAT0);
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
for (i = 1; i <= data->block[0]; i++)
data->block[i] = inb_p(SMBBLKDAT);
break;
}
}
return 0;
}
int piix4_init(void)
@@ -352,10 +402,8 @@ int piix4_cleanup(void)
piix4_initialized=0;
}
if (piix4_initialized >= 1) {
if (piix4_initialized) {
release_region(PIIX4_smba, 8);
piix4_initialized=0;
}
release_region(piix4_smba, 8);
piix4_initialized=0;
}
return 0;
}
-74
View File
@@ -1,74 +0,0 @@
/*
piix4.h - Part of a Linux module for reading sensor data.
Copyright (c) 1998 Alexander Larsson <alla@lysator.liu.se>,
Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This file was taken almost directly from the first (lm_sensors) project */
/* Some things will probably need to change or will simply not be used. */
#include <asm/types.h>
#include <linux/unistd.h>
/*
I/O Space Constants
*/
#define SMBHSTSTS PIIX4_smba
#define SMBHSLVSTS PIIX4_smba + 1
#define SMBHSTCNT PIIX4_smba + 2
#define SMBHSTCMD PIIX4_smba + 3
#define SMBHSTADD PIIX4_smba + 4
#define SMBHSTDAT0 PIIX4_smba + 5
#define SMBHSTDAT1 PIIX4_smba + 6
#define SMBBLKDAT PIIX4_smba + 7
#define SMBSLVCNT PIIX4_smba + 8
#define SMBSHDWCMD PIIX4_smba + 9
#define SMBSLVEVT PIIX4_smba + 0xA
#define SMBSLVDAT PIIX4_smba + 0xC
/*
PCI Address Constants
*/
#define SMBBA 0x090
#define SMBHSTCFG 0x0D2
#define SMBSLVC 0x0D3
#define SMBSHDW1 0x0D4
#define SMBSHDW2 0x0D5
#define SMBREV 0x0D6
/*
Contants for other uses
*/
#define MAX_TIMEOUT 500
#define SMBUS_READ 1
#define SMBUS_WRITE 0
/* Set to 1 to enable (don't comment out completely)
This is known to freeze some machines (as Frodo knows ;')
in the current implemented state, so beware! */
#define ENABLE_INT9 0
#define SMBUSTABLE_SIZE 64
/*
Prototypes
*/
extern int SMBus_PIIX4_Init(void);
extern void SMBus_PIIX4_Cleanup(void);
extern int SMBus_PIIX4_Access(u8 addr, char read_write, u8 command, int size,
union SMBus_Data *data);
extern int SMBus_PIIX4_Initialized;
+7 -7
View File
@@ -74,21 +74,21 @@ s32 smbus_access (struct i2c_adapter * adapter, u8 addr, char read_write,
u8 command, int size, union smbus_data * data)
{
int res;
if (adapter->id & ALGO_SMBUS) {
#ifdef SPINLOCK
spin_lock_irqsave(&adapter->lock,adapter->lockflags);
spin_lock_irqsave(&adapter->lock,adapter->lockflags);
#else
down(&adapter->lock);
down(&adapter->lock);
#endif
if (adapter->id & ALGO_SMBUS)
res = ((struct smbus_adapter *) adapter) ->
smbus_access(addr,read_write,command,size,data);
else
res = smbus_access_i2c(adapter,addr,read_write,command,size,data);
#ifdef SPINLOCK
spin_unlock_irqrestore(&adapter->lock,adapter->lockflags);
spin_unlock_irqrestore(&adapter->lock,adapter->lockflags);
#else
up(&adapter->lock);
up(&adapter->lock);
#endif
} else
res = smbus_access_i2c(adapter,addr,read_write,command,size,data);
return res;
}
+4
View File
@@ -20,6 +20,8 @@
#ifndef SENSORS_SMBUS_H
#define SENSORS_SMBUS_H
#ifdef __KERNEL__
/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is
OK, earlier versions are not; later versions will probably give problems
too.
@@ -285,5 +287,7 @@ extern inline int smbus_write_block_data(struct i2c_adapter * adapter,
i2c_detach_client((struct i2c_client *) (clientptr))
#endif /* def __KERNEL__ */
#endif /* ndef SENSORS_SMBUS_H */