(mds) Big update for 2.4.0-testx kernels. Now uses kernel

"hotplug" facility. Somewhat tested on my PC.


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@894 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Mark D. Studebaker committed 2000-10-09 03:10:03 +00:00
1 parent ec8a8ef06c
commit d51bdd40d2
3 files changed
+168 -249

No files matched your search

+13 -3
View File
@@ -1,9 +1,10 @@
INCLUDEDIR = /usr/include
CFLAGS = -D__KERNEL__ -DMODULE -DLINUX -DMODVERSION -O2 -Wall -I$(INCLUDEDIR)
#CFLAGS := -D__KERNEL__ -DMODULE -DLINUX -O2 -Wall -I$(INCLUDEDIR)
CC := gcc
# Compile with Debugging turned on - watch out, lots of pci device infos.
#CFLAGS = -D__KERNEL__ -DMODULE -DLINUX -DMODVERSION -DM7101_DEBUG -O2 -Wall -I$(INCLUDEDIR)
LD = ld
CFLAGS = -D__KERNEL__ -DMODULE -DLINUX -DM7101_DEBUG -O2 -Wall -I$(INCLUDEDIR)
LD := ld
# extract versionnumber from version.h
VER = $(shell awk -F\" '/REL/ {print $$2}' $(INCLUDEDIR)/linux/version.h)
@@ -11,3 +12,12 @@ VER = $(shell awk -F\" '/REL/ {print $$2}' $(INCLUDEDIR)/linux/version.h)
OBJS = m7101.o
all: $(OBJS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
install: all
install -o root -g root -m 644 $(OBJS) /lib/modules/$(VER)/misc
clean:
rm -f $(OBJS)
+19
View File
@@ -1,5 +1,23 @@
M7101 - SMBus Support for ALi M15x3 based motherboards.
--------------------------------------------------------
Quick Start:
"lspci" to verify that 7101 device is not present
"make"
(as root) "make install"
(as root) "insmod m7101"
"lspci" to verify that 7101 device is present
--------------------------------------------------------
Version 0.2 for 2.4.0-testx kernels.
Mark D. Studebaker <mdsxyz123@yahoo.com>
*** You must have 'Support for hot-pluggable devices' enabled
*** in your kernel (under 'general setup') for this module to work!!
Notes below from the 0.1 version, B. Kohl.
--------------------------------------------------------
This module was written to enable SMBus support on ALi M15x3 chipset based
motherboards. Although it was written for and tested on Gigabytes GA-5AX
it should work on any M15x3 chipset based board.
@@ -42,6 +60,7 @@ motherboard's SMBus through the M7101.
Values for the ACPI-IO port (normally 0x4000) and the SMBus-IO port
(normally 0x5000) can be specified using the parameters acpi_io and
smbus_io respectively on the insmod command line.
The module defaults to ports 0xec00 and 0xe800.
In case the module does not load you might want to switch on debugging
by uncommenting the second CFLAGS-line (with the -DM7101_DEBUG switch)
+136 -246
View File
@@ -4,8 +4,9 @@
* Initialize the M7101 device on ALi M15x3 Chipsets
*/
/*
Copyright (c) 2000 Burkhard Kohl <buk@buks.ipn.de>
and Frank Bauer <frank.bauer@nikocity.de>
Copyright (c) 2000 Burkhard Kohl <buk@buks.ipn.de>,
Frank Bauer <frank.bauer@nikocity.de>, and
Mark D. Studebaker <mdsxyz123@yahoo.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
@@ -33,9 +34,17 @@
* June 21, 2000 MDS: Add Copyright and GPL comments,
* distribute as release 0.1.
*
* Sept 21, 2000 MDS: Rewrite to use kernel hotplug facility,
* (similar to drivers/pcmcia/cardbus.c),
* fix makefile so it will compile,
* distribute as release 0.2.
*
* This code is absolutely experimental - use it at your own
* risk.
*
* Warning, this module will work only with 2.4.x kernels.
* If it works with earlier kernels then it is by luck.
*
* Warning, this module does not work with egcs < 2.95.2, use
* gcc > 2.7.2 or egcs >= 2.95.2.
*
@@ -53,8 +62,13 @@
#define FALSE !TRUE
#endif
#include <linux/config.h>
#ifndef CONFIG_HOTPLUG
#error ERROR - You must have 'Support for hot-pluggable devices' enabled in your kernel (under 'general setup')!!
#endif
/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif
@@ -66,41 +80,16 @@
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <asm/spinlock.h>
#include <asm/types.h>
/*
from lm_sensors-2.3.3:
*/
#define SMBHSTCFG 0x0E0
/* PCI Address Constants */
#define SMBCOM 0x004
#define ACPIBA 0x010
#define SMBBA 0x014
#define SMBATPC 0x05B /* used to unlock xxxBA registers */
#define SMBHSTCFG 0x0E0
#define SMBSLVC 0x0E1
#define SMBCLK 0x0E2
#define SMBREV 0x008
/* ALI15X3 address lock bits */
#define ALI15X3_LOCK 0x06
/* ALI15X3 command constants */
#define ALI15X3_ABORT 0x02
#define ALI15X3_T_OUT 0x04
#define ALI15X3_QUICK 0x00
#define ALI15X3_BYTE 0x10
#define ALI15X3_BYTE_DATA 0x20
#define ALI15X3_WORD_DATA 0x30
#define ALI15X3_BLOCK_DATA 0x40
#define ALI15X3_BLOCK_CLR 0x80
/* ALI15X3 status register bits */
#define ALI15X3_STS_IDLE 0x04
#define ALI15X3_STS_BUSY 0x08
#define ALI15X3_STS_DONE 0x10
#define ALI15X3_STS_DEV 0x20 /* device error */
#define ALI15X3_STS_COLL 0x40 /* collision or no response */
#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
/*
addresses the i/o space gets mapped to,
@@ -110,52 +99,25 @@
#define SMB_IO_SIZE 0x20
#define ACPI_BASE 0x0
#define SMB_BASE 0x1
static u32 acpi_io_parm = 0;
static u32 smb_io_parm = 0;
MODULE_PARM(acpi_io_parm, "l");
MODULE_PARM(smb_io_parm, "l");
static u32 acpi_io = 0xEC00; /* Set I/O Base defaults here */
static u32 smb_io = 0xE800;
static int debug = 0;
MODULE_PARM(acpi_io, "l");
MODULE_PARM(smb_io, "l");
#ifdef M7101_DEBUG
MODULE_PARM(debug, "i");
#endif
/* status, used to indicate that io space needs to be freed */
static struct pci_dev *m7101 = NULL;
static int m7101_attached = FALSE;
static int m7101_inserted = FALSE;
extern void cleanup_module();
static rwlock_t m7101_lock = RW_LOCK_UNLOCKED;
static unsigned long m7101_lock_flags = 0;
static rwlock_t m7101_lock = RW_LOCK_UNLOCKED;
static unsigned long m7101_lock_flags = 0;
/*
* This function was shamelessly stolen from the kernel pci
* driver code.
*/
static void
pci_read_bases(struct pci_dev *dev, unsigned int howmany)
{
unsigned int reg;
u32 l;
for(reg=0; reg<howmany; reg++) {
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
if (l == 0xffffffff)
continue;
dev->base_address[reg] = l;
if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
== (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { reg++;
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
if (l) {
#if BITS_PER_LONG == 64
dev->base_address[reg-1] |= ((unsigned long) l) << 32;
#else
DBG("PCI: Unable to handle 64-bit address for device %02x:%02x\n",
dev->bus->number, dev->devfn);
dev->base_address[reg-1] = 0;
#endif
}
}
}
}
#ifdef M7101_DEBUG
static void
dump_dev_data(struct pci_dev *dev, int address_data)
{
@@ -166,17 +128,18 @@ dump_dev_data(struct pci_dev *dev, int address_data)
dev->vendor, dev->device);
if (address_data) {
printk("m7101: base_address[0]: 0x%08lx base_address[1]: 0x%08lx\n",
dev->base_address[0], dev->base_address[1]);
printk("m7101: base_address[2]: 0x%08lx base_address[3]: 0x%08lx\n",
dev->base_address[2], dev->base_address[3]);
printk("m7101: base_address[4]: 0x%08lx base_address[5]: 0x%08lx\n",
dev->base_address[4], dev->base_address[5]);
printk("m7101: resource[0]: 0x%08lx resource[1]: 0x%08lx\n",
dev->resource[0].start, dev->resource[1].start);
printk("m7101: resource[2]: 0x%08lx resource[3]: 0x%08lx\n",
dev->resource[2].start, dev->resource[3].start);
printk("m7101: resource[4]: 0x%08lx resource[5]: 0x%08lx\n",
dev->resource[4].start, dev->resource[5].start);
printk("m7101: rom_address: 0x%08lx \n",
dev->rom_address);
dev->resource[PCI_ROM_RESOURCE].start);
}
}
}
#endif
/*
* Checks whether PMU and SMB are enabled and turns them on in case they are not.
@@ -184,13 +147,12 @@ dump_dev_data(struct pci_dev *dev, int address_data)
* I/O
*/
static int
m7101_enable(struct pci_dev *dev, u32 *devfn){
m7101_enable(struct pci_dev *dev){
u8 val = 0;
u16 id = 0;
pci_read_config_byte(dev, 0x5F, &val);
DBG("m7101: M7101 config byte reading 0x%X.\n", val);
if (val & 0x4) {
if (val & 0x4) {
pci_write_config_byte(dev, 0x5F, val & 0xFB);
pci_read_config_byte(dev, 0x5F, &val);
if(val & 0x4) {
@@ -198,12 +160,42 @@ m7101_enable(struct pci_dev *dev, u32 *devfn){
return -EIO;
}
}
return 0;
}
/*
* Builds the basic pci_dev for the M7101
*/
static int
m7101_build(struct pci_dev **m7101, struct pci_bus *bus)
{
u32 devfn;
u16 id = 0;
u16 vid = 0;
int ret;
DBG("m7101: requesting kernel space for the m7101 entry.\n");
*m7101 = kmalloc(sizeof(**m7101), GFP_ATOMIC);
if(NULL == *m7101) {
printk("m7101: out of memory.\n");
return -ENOMEM;
}
/* minimally fill in structure for search */
/* The device should be on the same bus as the M1533. */
memset(*m7101, 0, sizeof(**m7101));
(*m7101)->bus = bus;
(*m7101)->sysdata = bus->sysdata;
(*m7101)->hdr_type = PCI_HEADER_TYPE_NORMAL;
DBG("m7101: now looking for M7101.\n");
for (id = 0, *devfn = 0; *devfn < 0xFF; (*devfn)++) {
pcibios_read_config_word(dev->bus->number, *devfn, PCI_DEVICE_ID, &id);
if (PCI_DEVICE_ID_AL_M7101 == id) {
for (id = 0, devfn = 0; devfn < 0xFF; devfn++) {
(*m7101)->devfn = devfn;
ret = pci_read_config_word(*m7101, PCI_DEVICE_ID, &id);
if (ret == 0 && PCI_DEVICE_ID_AL_M7101 == id) {
pci_read_config_word(*m7101, PCI_VENDOR_ID, &vid);
if(vid == PCI_VENDOR_ID_AL)
break;
}
}
@@ -211,45 +203,16 @@ m7101_enable(struct pci_dev *dev, u32 *devfn){
DBG("m7101: M7101 not found although M1533 present - strange.\n");
return -EACCES;
} else {
DBG("m7101: M7101 found and enabled. Devfn: 0x%X.\n", *devfn);
DBG("m7101: M7101 found and enabled. Devfn: 0x%X.\n", devfn);
}
return 0;
}
/*
* Builds the basic pci_dev for the M7101
*
*/
static int
m7101_build(struct pci_dev **m7101, u32 devfn, struct pci_bus *bus)
{
u32 val = 0;
/* We now have the devfn and bus of the M7101 device.
* let's put the device data together.
*/
if ((pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &val) ||
/* some broken boards return 0 if a slot is empty: */
val == 0xffffffff || val == 0x00000000 ||
val == 0x0000ffff || val == 0xffff0000)) {
* let's put the rest of the device data together.
*/
m7101 = NULL;
return -ENODEV;
} else {
DBG("m7101: requesting kernel space for the m7101 entry.\n");
*m7101 = kmalloc(sizeof(**m7101), GFP_ATOMIC);
if(NULL == *m7101)
{
printk("m7101: out of memory.\n");
return -ENOMEM;
}
memset(*m7101, 0, sizeof(**m7101));
(*m7101)->bus = bus;
(*m7101)->devfn = devfn;
(*m7101)->vendor = val & 0xffff;
(*m7101)->device = (val >> 16) & 0xffff;
}
return 0;
(*m7101)->vendor = PCI_VENDOR_ID_AL;
(*m7101)->hdr_type = PCI_HEADER_TYPE_NORMAL;
(*m7101)->device = PCI_DEVICE_ID_AL_M7101;
return(pci_setup_device(*m7101));
}
/*
@@ -267,7 +230,7 @@ m7101_unlock_registers(struct pci_dev *m7101)
if(val & ALI15X3_LOCK) {
DBG("m7101: need to unlock the address registers\n");
val &= ~ALI15X3_LOCK;
if (pci_write_config_byte(m7101, SMBATPC, val)) {
if (pci_write_config_byte(m7101, SMBATPC, val)) {
DBG("m7101: failed to write SMBATPC\n");
return -EIO;
}
@@ -283,149 +246,100 @@ m7101_set_io_address(struct pci_dev *m7101, u32 addr, int base_idx, int size)
{
if (!addr) {
printk("m7101: Sorry - cannot assign address 0 to region.\n");
return -EINVAL;
return -EINVAL;
}
if (check_region(addr, size)) {
printk("m7101: Requested IO-region 0x%x already in use.\n", addr);
return -EBUSY;
return -EBUSY;
} else {
m7101->base_address[base_idx] =
addr | PCI_BASE_ADDRESS_SPACE_IO;
m7101->resource[base_idx].start = addr;
}
return 0;
}
/*
* Maintain the ordering of the other devices.
* We know that first_on_bus and dev are on the same bus.
*/
static void
m7101_insert(struct pci_dev *m7101)
{
struct pci_dev *first_on_bus = NULL, *dev = NULL;
u32 devfn = 0;
unsigned char bus_number = m7101->bus->number;
/* Insert device into global chain of devices. */
/* We have at least one other sibling on this bus */
DBG("m7101: find first device in chain.\n");
first_on_bus = NULL; devfn = 0;
while (NULL == (first_on_bus = pci_find_slot(bus_number, devfn)) ) {
devfn++;
}
write_lock_irqsave(m7101_lock, m7101_lock_flags);
if (first_on_bus->devfn < m7101->devfn) {
DBG("m7101: inserting M7101 after other devices on bus 0x%X.\n",
bus_number);
dev = first_on_bus;
while (dev->sibling) {
if (dev->sibling->devfn > m7101->devfn) {
break;
}
dev = dev->sibling;
}
m7101->next = dev->next;
m7101->sibling = dev->sibling;
dev->next = m7101;
dev->sibling = m7101;
} else {
/*
* If we insert dev before first_on_bus, we have to find the
* device pointing to first_on_bus.
*/
DBG("m7101: inserting M7101 as first device on bus 0x%X.\n",
bus_number);
m7101->next = first_on_bus;
m7101->sibling = first_on_bus;
dev = pci_devices;
if (dev == first_on_bus) {
dev = m7101;
} else {
while (dev->next != first_on_bus) {
dev = dev->next;
}
/* We can't miss first_on_bus, can we ? */
dev->next = m7101;
}
}
write_unlock_irqrestore(m7101_lock, m7101_lock_flags);
}
/* Initialize the module */
int init_module(void)
{
struct pci_bus *bus = NULL;
struct pci_dev *dev = NULL;
u32 devfn = 0;
u32 acpi_addr = 0, smb_addr = 0;
u32 acpi_addr = 0, smb_addr = 0;
int ret = 0;
DBG("m7101: init_module().\n");
/* Are we on a PCI-Board? */
if (!pci_present()) {
printk("m7101: No pci board found - sorry.\n");
printk("m7101: No PCI bus found - sorry.\n");
return -ENODEV;
}
/* We want to be sure that the M7101 is not present yet. */
dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
if (dev) {
dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
if (dev) {
printk("m7101: M7101 already present, no need to run this module.\n");
dev = NULL;
return -EPERM;
}
#ifdef M7101_DEBUG
if(debug)
{
pci_remove_device(dev);
printk("m7101: removing device for testing\n");
m7101_inserted = 0;
return 0;
}
else
#endif
return -EPERM;
}
/* Are we operating a M15x3 chipset */
dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (NULL == dev) {
printk("m7101: This is not an ALi M15x3 chipset.\n");
dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (NULL == dev) {
printk("m7101: ALi M15xx chipset not found.\n");
return -ENODEV ;
} else {
/* we need the bus pointer later */
bus = dev->bus;
}
/* we need the bus pointer later */
bus = dev->bus;
if ( (ret = m7101_enable(dev, &devfn)) ) {
if ( (ret = m7101_enable(dev)) ) {
printk("m7101: Unable to turn on M7101 device - sorry!\n");
return ret;
}
if ( (ret = m7101_build(&m7101, devfn, bus)) ){
if ( (ret = m7101_build(&m7101, bus)) ){
return ret;
}
/* thus, now we have a rudimentary dev for M7101 ... */
/* check wether register need to be unlocked. */
/* thus, now we have a rudimentary dev for M7101 ... */
/* check wether register need to be unlocked. */
if ( (ret = m7101_unlock_registers(m7101)) ){
return ret;
}
/* Just for debugging purposes */
pci_read_bases(m7101, 6);
/*
* Handle address assignment for ACPI_IO
* If address is already assigned do nothing.
*/
acpi_addr = m7101->base_address[ACPI_BASE];
acpi_addr = m7101->resource[ACPI_BASE].start;
if (!acpi_addr) {
ret = m7101_set_io_address(m7101, acpi_io_parm,ACPI_BASE, ACPI_IO_SIZE);
acpi_io |= PCI_BASE_ADDRESS_SPACE_IO;
ret = m7101_set_io_address(m7101, acpi_io,ACPI_BASE, ACPI_IO_SIZE);
if (ret)
return ret;
acpi_addr = acpi_io;
}
/*
* Handle address assignment for SMB_IO
* If address is already assigned then do nothing.
*/
smb_addr = m7101->base_address[SMB_BASE];
smb_addr = m7101->resource[SMB_BASE].start;
if (!smb_addr) {
ret = m7101_set_io_address(m7101, smb_io_parm, SMB_BASE, SMB_IO_SIZE);
smb_io |= PCI_BASE_ADDRESS_SPACE_IO;
ret = m7101_set_io_address(m7101, smb_io, SMB_BASE, SMB_IO_SIZE);
if (ret)
return ret;
smb_addr = smb_io;
}
#ifdef M7101_DEBUG
@@ -433,60 +347,26 @@ int init_module(void)
#endif
if ( (ret = pci_enable_device(m7101)) ) {
printk("m7101: Unable to pci_enable M7101 device!\n");
return ret;
}
DBG("m7101: now inserting.\n");
m7101_insert(m7101);
pci_insert_device(m7101, m7101->bus);
printk("m7101: Enabled with ACPI I/O address 0x%04X and SMB I/O address 0x%04X\n",
acpi_addr, smb_addr);
m7101_inserted = TRUE;
DBG("m7101: now dumping global list.\n");
for (dev = pci_devices; NULL != dev->next ; dev = dev->next) {
#ifdef M7101_DEBUG
dump_dev_data(dev, 0);
dump_dev_data(dev->next, 0);
dump_dev_data(dev->sibling, 0);
printk("\n");
#endif
}
/* Attach the device to the proc listing. */
DBG("m7101: Attaching device to proc file system.\n");
if ( (ret = pci_proc_attach_device(m7101)) ){
printk("m7101: could not attach device to proc fs.\n");
/* Get it out of the way or /proc/bus/pci will be garbled. */
cleanup_module();
return ret;
} else {
m7101_attached = TRUE;
printk("m7101: device inserted.\n");
}
return 0;
}
void cleanup_module()
{
struct pci_dev *dev;
if (m7101_attached) {
pci_proc_detach_device(m7101);
m7101_attached = FALSE;
}
write_lock_irqsave(m7101_lock, m7101_lock_flags);
if (m7101_inserted) {
if (pci_devices == m7101)
pci_devices = m7101->next;
else {
dev = pci_devices;
while (dev->next != m7101) {
dev = dev->next;
}
dev->next = m7101->next;
if (dev->sibling) {
dev->sibling = m7101->sibling;
}
}
pci_remove_device(m7101);
m7101_inserted = FALSE;
}
write_unlock_irqrestore(m7101_lock, m7101_lock_flags);
@@ -495,5 +375,15 @@ void cleanup_module()
kfree(m7101);
printk("m7101: bye bye\n");
}
EXPORT_NO_SYMBOLS;
#ifdef MODULE
MODULE_AUTHOR("Burkhard Kohl <bku@buks.ipn.de>, "
"Frank Bauer <frank.bauer@nikocity.de>, "
"and Mark Studebaker <mdsxyz123@yahoo.com>");
MODULE_DESCRIPTION("M7101 PCI Inserter");
#endif /* MODULE */