Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
14
drivers/mca/Kconfig
Normal file
14
drivers/mca/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
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.
|
7
drivers/mca/Makefile
Normal file
7
drivers/mca/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
# 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
|
||||
|
149
drivers/mca/mca-bus.c
Normal file
149
drivers/mca/mca-bus.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/* -*- 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 */
|
||||
static 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)
|
||||
{
|
||||
/* four digits, \n and trailing \0 */
|
||||
struct mca_device *mca_dev = to_mca_device(dev);
|
||||
int len;
|
||||
|
||||
if(mca_dev->pos_id < MCA_DUMMY_POS_START)
|
||||
len = sprintf(buf, "%04x\n", mca_dev->pos_id);
|
||||
else
|
||||
len = sprintf(buf, "none\n");
|
||||
return len;
|
||||
}
|
||||
static ssize_t mca_show_pos(struct device *dev, char *buf)
|
||||
{
|
||||
/* enough for 8 two byte hex chars plus space and new line */
|
||||
int j, len=0;
|
||||
struct mca_device *mca_dev = to_mca_device(dev);
|
||||
|
||||
for(j=0; j<8; j++)
|
||||
len += sprintf(buf+len, "%02x ", mca_dev->pos[j]);
|
||||
/* change last trailing space to new line */
|
||||
buf[len-1] = '\n';
|
||||
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;
|
||||
mca_dev->dev.coherent_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->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);
|
||||
}
|
217
drivers/mca/mca-device.c
Normal file
217
drivers/mca/mca-device.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
EXPORT_SYMBOL(mca_device_status);
|
||||
|
||||
/**
|
||||
* mca_device_set_name - set the name of the device
|
||||
* @mca_device: device to set the name of
|
||||
* @name: name to set
|
||||
*/
|
||||
void mca_device_set_name(struct mca_device *mca_dev, const char *name)
|
||||
{
|
||||
if(!mca_dev)
|
||||
return;
|
||||
|
||||
strlcpy(mca_dev->name, name, sizeof(mca_dev->name));
|
||||
}
|
||||
EXPORT_SYMBOL(mca_device_set_name);
|
50
drivers/mca/mca-driver.c
Normal file
50
drivers/mca/mca-driver.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/* -*- 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;
|
||||
|
||||
if (MCA_bus) {
|
||||
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)
|
||||
{
|
||||
if (MCA_bus)
|
||||
driver_unregister(&mca_drv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_unregister_driver);
|
348
drivers/mca/mca-legacy.c
Normal file
348
drivers/mca/mca-legacy.c
Normal file
@@ -0,0 +1,348 @@
|
||||
/* -*- mode: c; c-basic-offset: 8 -*- */
|
||||
|
||||
/*
|
||||
* MCA bus support functions for legacy (2.4) 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/device.h>
|
||||
#include <linux/mca-legacy.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* NOTE: This structure is stack allocated */
|
||||
struct mca_find_adapter_info {
|
||||
int id;
|
||||
int slot;
|
||||
struct mca_device *mca_dev;
|
||||
};
|
||||
|
||||
/* The purpose of this iterator is to loop over all the devices and
|
||||
* find the one with the smallest slot number that's just greater than
|
||||
* or equal to the required slot with a matching id */
|
||||
static int mca_find_adapter_callback(struct device *dev, void *data)
|
||||
{
|
||||
struct mca_find_adapter_info *info = data;
|
||||
struct mca_device *mca_dev = to_mca_device(dev);
|
||||
|
||||
if(mca_dev->pos_id != info->id)
|
||||
return 0;
|
||||
|
||||
if(mca_dev->slot < info->slot)
|
||||
return 0;
|
||||
|
||||
if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
|
||||
info->mca_dev = mca_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mca_find_adapter - scan for adapters
|
||||
* @id: MCA identification to search for
|
||||
* @start: starting slot
|
||||
*
|
||||
* Search the MCA configuration for adapters matching the 16bit
|
||||
* ID given. The first time it should be called with start as zero
|
||||
* and then further calls made passing the return value of the
|
||||
* previous call until %MCA_NOTFOUND is returned.
|
||||
*
|
||||
* Disabled adapters are not reported.
|
||||
*/
|
||||
|
||||
int mca_find_adapter(int id, int start)
|
||||
{
|
||||
struct mca_find_adapter_info info;
|
||||
|
||||
if(id == 0xffff)
|
||||
return MCA_NOTFOUND;
|
||||
|
||||
info.slot = start;
|
||||
info.id = id;
|
||||
info.mca_dev = NULL;
|
||||
|
||||
for(;;) {
|
||||
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
|
||||
|
||||
if(info.mca_dev == NULL)
|
||||
return MCA_NOTFOUND;
|
||||
|
||||
if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
|
||||
break;
|
||||
|
||||
/* OK, found adapter but it was disabled. Go around
|
||||
* again, excluding the slot we just found */
|
||||
|
||||
info.slot = info.mca_dev->slot + 1;
|
||||
info.mca_dev = NULL;
|
||||
}
|
||||
|
||||
return info.mca_dev->slot;
|
||||
}
|
||||
EXPORT_SYMBOL(mca_find_adapter);
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* mca_find_unused_adapter - scan for unused adapters
|
||||
* @id: MCA identification to search for
|
||||
* @start: starting slot
|
||||
*
|
||||
* Search the MCA configuration for adapters matching the 16bit
|
||||
* ID given. The first time it should be called with start as zero
|
||||
* and then further calls made passing the return value of the
|
||||
* previous call until %MCA_NOTFOUND is returned.
|
||||
*
|
||||
* Adapters that have been claimed by drivers and those that
|
||||
* are disabled are not reported. This function thus allows a driver
|
||||
* to scan for further cards when some may already be driven.
|
||||
*/
|
||||
|
||||
int mca_find_unused_adapter(int id, int start)
|
||||
{
|
||||
struct mca_find_adapter_info info = { 0 };
|
||||
|
||||
if (!MCA_bus || id == 0xffff)
|
||||
return MCA_NOTFOUND;
|
||||
|
||||
info.slot = start;
|
||||
info.id = id;
|
||||
info.mca_dev = NULL;
|
||||
|
||||
for(;;) {
|
||||
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
|
||||
|
||||
if(info.mca_dev == NULL)
|
||||
return MCA_NOTFOUND;
|
||||
|
||||
if(info.mca_dev->status != MCA_ADAPTER_DISABLED
|
||||
&& !info.mca_dev->driver_loaded)
|
||||
break;
|
||||
|
||||
/* OK, found adapter but it was disabled or already in
|
||||
* use. Go around again, excluding the slot we just
|
||||
* found */
|
||||
|
||||
info.slot = info.mca_dev->slot + 1;
|
||||
info.mca_dev = NULL;
|
||||
}
|
||||
|
||||
return info.mca_dev->slot;
|
||||
}
|
||||
EXPORT_SYMBOL(mca_find_unused_adapter);
|
||||
|
||||
/* NOTE: stack allocated structure */
|
||||
struct mca_find_device_by_slot_info {
|
||||
int slot;
|
||||
struct mca_device *mca_dev;
|
||||
};
|
||||
|
||||
static int mca_find_device_by_slot_callback(struct device *dev, void *data)
|
||||
{
|
||||
struct mca_find_device_by_slot_info *info = data;
|
||||
struct mca_device *mca_dev = to_mca_device(dev);
|
||||
|
||||
if(mca_dev->slot == info->slot)
|
||||
info->mca_dev = mca_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mca_device *mca_find_device_by_slot(int slot)
|
||||
{
|
||||
struct mca_find_device_by_slot_info info;
|
||||
|
||||
info.slot = slot;
|
||||
info.mca_dev = NULL;
|
||||
|
||||
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
|
||||
|
||||
return info.mca_dev;
|
||||
}
|
||||
EXPORT_SYMBOL(mca_find_device_by_slot);
|
||||
|
||||
/**
|
||||
* mca_read_stored_pos - read POS register from boot data
|
||||
* @slot: slot number 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_read_stored_pos(int slot, int reg)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
return 0;
|
||||
|
||||
return mca_device_read_stored_pos(mca_dev, reg);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_read_stored_pos);
|
||||
|
||||
|
||||
/**
|
||||
* mca_read_pos - read POS register from card
|
||||
* @slot: slot number 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_read_stored_pos and
|
||||
* may not be invoked from interrupt context. It handles the
|
||||
* deep magic required for onboard devices transparently.
|
||||
*/
|
||||
|
||||
unsigned char mca_read_pos(int slot, int reg)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
return 0;
|
||||
|
||||
return mca_device_read_pos(mca_dev, reg);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_read_pos);
|
||||
|
||||
|
||||
/**
|
||||
* mca_write_pos - read POS register from card
|
||||
* @slot: slot number to read from
|
||||
* @reg: register to read from
|
||||
* @byte: byte to write to the POS registers
|
||||
*
|
||||
* Store a POS value directly from 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.
|
||||
*
|
||||
* Note that this a technically a Bad Thing, as IBM tech stuff says
|
||||
* you should only set POS values through their utilities.
|
||||
* However, some devices such as the 3c523 recommend that you write
|
||||
* back some data to make sure the configuration is consistent.
|
||||
* I'd say that IBM is right, but I like my drivers to work.
|
||||
*
|
||||
* This function can't do checks to see if multiple devices end up
|
||||
* with the same resources, so you might see magic smoke if someone
|
||||
* screws up.
|
||||
*/
|
||||
|
||||
void mca_write_pos(int slot, int reg, unsigned char byte)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
return;
|
||||
|
||||
mca_device_write_pos(mca_dev, reg, byte);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_write_pos);
|
||||
|
||||
/**
|
||||
* mca_set_adapter_name - Set the description of the card
|
||||
* @slot: slot to name
|
||||
* @name: text string for the namen
|
||||
*
|
||||
* This function sets the name reported via /proc for this
|
||||
* adapter slot. This is for user information only. Setting a
|
||||
* name deletes any previous name.
|
||||
*/
|
||||
|
||||
void mca_set_adapter_name(int slot, char* name)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
return;
|
||||
|
||||
mca_device_set_name(mca_dev, name);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_set_adapter_name);
|
||||
|
||||
/**
|
||||
* mca_is_adapter_used - check if claimed by driver
|
||||
* @slot: slot to check
|
||||
*
|
||||
* Returns 1 if the slot has been claimed by a driver
|
||||
*/
|
||||
|
||||
int mca_is_adapter_used(int slot)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
return 0;
|
||||
|
||||
return mca_device_claimed(mca_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_is_adapter_used);
|
||||
|
||||
/**
|
||||
* mca_mark_as_used - claim an MCA device
|
||||
* @slot: slot to claim
|
||||
* FIXME: should we make this threadsafe
|
||||
*
|
||||
* Claim an MCA slot for a device driver. If the
|
||||
* slot is already taken the function returns 1,
|
||||
* if it is not taken it is claimed and 0 is
|
||||
* returned.
|
||||
*/
|
||||
|
||||
int mca_mark_as_used(int slot)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
/* FIXME: this is actually a severe error */
|
||||
return 1;
|
||||
|
||||
if(mca_device_claimed(mca_dev))
|
||||
return 1;
|
||||
|
||||
mca_device_set_claim(mca_dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mca_mark_as_used);
|
||||
|
||||
/**
|
||||
* mca_mark_as_unused - release an MCA device
|
||||
* @slot: slot to claim
|
||||
*
|
||||
* Release the slot for other drives to use.
|
||||
*/
|
||||
|
||||
void mca_mark_as_unused(int slot)
|
||||
{
|
||||
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
|
||||
|
||||
if(!mca_dev)
|
||||
return;
|
||||
|
||||
mca_device_set_claim(mca_dev, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(mca_mark_as_unused);
|
||||
|
249
drivers/mca/mca-proc.c
Normal file
249
drivers/mca/mca-proc.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/* -*- 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->name : "");
|
||||
return len;
|
||||
}
|
||||
|
||||
static 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->name[0]) {
|
||||
|
||||
/* Drivers might register a name without /proc handler... */
|
||||
|
||||
len += sprintf(buf+len, "Adapter Name: %s\n",
|
||||
mca_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_device_status(mca_dev) == MCA_ADAPTER_NORMAL ?
|
||||
"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_device_claimed(mca_dev) ? "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++) {
|
||||
enum MCA_AdapterStatus status;
|
||||
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");
|
||||
|
||||
status = mca_device_status(mca_dev);
|
||||
if (status != MCA_ADAPTER_NORMAL &&
|
||||
status != MCA_ADAPTER_DISABLED)
|
||||
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);
|
Reference in New Issue
Block a user