diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/mca |
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!
Diffstat (limited to 'drivers/mca')
-rw-r--r-- | drivers/mca/Kconfig | 14 | ||||
-rw-r--r-- | drivers/mca/Makefile | 7 | ||||
-rw-r--r-- | drivers/mca/mca-bus.c | 149 | ||||
-rw-r--r-- | drivers/mca/mca-device.c | 217 | ||||
-rw-r--r-- | drivers/mca/mca-driver.c | 50 | ||||
-rw-r--r-- | drivers/mca/mca-legacy.c | 348 | ||||
-rw-r--r-- | drivers/mca/mca-proc.c | 249 |
7 files changed, 1034 insertions, 0 deletions
diff --git a/drivers/mca/Kconfig b/drivers/mca/Kconfig new file mode 100644 index 00000000000..a7a0220ab4b --- /dev/null +++ b/drivers/mca/Kconfig @@ -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. diff --git a/drivers/mca/Makefile b/drivers/mca/Makefile new file mode 100644 index 00000000000..0794b122520 --- /dev/null +++ b/drivers/mca/Makefile @@ -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 + diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c new file mode 100644 index 00000000000..ff9be67c2a1 --- /dev/null +++ b/drivers/mca/mca-bus.c @@ -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); +} diff --git a/drivers/mca/mca-device.c b/drivers/mca/mca-device.c new file mode 100644 index 00000000000..76d430aa243 --- /dev/null +++ b/drivers/mca/mca-device.c @@ -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); diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c new file mode 100644 index 00000000000..2223466b3d8 --- /dev/null +++ b/drivers/mca/mca-driver.c @@ -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); diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c new file mode 100644 index 00000000000..af56313ba0a --- /dev/null +++ b/drivers/mca/mca-legacy.c @@ -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); + diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c new file mode 100644 index 00000000000..33d5e0820cc --- /dev/null +++ b/drivers/mca/mca-proc.c @@ -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); |