Commit f347cc1b authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-voyager.bkbits.net/mca-sysfs-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents e482449c c845933e
...@@ -1108,6 +1108,8 @@ config MCA ...@@ -1108,6 +1108,8 @@ config MCA
<file:Documentation/mca.txt> (and especially the web page given <file:Documentation/mca.txt> (and especially the web page given
there) before attempting to build an MCA bus kernel. there) before attempting to build an MCA bus kernel.
source "drivers/mca/Kconfig"
config HOTPLUG config HOTPLUG
bool "Support for hot-pluggable devices" bool "Support for hot-pluggable devices"
---help--- ---help---
......
This diff is collapsed.
...@@ -44,5 +44,6 @@ obj-$(CONFIG_MD) += md/ ...@@ -44,5 +44,6 @@ obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
obj-$(CONFIG_ISDN_BOOL) += isdn/ obj-$(CONFIG_ISDN_BOOL) += isdn/
obj-$(CONFIG_MCA) += mca/
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
comment "Micro Channel Architecture Bus support"
depends on MCA
config MCA_LEGACY
bool "Legacy MCA API Support"
depends on MCA
help
This compiles in support for the old slot based MCA API. If you
have an unconverted MCA driver, you will need to say Y here. It
is safe to say Y anyway.
config MCA_PROC_FS
bool "Support for the mca entry in /proc"
depends on MCA_LEGACY && PROC_FS
help
If you want the old style /proc/mca directory in addition to the
new style sysfs say Y here.
# Makefile for the Linux MCA bus support
obj-y := mca-bus.o mca-device.o mca-driver.o
obj-$(CONFIG_MCA_PROC_FS) += mca-proc.o
obj-$(CONFIG_MCA_LEGACY) += mca-legacy.o
export-objs := mca-bus.o mca-legacy.o mca-proc.o mca-driver.o
include $(TOPDIR)/Rules.make
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA bus support functions for sysfs.
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
**-----------------------------------------------------------------------------
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/mca.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
/* Very few machines have more than one MCA bus. However, there are
* those that do (Voyager 35xx/5xxx), so we do it this way for future
* expansion. None that I know have more than 2 */
struct mca_bus *mca_root_busses[MAX_MCA_BUSSES];
#define MCA_DEVINFO(i,s) { .pos = i, .name = s }
struct mca_device_info {
short pos_id; /* the 2 byte pos id for this card */
char name[DEVICE_NAME_SIZE];
};
static int mca_bus_match (struct device *dev, struct device_driver *drv)
{
struct mca_device *mca_dev = to_mca_device (dev);
struct mca_driver *mca_drv = to_mca_driver (drv);
const short *mca_ids = mca_drv->id_table;
int i;
if (!mca_ids)
return 0;
for(i = 0; mca_ids[i]; i++) {
if (mca_ids[i] == mca_dev->pos_id) {
mca_dev->index = i;
return 1;
}
}
return 0;
}
struct bus_type mca_bus_type = {
.name = "MCA",
.match = mca_bus_match,
};
EXPORT_SYMBOL (mca_bus_type);
static ssize_t mca_show_pos_id(struct device *dev, char *buf, size_t count,
loff_t off)
{
/* four digits, \n and trailing \0 */
char mybuf[6];
struct mca_device *mca_dev = to_mca_device(dev);
int len;
if(mca_dev->pos_id < MCA_DUMMY_POS_START)
len = sprintf(mybuf, "%04x\n", mca_dev->pos_id);
else
len = sprintf(mybuf, "none\n");
len++;
if(len > off) {
len = min((size_t)(len - off), count);
memcpy(buf + off, mybuf + off, len);
} else {
len = 0;
}
return len;
}
static ssize_t mca_show_pos(struct device *dev, char *buf, size_t count,
loff_t off)
{
/* enough for 8 two byte hex chars plus space and new line */
char mybuf[26];
int j, len=0;
struct mca_device *mca_dev = to_mca_device(dev);
for(j=0; j<8; j++)
len += sprintf(mybuf+len, "%02x ", mca_dev->pos[j]);
/* change last trailing space to new line */
mybuf[len-1] = '\n';
len++;
if(len > off) {
len = min((size_t)(len - off), count);
memcpy(buf + off, mybuf + off, len);
} else {
len = 0;
}
return len;
}
static DEVICE_ATTR(id, S_IRUGO, mca_show_pos_id, NULL);
static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL);
int __init mca_register_device(int bus, struct mca_device *mca_dev)
{
struct mca_bus *mca_bus = mca_root_busses[bus];
mca_dev->dev.parent = &mca_bus->dev;
mca_dev->dev.bus = &mca_bus_type;
sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot);
mca_dev->dma_mask = mca_bus->default_dma_mask;
mca_dev->dev.dma_mask = &mca_dev->dma_mask;
if (device_register(&mca_dev->dev))
return 0;
device_create_file(&mca_dev->dev, &dev_attr_id);
device_create_file(&mca_dev->dev, &dev_attr_pos);
return 1;
}
/* */
struct mca_bus * __devinit mca_attach_bus(int bus)
{
struct mca_bus *mca_bus;
if (unlikely(mca_root_busses[bus] != NULL)) {
/* This should never happen, but just in case */
printk(KERN_EMERG "MCA tried to add already existing bus %d\n",
bus);
dump_stack();
return NULL;
}
mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL);
if (!mca_bus)
return NULL;
memset(mca_bus, 0, sizeof(struct mca_bus));
sprintf(mca_bus->dev.bus_id,"mca%d",bus);
sprintf(mca_bus->dev.name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
device_register(&mca_bus->dev);
mca_root_busses[bus] = mca_bus;
return mca_bus;
}
int __init mca_system_init (void)
{
return bus_register(&mca_bus_type);
}
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA device support functions
*
* These functions support the ongoing device access API.
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
**-----------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mca.h>
/**
* mca_device_read_stored_pos - read POS register from stored data
* @mca_dev: device to read from
* @reg: register to read from
*
* Fetch a POS value that was stored at boot time by the kernel
* when it scanned the MCA space. The register value is returned.
* Missing or invalid registers report 0.
*/
unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev, int reg)
{
if(reg < 0 || reg >= 8)
return 0;
return mca_dev->pos[reg];
}
EXPORT_SYMBOL(mca_device_read_stored_pos);
/**
* mca_device_read_pos - read POS register from card
* @mca_dev: device to read from
* @reg: register to read from
*
* Fetch a POS value directly from the hardware to obtain the
* current value. This is much slower than
* mca_device_read_stored_pos and may not be invoked from
* interrupt context. It handles the deep magic required for
* onboard devices transparently.
*/
unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_read_pos(mca_dev, reg);
return mca_dev->pos[reg];
}
EXPORT_SYMBOL(mca_device_read_pos);
/**
* mca_device_write_pos - read POS register from card
* @mca_dev: device to write pos register to
* @reg: register to write to
* @byte: byte to write to the POS registers
*
* Store a POS value directly to the hardware. You should not
* normally need to use this function and should have a very good
* knowledge of MCA bus before you do so. Doing this wrongly can
* damage the hardware.
*
* This function may not be used from interrupt context.
*
*/
void mca_device_write_pos(struct mca_device *mca_dev, int reg,
unsigned char byte)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
mca_bus->f.mca_write_pos(mca_dev, reg, byte);
}
EXPORT_SYMBOL(mca_device_write_pos);
/**
* mca_device_transform_irq - transform the ADF obtained IRQ
* @mca_device: device whose irq needs transforming
* @irq: input irq from ADF
*
* MCA Adapter Definition Files (ADF) contain irq, ioport, memory
* etc. definitions. In systems with more than one bus, these need
* to be transformed through bus mapping functions to get the real
* system global quantities.
*
* This function transforms the interrupt number and returns the
* transformed system global interrupt
*/
int mca_device_transform_irq(struct mca_device *mca_dev, int irq)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_transform_irq(mca_dev, irq);
}
EXPORT_SYMBOL(mca_device_transform_irq);
/**
* mca_device_transform_ioport - transform the ADF obtained I/O port
* @mca_device: device whose port needs transforming
* @ioport: input I/O port from ADF
*
* MCA Adapter Definition Files (ADF) contain irq, ioport, memory
* etc. definitions. In systems with more than one bus, these need
* to be transformed through bus mapping functions to get the real
* system global quantities.
*
* This function transforms the I/O port number and returns the
* transformed system global port number.
*
* This transformation can be assumed to be linear for port ranges.
*/
int mca_device_transform_ioport(struct mca_device *mca_dev, int port)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_transform_ioport(mca_dev, port);
}
EXPORT_SYMBOL(mca_device_transform_ioport);
/**
* mca_device_transform_memory - transform the ADF obtained memory
* @mca_device: device whose memory region needs transforming
* @mem: memory region start from ADF
*
* MCA Adapter Definition Files (ADF) contain irq, ioport, memory
* etc. definitions. In systems with more than one bus, these need
* to be transformed through bus mapping functions to get the real
* system global quantities.
*
* This function transforms the memory region start and returns the
* transformed system global memory region (physical).
*
* This transformation can be assumed to be linear for region ranges.
*/
void *mca_device_transform_memory(struct mca_device *mca_dev, void *mem)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_transform_memory(mca_dev, mem);
}
EXPORT_SYMBOL(mca_device_transform_memory);
/**
* mca_device_claimed - check if claimed by driver
* @mca_dev: device to check
*
* Returns 1 if the slot has been claimed by a driver
*/
int mca_device_claimed(struct mca_device *mca_dev)
{
return mca_dev->driver_loaded;
}
EXPORT_SYMBOL(mca_device_claimed);
/**
* mca_device_set_claim - set the claim value of the driver
* @mca_dev: device to set value for
* @val: claim value to set (1 claimed, 0 unclaimed)
*/
void mca_device_set_claim(struct mca_device *mca_dev, int val)
{
mca_dev->driver_loaded = val;
}
EXPORT_SYMBOL(mca_device_set_claim);
/**
* mca_device_status - get the status of the device
* @mca_device: device to get
*
* returns an enumeration of the device status:
*
* MCA_ADAPTER_NORMAL adapter is OK.
* MCA_ADAPTER_NONE no adapter at device (should never happen).
* MCA_ADAPTER_DISABLED adapter is disabled.
* MCA_ADAPTER_ERROR adapter cannot be initialised.
*/
enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev)
{
return mca_dev->status;
}
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA driver support functions for sysfs.
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
**-----------------------------------------------------------------------------
*/
#include <linux/device.h>
#include <linux/mca.h>
#include <linux/module.h>
int mca_register_driver(struct mca_driver *mca_drv)
{
int r;
mca_drv->driver.bus = &mca_bus_type;
if ((r = driver_register(&mca_drv->driver)) < 0)
return r;
return 0;
}
EXPORT_SYMBOL(mca_register_driver);
void mca_unregister_driver(struct mca_driver *mca_drv)
{
driver_unregister(&mca_drv->driver);
}
EXPORT_SYMBOL(mca_unregister_driver);
This diff is collapsed.
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA bus support functions for the proc fs.
*
* NOTE: this code *requires* the legacy MCA api.
*
* Legacy API means the API that operates in terms of MCA slot number
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
**-----------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/mca.h>
static int get_mca_info_helper(struct mca_device *mca_dev, char *page, int len)
{
int j;
for(j=0; j<8; j++)
len += sprintf(page+len, "%02x ",
mca_dev ? mca_dev->pos[j] : 0xff);
len += sprintf(page+len, " %s\n", mca_dev ? mca_dev->dev.name : "");
return len;
}
int get_mca_info(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int i, len = 0;
if(MCA_bus) {
struct mca_device *mca_dev;
/* Format POS registers of eight MCA slots */
for(i=0; i<MCA_MAX_SLOT_NR; i++) {
mca_dev = mca_find_device_by_slot(i);
len += sprintf(page+len, "Slot %d: ", i+1);
len = get_mca_info_helper(mca_dev, page, len);
}
/* Format POS registers of integrated video subsystem */
mca_dev = mca_find_device_by_slot(MCA_INTEGVIDEO);
len += sprintf(page+len, "Video : ");
len = get_mca_info_helper(mca_dev, page, len);
/* Format POS registers of integrated SCSI subsystem */
mca_dev = mca_find_device_by_slot(MCA_INTEGSCSI);
len += sprintf(page+len, "SCSI : ");
len = get_mca_info_helper(mca_dev, page, len);
/* Format POS registers of motherboard */
mca_dev = mca_find_device_by_slot(MCA_MOTHERBOARD);
len += sprintf(page+len, "Planar: ");
len = get_mca_info_helper(mca_dev, page, len);
} else {
/* Leave it empty if MCA not detected - this should *never*
* happen!
*/
}
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
/*--------------------------------------------------------------------*/
static int mca_default_procfn(char* buf, struct mca_device *mca_dev)
{
int len = 0, i;
int slot = mca_dev->slot;
/* Print out the basic information */
if(slot < MCA_MAX_SLOT_NR) {
len += sprintf(buf+len, "Slot: %d\n", slot+1);
} else if(slot == MCA_INTEGSCSI) {
len += sprintf(buf+len, "Integrated SCSI Adapter\n");
} else if(slot == MCA_INTEGVIDEO) {
len += sprintf(buf+len, "Integrated Video Adapter\n");
} else if(slot == MCA_MOTHERBOARD) {
len += sprintf(buf+len, "Motherboard\n");
}
if(mca_dev->dev.name[0]) {
/* Drivers might register a name without /proc handler... */
len += sprintf(buf+len, "Adapter Name: %s\n",
mca_dev->dev.name);
} else {
len += sprintf(buf+len, "Adapter Name: Unknown\n");
}
len += sprintf(buf+len, "Id: %02x%02x\n",
mca_dev->pos[1], mca_dev->pos[0]);
len += sprintf(buf+len, "Enabled: %s\nPOS: ",
mca_isenabled(slot) ? "Yes" : "No");
for(i=0; i<8; i++) {
len += sprintf(buf+len, "%02x ", mca_dev->pos[i]);
}
len += sprintf(buf+len, "\nDriver Installed: %s",
mca_is_adapter_used(slot) ? "Yes" : "No");
buf[len++] = '\n';
buf[len] = 0;
return len;
} /* mca_default_procfn() */
static int get_mca_machine_info(char* page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
static int mca_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct mca_device *mca_dev = (struct mca_device *)data;
int len = 0;
/* Get the standard info */
len = mca_default_procfn(page, mca_dev);
/* Do any device-specific processing, if there is any */
if(mca_dev->procfn) {
len += mca_dev->procfn(page+len, mca_dev->slot,
mca_dev->proc_dev);
}
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
} /* mca_read_proc() */
/*--------------------------------------------------------------------*/
void __init mca_do_proc_init(void)
{
int i;
struct proc_dir_entry *proc_mca;
struct proc_dir_entry* node = NULL;
struct mca_device *mca_dev;
proc_mca = proc_mkdir("mca", &proc_root);
create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
/* Initialize /proc/mca entries for existing adapters */
for(i = 0; i < MCA_NUMADAPTERS; i++) {
mca_dev = mca_find_device_by_slot(i);
if(!mca_dev)
continue;
mca_dev->procfn = NULL;
if(i < MCA_MAX_SLOT_NR) sprintf(mca_dev->procname,"slot%d", i+1);
else if(i == MCA_INTEGVIDEO) sprintf(mca_dev->procname,"video");
else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi");
else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar");
if(!mca_isadapter(i)) continue;
node = create_proc_read_entry(mca_dev->procname, 0, proc_mca,
mca_read_proc, (void *)mca_dev);
if(node == NULL) {
printk("Failed to allocate memory for MCA proc-entries!");
return;
}
}
} /* mca_do_proc_init() */
/**
* mca_set_adapter_procfn - Set the /proc callback
* @slot: slot to configure
* @procfn: callback function to call for /proc
* @dev: device information passed to the callback
*
* This sets up an information callback for /proc/mca/slot?. The
* function is called with the buffer, slot, and device pointer (or
* some equally informative context information, or nothing, if you
* prefer), and is expected to put useful information into the
* buffer. The adapter name, ID, and POS registers get printed
* before this is called though, so don't do it again.
*
* This should be called with a %NULL @procfn when a module
* unregisters, thus preventing kernel crashes and other such
* nastiness.
*/
void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* proc_dev)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return;
mca_dev->procfn = procfn;
mca_dev->proc_dev = proc_dev;
}
EXPORT_SYMBOL(mca_set_adapter_procfn);
...@@ -48,7 +48,6 @@ extern int ne2_probe(struct net_device *dev); ...@@ -48,7 +48,6 @@ extern int ne2_probe(struct net_device *dev);
extern int hp100_probe(struct net_device *dev); extern int hp100_probe(struct net_device *dev);
extern int ultra_probe(struct net_device *dev); extern int ultra_probe(struct net_device *dev);
extern int ultra32_probe(struct net_device *dev); extern int ultra32_probe(struct net_device *dev);
extern int ultramca_probe(struct net_device *dev);
extern int wd_probe(struct net_device *dev); extern int wd_probe(struct net_device *dev);
extern int el2_probe(struct net_device *dev); extern int el2_probe(struct net_device *dev);
extern int ne_probe(struct net_device *dev); extern int ne_probe(struct net_device *dev);
...@@ -191,9 +190,6 @@ static struct devprobe eisa_probes[] __initdata = { ...@@ -191,9 +190,6 @@ static struct devprobe eisa_probes[] __initdata = {
static struct devprobe mca_probes[] __initdata = { static struct devprobe mca_probes[] __initdata = {
#ifdef CONFIG_ULTRAMCA
{ultramca_probe, 0},
#endif
#ifdef CONFIG_NE2_MCA #ifdef CONFIG_NE2_MCA
{ne2_probe, 0}, {ne2_probe, 0},
#endif #endif
......
This diff is collapsed.
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h>
#include <linux/mca.h> #include <linux/mca.h>
#include <asm/dma.h> #include <asm/dma.h>
...@@ -182,131 +183,140 @@ param_setup(char *string) ...@@ -182,131 +183,140 @@ param_setup(char *string)
__setup("NCR_D700=", param_setup); __setup("NCR_D700=", param_setup);
#endif #endif
/* private stack allocated structure for passing device information from
* detect to probe */
struct NCR_700_info {
Scsi_Host_Template *tpnt;
int found;
};
/* Detect a D700 card. Note, because of the set up---the chips are /* Detect a D700 card. Note, because of the set up---the chips are
* essentially connectecd to the MCA bus independently, it is easier * essentially connectecd to the MCA bus independently, it is easier
* to set them up as two separate host adapters, rather than one * to set them up as two separate host adapters, rather than one
* adapter with two channels */ * adapter with two channels */
STATIC int __init static int
D700_detect(Scsi_Host_Template *tpnt) NCR_D700_probe(struct device *dev)
{ {
int slot = 0;
int found = 0;
int differential; int differential;
int banner = 1; static int banner = 1;
struct mca_device *mca_dev = to_mca_device(dev);
if(!MCA_bus) int slot = mca_dev->slot;
return 0; struct NCR_700_info *info = to_mca_driver(dev->driver)->driver_data;
int found = 0;
#ifdef MODULE int irq, i;
if(NCR_D700) int pos3j, pos3k, pos3a, pos3b, pos4;
param_setup(NCR_D700); __u32 base_addr, offset_addr;
#endif struct Scsi_Host *host = NULL;
/* enable board interrupt */
pos4 = mca_device_read_pos(mca_dev, 4);
pos4 |= 0x4;
mca_device_write_pos(mca_dev, 4, pos4);
mca_device_write_pos(mca_dev, 6, 9);
pos3j = mca_device_read_pos(mca_dev, 3);
mca_device_write_pos(mca_dev, 6, 10);
pos3k = mca_device_read_pos(mca_dev, 3);
mca_device_write_pos(mca_dev, 6, 0);
pos3a = mca_device_read_pos(mca_dev, 3);
mca_device_write_pos(mca_dev, 6, 1);
pos3b = mca_device_read_pos(mca_dev, 3);
base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0;
offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70;
irq = (pos4 & 0x3) + 11;
if(irq >= 13)
irq++;
if(banner) {
printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n"
"NCR D700: Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n"
"NCR D700:\n");
banner = 0;
}
/* now do the bus related transforms */
irq = mca_device_transform_irq(mca_dev, irq);
base_addr = mca_device_transform_ioport(mca_dev, base_addr);
offset_addr = mca_device_transform_ioport(mca_dev, offset_addr);
printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr);
info->tpnt->proc_name = "NCR_D700";
/*outb(BOARD_RESET, base_addr);*/
/* clear any pending interrupts */
(void)inb(base_addr + 0x08);
/* get modctl, used later for setting diff bits */
switch(differential = (inb(base_addr + 0x08) >> 6)) {
case 0x00:
/* only SIOP1 differential */
differential = 0x02;
break;
case 0x01:
/* Both SIOPs differential */
differential = 0x03;
break;
case 0x03:
/* No SIOPs differential */
differential = 0x00;
break;
default:
printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n",
differential);
differential = 0x00;
break;
}
for(slot = 0; (slot = mca_find_adapter(NCR_D700_MCA_ID, slot)) != MCA_NOTFOUND; slot++) { /* plumb in both 700 chips */
int irq, i; for(i=0; i<2; i++) {
int pos3j, pos3k, pos3a, pos3b, pos4; __u32 region = offset_addr | (0x80 * i);
__u32 base_addr, offset_addr; struct NCR_700_Host_Parameters *hostdata =
struct Scsi_Host *host = NULL; kmalloc(sizeof(struct NCR_700_Host_Parameters),
GFP_KERNEL);
/* enable board interrupt */ if(hostdata == NULL) {
pos4 = mca_read_pos(slot, 4); printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i);
pos4 |= 0x4; continue;
mca_write_pos(slot, 4, pos4);
mca_write_pos(slot, 6, 9);
pos3j = mca_read_pos(slot, 3);
mca_write_pos(slot, 6, 10);
pos3k = mca_read_pos(slot, 3);
mca_write_pos(slot, 6, 0);
pos3a = mca_read_pos(slot, 3);
mca_write_pos(slot, 6, 1);
pos3b = mca_read_pos(slot, 3);
base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0;
offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70;
irq = (pos4 & 0x3) + 11;
if(irq >= 13)
irq++;
if(banner) {
printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n"
"NCR D700: Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n"
"NCR D700:\n");
banner = 0;
} }
printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr); memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
if(request_region(region, 64, "NCR_D700") == NULL) {
tpnt->proc_name = "NCR_D700"; printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region);
kfree(hostdata);
/*outb(BOARD_RESET, base_addr);*/ continue;
/* clear any pending interrupts */
(void)inb(base_addr + 0x08);
/* get modctl, used later for setting diff bits */
switch(differential = (inb(base_addr + 0x08) >> 6)) {
case 0x00:
/* only SIOP1 differential */
differential = 0x02;
break;
case 0x01:
/* Both SIOPs differential */
differential = 0x03;
break;
case 0x03:
/* No SIOPs differential */
differential = 0x00;
break;
default:
printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n",
differential);
differential = 0x00;
break;
} }
/* plumb in both 700 chips */ /* Fill in the three required pieces of hostdata */
for(i=0; i<2; i++) { hostdata->base = region;
__u32 region = offset_addr | (0x80 * i); hostdata->differential = (((1<<i) & differential) != 0);
struct NCR_700_Host_Parameters *hostdata = hostdata->clock = NCR_D700_CLOCK_MHZ;
kmalloc(sizeof(struct NCR_700_Host_Parameters), /* and register the chip */
GFP_KERNEL); if((host = NCR_700_detect(info->tpnt, hostdata)) == NULL) {
if(hostdata == NULL) { kfree(hostdata);
printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i); release_region(host->base, 64);
continue; continue;
} }
memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); host->irq = irq;
if(request_region(region, 64, "NCR_D700") == NULL) { /* FIXME: Read this from SUS */
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region); host->this_id = id_array[slot * 2 + i];
kfree(hostdata); printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
continue; i, host->this_id);
} if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
/* Fill in the three required pieces of hostdata */ scsi_unregister(host);
hostdata->base = region; NCR_700_release(host);
hostdata->differential = (((1<<i) & differential) != 0); continue;
hostdata->clock = NCR_D700_CLOCK_MHZ;
/* and register the chip */
if((host = NCR_700_detect(tpnt, hostdata)) == NULL) {
kfree(hostdata);
release_region(host->base, 64);
continue;
}
host->irq = irq;
/* FIXME: Read this from SUS */
host->this_id = id_array[slot * 2 + i];
printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
i, host->this_id);
if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
scsi_unregister(host);
NCR_700_release(host);
continue;
}
found++;
mca_set_adapter_name(slot, "NCR D700 SCSI Adapter (version " NCR_D700_VERSION ")");
} }
scsi_set_device(host, dev);
found++;
}
info->found += found;
if(found) {
mca_device_set_claim(mca_dev, 1);
strncpy(dev->name, "NCR_D700", sizeof(dev->name));
} }
return found; return found? 0 : -ENODEV;
} }
...@@ -323,7 +333,38 @@ D700_release(struct Scsi_Host *host) ...@@ -323,7 +333,38 @@ D700_release(struct Scsi_Host *host)
return 1; return 1;
} }
static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
struct mca_driver NCR_D700_driver = {
.id_table = NCR_D700_id_table,
.driver = {
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
},
};
STATIC int __init
D700_detect(Scsi_Host_Template *tpnt)
{
struct NCR_700_info info;
if(!MCA_bus)
return 0;
#ifdef MODULE
if(NCR_D700)
param_setup(NCR_D700);
#endif
info.tpnt = tpnt;
info.found = 0;
NCR_D700_driver.driver_data = &info;
mca_register_driver(&NCR_D700_driver);
return info.found;
}
static Scsi_Host_Template driver_template = NCR_D700_SCSI; static Scsi_Host_Template driver_template = NCR_D700_SCSI;
#include "scsi_module.c" #include "scsi_module.c"
......
/* -*- mode: c; c-basic-offset: 8 -*- */
/* Platform specific MCA defines */
#ifndef _ASM_MCA_H
#define _ASM_MCA_H
/* Maximal number of MCA slots - actually, some machines have less, but
* they all have sufficient number of POS registers to cover 8.
*/
#define MCA_MAX_SLOT_NR 8
/* Most machines have only one MCA bus. The only multiple bus machines
* I know have at most two */
#define MAX_MCA_BUSSES 2
#define MCA_PRIMARY_BUS 0
#define MCA_SECONDARY_BUS 1
/* Dummy slot numbers on primary MCA for integrated functions */
#define MCA_INTEGSCSI (MCA_MAX_SLOT_NR)
#define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1)
#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2)
/* Dummy POS values for integrated functions */
#define MCA_DUMMY_POS_START 0x10000
#define MCA_INTEGSCSI_POS (MCA_DUMMY_POS_START+1)
#define MCA_INTEGVIDEO_POS (MCA_DUMMY_POS_START+2)
#define MCA_MOTHERBOARD_POS (MCA_DUMMY_POS_START+3)
/* MCA registers */
#define MCA_MOTHERBOARD_SETUP_REG 0x94
#define MCA_ADAPTER_SETUP_REG 0x96
#define MCA_POS_REG(n) (0x100+(n))
#define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
/* Max number of adapters, including both slots and various integrated
* things.
*/
#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
/* lock to protect access to the MCA registers */
extern spinlock_t mca_lock;
#endif
/* -*- mode: c; c-basic-offset: 8 -*- */
/* This is the function prototypes for the old legacy MCA interface
*
* Please move your driver to the new sysfs based one instead */
#ifndef _LINUX_MCA_LEGACY_H
#define _LINUX_MCA_LEGACY_H
/* MCA_NOTFOUND is an error condition. The other two indicate
* motherboard POS registers contain the adapter. They might be
* returned by the mca_find_adapter() function, and can be used as
* arguments to mca_read_stored_pos(). I'm not going to allow direct
* access to the motherboard registers until we run across an adapter
* that requires it. We don't know enough about them to know if it's
* safe.
*
* See Documentation/mca.txt or one of the existing drivers for
* more information.
*/
#define MCA_NOTFOUND (-1)
/* Returns the slot of the first enabled adapter matching id. User can
* specify a starting slot beyond zero, to deal with detecting multiple
* devices. Returns MCA_NOTFOUND if id not found. Also checks the
* integrated adapters.
*/
extern int mca_find_adapter(int id, int start);
extern int mca_find_unused_adapter(int id, int start);
/* adapter state info - returns 0 if no */
extern int mca_isadapter(int slot);
extern int mca_isenabled(int slot);
extern int mca_is_adapter_used(int slot);
extern int mca_mark_as_used(int slot);
extern void mca_mark_as_unused(int slot);
/* gets a byte out of POS register (stored in memory) */
extern unsigned char mca_read_stored_pos(int slot, int reg);
/* This can be expanded later. Right now, it gives us a way of
* getting meaningful information into the MCA_info structure,
* so we can have a more interesting /proc/mca.
*/
extern void mca_set_adapter_name(int slot, char* name);
extern char* mca_get_adapter_name(int slot);
/* These routines actually mess with the hardware POS registers. They
* temporarily disable the device (and interrupts), so make sure you know
* what you're doing if you use them. Furthermore, writing to a POS may
* result in two devices trying to share a resource, which in turn can
* result in multiple devices sharing memory spaces, IRQs, or even trashing
* hardware. YOU HAVE BEEN WARNED.
*
* You can only access slots with this. Motherboard registers are off
* limits.
*/
/* read a byte from the specified POS register. */
extern unsigned char mca_read_pos(int slot, int reg);
/* write a byte to the specified POS register. */
extern void mca_write_pos(int slot, int reg, unsigned char byte);
#endif
...@@ -6,6 +6,14 @@ ...@@ -6,6 +6,14 @@
#ifndef _LINUX_MCA_H #ifndef _LINUX_MCA_H
#define _LINUX_MCA_H #define _LINUX_MCA_H
/* FIXME: This shouldn't happen, but we need everything that previously
* included mca.h to compile. Take it out later when the MCA #includes
* are sorted out */
#include <linux/device.h>
/* get the platform specific defines */
#include <asm/mca.h>
/* The detection of MCA bus is done in the real mode (using BIOS). /* The detection of MCA bus is done in the real mode (using BIOS).
* The information is exported to the protected code, where this * The information is exported to the protected code, where this
* variable is set to one in case MCA bus was detected. * variable is set to one in case MCA bus was detected.
...@@ -14,58 +22,6 @@ ...@@ -14,58 +22,6 @@
extern int MCA_bus; extern int MCA_bus;
#endif #endif
/* Maximal number of MCA slots - actually, some machines have less, but
* they all have sufficient number of POS registers to cover 8.
*/
#define MCA_MAX_SLOT_NR 8
/* MCA_NOTFOUND is an error condition. The other two indicate
* motherboard POS registers contain the adapter. They might be
* returned by the mca_find_adapter() function, and can be used as
* arguments to mca_read_stored_pos(). I'm not going to allow direct
* access to the motherboard registers until we run across an adapter
* that requires it. We don't know enough about them to know if it's
* safe.
*
* See Documentation/mca.txt or one of the existing drivers for
* more information.
*/
#define MCA_NOTFOUND (-1)
#define MCA_INTEGSCSI (MCA_MAX_SLOT_NR)
#define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1)
#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2)
/* Max number of adapters, including both slots and various integrated
* things.
*/
#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
/* Returns the slot of the first enabled adapter matching id. User can
* specify a starting slot beyond zero, to deal with detecting multiple
* devices. Returns MCA_NOTFOUND if id not found. Also checks the
* integrated adapters.
*/
extern int mca_find_adapter(int id, int start);
extern int mca_find_unused_adapter(int id, int start);
/* adapter state info - returns 0 if no */
extern int mca_isadapter(int slot);
extern int mca_isenabled(int slot);
extern int mca_is_adapter_used(int slot);
extern int mca_mark_as_used(int slot);
extern void mca_mark_as_unused(int slot);
/* gets a byte out of POS register (stored in memory) */
extern unsigned char mca_read_stored_pos(int slot, int reg);
/* This can be expanded later. Right now, it gives us a way of
* getting meaningful information into the MCA_info structure,
* so we can have a more interesting /proc/mca.
*/
extern void mca_set_adapter_name(int slot, char* name);
extern char* mca_get_adapter_name(int slot);
/* This sets up an information callback for /proc/mca/slot?. The /* This sets up an information callback for /proc/mca/slot?. The
* function is called with the buffer, slot, and device pointer (or * function is called with the buffer, slot, and device pointer (or
* some equally informative context information, or nothing, if you * some equally informative context information, or nothing, if you
...@@ -78,28 +34,115 @@ extern char* mca_get_adapter_name(int slot); ...@@ -78,28 +34,115 @@ extern char* mca_get_adapter_name(int slot);
* nastiness. * nastiness.
*/ */
typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev); typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev);
extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
/* These routines actually mess with the hardware POS registers. They
* temporarily disable the device (and interrupts), so make sure you know
* what you're doing if you use them. Furthermore, writing to a POS may
* result in two devices trying to share a resource, which in turn can
* result in multiple devices sharing memory spaces, IRQs, or even trashing
* hardware. YOU HAVE BEEN WARNED.
*
* You can only access slots with this. Motherboard registers are off
* limits.
*/
/* read a byte from the specified POS register. */
extern unsigned char mca_read_pos(int slot, int reg);
/* write a byte to the specified POS register. */
extern void mca_write_pos(int slot, int reg, unsigned char byte);
/* Should only be called by the NMI interrupt handler, this will do some /* Should only be called by the NMI interrupt handler, this will do some
* fancy stuff to figure out what might have generated a NMI. * fancy stuff to figure out what might have generated a NMI.
*/ */
extern void mca_handle_nmi(void); extern void mca_handle_nmi(void);
enum MCA_AdapterStatus {
MCA_ADAPTER_NORMAL = 0,
MCA_ADAPTER_NONE = 1,
MCA_ADAPTER_DISABLED = 2,
MCA_ADAPTER_ERROR = 3
};
struct mca_device {
u64 dma_mask;
int pos_id;
int slot;
/* index into id_table, set by the bus match routine */
int index;
/* is there a driver installed? 0 - No, 1 - Yes */
int driver_loaded;
/* POS registers */
unsigned char pos[8];
/* if a pseudo adapter of the motherboard, this is the motherboard
* register value to use for setup cycles */
short pos_register;
enum MCA_AdapterStatus status;
#ifdef CONFIG_MCA_PROC_FS
/* name of the proc/mca file */
char procname[8];
/* /proc info callback */
MCA_ProcFn procfn;
/* device/context info for proc callback */
void *proc_dev;
#endif
struct device dev;
};
#define to_mca_device(mdev) container_of(mdev, struct mca_device, dev)
struct mca_bus_accessor_functions {
unsigned char (*mca_read_pos)(struct mca_device *, int reg);
void (*mca_write_pos)(struct mca_device *, int reg,
unsigned char byte);
int (*mca_transform_irq)(struct mca_device *, int irq);
int (*mca_transform_ioport)(struct mca_device *,
int region);
void * (*mca_transform_memory)(struct mca_device *,
void *memory);
};
struct mca_bus {
u64 default_dma_mask;
int number;
struct mca_bus_accessor_functions f;
struct device dev;
};
#define to_mca_bus(mdev) container_of(mdev, struct mca_bus, dev)
struct mca_driver {
const short *id_table;
void *driver_data;
struct device_driver driver;
};
#define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
/* Ongoing supported API functions */
extern struct mca_device *mca_find_device_by_slot(int slot);
extern int mca_system_init(void);
extern struct mca_bus *mca_attach_bus(int);
extern unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev,
int reg);
extern unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg);
extern void mca_device_write_pos(struct mca_device *mca_dev, int reg,
unsigned char byte);
extern int mca_device_transform_irq(struct mca_device *mca_dev, int irq);
extern int mca_device_transform_ioport(struct mca_device *mca_dev, int port);
extern void *mca_device_transform_memory(struct mca_device *mca_dev,
void *mem);
extern int mca_device_claimed(struct mca_device *mca_dev);
extern void mca_device_set_claim(struct mca_device *mca_dev, int val);
extern enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev);
extern struct bus_type mca_bus_type;
extern int mca_register_driver(struct mca_driver *drv);
extern void mca_unregister_driver(struct mca_driver *drv);
/* WARNING: only called by the boot time device setup */
extern int mca_register_device(int bus, struct mca_device *mca_dev);
#ifdef CONFIG_MCA_LEGACY
#include <linux/mca-legacy.h>
#endif
#ifdef CONFIG_MCA_PROC_FS
extern void mca_do_proc_init(void);
extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
#else
static inline void mca_do_proc_init(void)
{
}
static inline void mca_set_adapter_procfn(int slot, MCA_ProcFn *fn, void* dev)
{
}
#endif
#endif /* _LINUX_MCA_H */ #endif /* _LINUX_MCA_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment