aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mca
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/mca
Linux-2.6.12-rc2v2.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/Kconfig14
-rw-r--r--drivers/mca/Makefile7
-rw-r--r--drivers/mca/mca-bus.c149
-rw-r--r--drivers/mca/mca-device.c217
-rw-r--r--drivers/mca/mca-driver.c50
-rw-r--r--drivers/mca/mca-legacy.c348
-rw-r--r--drivers/mca/mca-proc.c249
7 files changed, 1034 insertions, 0 deletions
diff --git a/drivers/mca/Kconfig b/drivers/mca/Kconfig
new file mode 100644
index 000000000000..a7a0220ab4bd
--- /dev/null
+++ b/drivers/mca/Kconfig
@@ -0,0 +1,14 @@
1config MCA_LEGACY
2 bool "Legacy MCA API Support"
3 depends on MCA
4 help
5 This compiles in support for the old slot based MCA API. If you
6 have an unconverted MCA driver, you will need to say Y here. It
7 is safe to say Y anyway.
8
9config MCA_PROC_FS
10 bool "Support for the mca entry in /proc"
11 depends on MCA_LEGACY && PROC_FS
12 help
13 If you want the old style /proc/mca directory in addition to the
14 new style sysfs say Y here.
diff --git a/drivers/mca/Makefile b/drivers/mca/Makefile
new file mode 100644
index 000000000000..0794b122520e
--- /dev/null
+++ b/drivers/mca/Makefile
@@ -0,0 +1,7 @@
1# Makefile for the Linux MCA bus support
2
3obj-y := mca-bus.o mca-device.o mca-driver.o
4
5obj-$(CONFIG_MCA_PROC_FS) += mca-proc.o
6obj-$(CONFIG_MCA_LEGACY) += mca-legacy.o
7
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
new file mode 100644
index 000000000000..ff9be67c2a15
--- /dev/null
+++ b/drivers/mca/mca-bus.c
@@ -0,0 +1,149 @@
1/* -*- mode: c; c-basic-offset: 8 -*- */
2
3/*
4 * MCA bus support functions for sysfs.
5 *
6 * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
7 *
8**-----------------------------------------------------------------------------
9**
10** This program is free software; you can redistribute it and/or modify
11** it under the terms of the GNU General Public License as published by
12** the Free Software Foundation; either version 2 of the License, or
13** (at your option) any later version.
14**
15** This program is distributed in the hope that it will be useful,
16** but WITHOUT ANY WARRANTY; without even the implied warranty of
17** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18** GNU General Public License for more details.
19**
20** You should have received a copy of the GNU General Public License
21** along with this program; if not, write to the Free Software
22** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23**
24**-----------------------------------------------------------------------------
25 */
26
27#include <linux/kernel.h>
28#include <linux/device.h>
29#include <linux/mca.h>
30#include <linux/module.h>
31#include <linux/init.h>
32#include <linux/slab.h>
33
34/* Very few machines have more than one MCA bus. However, there are
35 * those that do (Voyager 35xx/5xxx), so we do it this way for future
36 * expansion. None that I know have more than 2 */
37static struct mca_bus *mca_root_busses[MAX_MCA_BUSSES];
38
39#define MCA_DEVINFO(i,s) { .pos = i, .name = s }
40
41struct mca_device_info {
42 short pos_id; /* the 2 byte pos id for this card */
43 char name[DEVICE_NAME_SIZE];
44};
45
46static int mca_bus_match (struct device *dev, struct device_driver *drv)
47{
48 struct mca_device *mca_dev = to_mca_device (dev);
49 struct mca_driver *mca_drv = to_mca_driver (drv);
50 const short *mca_ids = mca_drv->id_table;
51 int i;
52
53 if (!mca_ids)
54 return 0;
55
56 for(i = 0; mca_ids[i]; i++) {
57 if (mca_ids[i] == mca_dev->pos_id) {
58 mca_dev->index = i;
59 return 1;
60 }
61 }
62
63 return 0;
64}
65
66struct bus_type mca_bus_type = {
67 .name = "MCA",
68 .match = mca_bus_match,
69};
70EXPORT_SYMBOL (mca_bus_type);
71
72static ssize_t mca_show_pos_id(struct device *dev, char *buf)
73{
74 /* four digits, \n and trailing \0 */
75 struct mca_device *mca_dev = to_mca_device(dev);
76 int len;
77
78 if(mca_dev->pos_id < MCA_DUMMY_POS_START)
79 len = sprintf(buf, "%04x\n", mca_dev->pos_id);
80 else
81 len = sprintf(buf, "none\n");
82 return len;
83}
84static ssize_t mca_show_pos(struct device *dev, char *buf)
85{
86 /* enough for 8 two byte hex chars plus space and new line */
87 int j, len=0;
88 struct mca_device *mca_dev = to_mca_device(dev);
89
90 for(j=0; j<8; j++)
91 len += sprintf(buf+len, "%02x ", mca_dev->pos[j]);
92 /* change last trailing space to new line */
93 buf[len-1] = '\n';
94 return len;
95}
96
97static DEVICE_ATTR(id, S_IRUGO, mca_show_pos_id, NULL);
98static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL);
99
100int __init mca_register_device(int bus, struct mca_device *mca_dev)
101{
102 struct mca_bus *mca_bus = mca_root_busses[bus];
103
104 mca_dev->dev.parent = &mca_bus->dev;
105 mca_dev->dev.bus = &mca_bus_type;
106 sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot);
107 mca_dev->dma_mask = mca_bus->default_dma_mask;
108 mca_dev->dev.dma_mask = &mca_dev->dma_mask;
109 mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
110
111 if (device_register(&mca_dev->dev))
112 return 0;
113
114 device_create_file(&mca_dev->dev, &dev_attr_id);
115 device_create_file(&mca_dev->dev, &dev_attr_pos);
116
117 return 1;
118}
119
120/* */
121struct mca_bus * __devinit mca_attach_bus(int bus)
122{
123 struct mca_bus *mca_bus;
124
125 if (unlikely(mca_root_busses[bus] != NULL)) {
126 /* This should never happen, but just in case */
127 printk(KERN_EMERG "MCA tried to add already existing bus %d\n",
128 bus);
129 dump_stack();
130 return NULL;
131 }
132
133 mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL);
134 if (!mca_bus)
135 return NULL;
136 memset(mca_bus, 0, sizeof(struct mca_bus));
137 sprintf(mca_bus->dev.bus_id,"mca%d",bus);
138 sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
139 device_register(&mca_bus->dev);
140
141 mca_root_busses[bus] = mca_bus;
142
143 return mca_bus;
144}
145
146int __init mca_system_init (void)
147{
148 return bus_register(&mca_bus_type);
149}
diff --git a/drivers/mca/mca-device.c b/drivers/mca/mca-device.c
new file mode 100644
index 000000000000..76d430aa243f
--- /dev/null
+++ b/drivers/mca/mca-device.c
@@ -0,0 +1,217 @@
1/* -*- mode: c; c-basic-offset: 8 -*- */
2
3/*
4 * MCA device support functions
5 *
6 * These functions support the ongoing device access API.
7 *
8 * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
9 *
10**-----------------------------------------------------------------------------
11**
12** This program is free software; you can redistribute it and/or modify
13** it under the terms of the GNU General Public License as published by
14** the Free Software Foundation; either version 2 of the License, or
15** (at your option) any later version.
16**
17** This program is distributed in the hope that it will be useful,
18** but WITHOUT ANY WARRANTY; without even the implied warranty of
19** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20** GNU General Public License for more details.
21**
22** You should have received a copy of the GNU General Public License
23** along with this program; if not, write to the Free Software
24** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25**
26**-----------------------------------------------------------------------------
27 */
28
29#include <linux/module.h>
30#include <linux/device.h>
31#include <linux/mca.h>
32
33/**
34 * mca_device_read_stored_pos - read POS register from stored data
35 * @mca_dev: device to read from
36 * @reg: register to read from
37 *
38 * Fetch a POS value that was stored at boot time by the kernel
39 * when it scanned the MCA space. The register value is returned.
40 * Missing or invalid registers report 0.
41 */
42unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev, int reg)
43{
44 if(reg < 0 || reg >= 8)
45 return 0;
46
47 return mca_dev->pos[reg];
48}
49EXPORT_SYMBOL(mca_device_read_stored_pos);
50
51/**
52 * mca_device_read_pos - read POS register from card
53 * @mca_dev: device to read from
54 * @reg: register to read from
55 *
56 * Fetch a POS value directly from the hardware to obtain the
57 * current value. This is much slower than
58 * mca_device_read_stored_pos and may not be invoked from
59 * interrupt context. It handles the deep magic required for
60 * onboard devices transparently.
61 */
62unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg)
63{
64 struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
65
66 return mca_bus->f.mca_read_pos(mca_dev, reg);
67
68 return mca_dev->pos[reg];
69}
70EXPORT_SYMBOL(mca_device_read_pos);
71
72
73/**
74 * mca_device_write_pos - read POS register from card
75 * @mca_dev: device to write pos register to
76 * @reg: register to write to
77 * @byte: byte to write to the POS registers
78 *
79 * Store a POS value directly to the hardware. You should not
80 * normally need to use this function and should have a very good
81 * knowledge of MCA bus before you do so. Doing this wrongly can
82 * damage the hardware.
83 *
84 * This function may not be used from interrupt context.
85 *
86 */
87void mca_device_write_pos(struct mca_device *mca_dev, int reg,
88 unsigned char byte)
89{
90 struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
91
92 mca_bus->f.mca_write_pos(mca_dev, reg, byte);
93}
94EXPORT_SYMBOL(mca_device_write_pos);
95
96/**
97 * mca_device_transform_irq - transform the ADF obtained IRQ
98 * @mca_device: device whose irq needs transforming
99 * @irq: input irq from ADF
100 *
101 * MCA Adapter Definition Files (ADF) contain irq, ioport, memory
102 * etc. definitions. In systems with more than one bus, these need
103 * to be transformed through bus mapping functions to get the real
104 * system global quantities.
105 *
106 * This function transforms the interrupt number and returns the
107 * transformed system global interrupt
108 */
109int mca_device_transform_irq(struct mca_device *mca_dev, int irq)
110{
111 struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
112
113 return mca_bus->f.mca_transform_irq(mca_dev, irq);
114}
115EXPORT_SYMBOL(mca_device_transform_irq);
116
117/**
118 * mca_device_transform_ioport - transform the ADF obtained I/O port
119 * @mca_device: device whose port needs transforming
120 * @ioport: input I/O port from ADF
121 *
122 * MCA Adapter Definition Files (ADF) contain irq, ioport, memory
123 * etc. definitions. In systems with more than one bus, these need
124 * to be transformed through bus mapping functions to get the real
125 * system global quantities.
126 *
127 * This function transforms the I/O port number and returns the
128 * transformed system global port number.
129 *
130 * This transformation can be assumed to be linear for port ranges.
131 */
132int mca_device_transform_ioport(struct mca_device *mca_dev, int port)
133{
134 struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
135
136 return mca_bus->f.mca_transform_ioport(mca_dev, port);
137}
138EXPORT_SYMBOL(mca_device_transform_ioport);
139
140/**
141 * mca_device_transform_memory - transform the ADF obtained memory
142 * @mca_device: device whose memory region needs transforming
143 * @mem: memory region start from ADF
144 *
145 * MCA Adapter Definition Files (ADF) contain irq, ioport, memory
146 * etc. definitions. In systems with more than one bus, these need
147 * to be transformed through bus mapping functions to get the real
148 * system global quantities.
149 *
150 * This function transforms the memory region start and returns the
151 * transformed system global memory region (physical).
152 *
153 * This transformation can be assumed to be linear for region ranges.
154 */
155void *mca_device_transform_memory(struct mca_device *mca_dev, void *mem)
156{
157 struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
158
159 return mca_bus->f.mca_transform_memory(mca_dev, mem);
160}
161EXPORT_SYMBOL(mca_device_transform_memory);
162
163
164/**
165 * mca_device_claimed - check if claimed by driver
166 * @mca_dev: device to check
167 *
168 * Returns 1 if the slot has been claimed by a driver
169 */
170
171int mca_device_claimed(struct mca_device *mca_dev)
172{
173 return mca_dev->driver_loaded;
174}
175EXPORT_SYMBOL(mca_device_claimed);
176
177/**
178 * mca_device_set_claim - set the claim value of the driver
179 * @mca_dev: device to set value for
180 * @val: claim value to set (1 claimed, 0 unclaimed)
181 */
182void mca_device_set_claim(struct mca_device *mca_dev, int val)
183{
184 mca_dev->driver_loaded = val;
185}
186EXPORT_SYMBOL(mca_device_set_claim);
187
188/**
189 * mca_device_status - get the status of the device
190 * @mca_device: device to get
191 *
192 * returns an enumeration of the device status:
193 *
194 * MCA_ADAPTER_NORMAL adapter is OK.
195 * MCA_ADAPTER_NONE no adapter at device (should never happen).
196 * MCA_ADAPTER_DISABLED adapter is disabled.
197 * MCA_ADAPTER_ERROR adapter cannot be initialised.
198 */
199enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev)
200{
201 return mca_dev->status;
202}
203EXPORT_SYMBOL(mca_device_status);
204
205/**
206 * mca_device_set_name - set the name of the device
207 * @mca_device: device to set the name of
208 * @name: name to set
209 */
210void mca_device_set_name(struct mca_device *mca_dev, const char *name)
211{
212 if(!mca_dev)
213 return;
214
215 strlcpy(mca_dev->name, name, sizeof(mca_dev->name));
216}
217EXPORT_SYMBOL(mca_device_set_name);
diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c
new file mode 100644
index 000000000000..2223466b3d8a
--- /dev/null
+++ b/drivers/mca/mca-driver.c
@@ -0,0 +1,50 @@
1/* -*- mode: c; c-basic-offset: 8 -*- */
2
3/*
4 * MCA driver support functions for sysfs.
5 *
6 * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
7 *
8**-----------------------------------------------------------------------------
9**
10** This program is free software; you can redistribute it and/or modify
11** it under the terms of the GNU General Public License as published by
12** the Free Software Foundation; either version 2 of the License, or
13** (at your option) any later version.
14**
15** This program is distributed in the hope that it will be useful,
16** but WITHOUT ANY WARRANTY; without even the implied warranty of
17** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18** GNU General Public License for more details.
19**
20** You should have received a copy of the GNU General Public License
21** along with this program; if not, write to the Free Software
22** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23**
24**-----------------------------------------------------------------------------
25 */
26
27#include <linux/device.h>
28#include <linux/mca.h>
29#include <linux/module.h>
30
31int mca_register_driver(struct mca_driver *mca_drv)
32{
33 int r;
34
35 if (MCA_bus) {
36 mca_drv->driver.bus = &mca_bus_type;
37 if ((r = driver_register(&mca_drv->driver)) < 0)
38 return r;
39 }
40
41 return 0;
42}
43EXPORT_SYMBOL(mca_register_driver);
44
45void mca_unregister_driver(struct mca_driver *mca_drv)
46{
47 if (MCA_bus)
48 driver_unregister(&mca_drv->driver);
49}
50EXPORT_SYMBOL(mca_unregister_driver);
diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c
new file mode 100644
index 000000000000..af56313ba0af
--- /dev/null
+++ b/drivers/mca/mca-legacy.c
@@ -0,0 +1,348 @@
1/* -*- mode: c; c-basic-offset: 8 -*- */
2
3/*
4 * MCA bus support functions for legacy (2.4) API.
5 *
6 * Legacy API means the API that operates in terms of MCA slot number
7 *
8 * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
9 *
10**-----------------------------------------------------------------------------
11**
12** This program is free software; you can redistribute it and/or modify
13** it under the terms of the GNU General Public License as published by
14** the Free Software Foundation; either version 2 of the License, or
15** (at your option) any later version.
16**
17** This program is distributed in the hope that it will be useful,
18** but WITHOUT ANY WARRANTY; without even the implied warranty of
19** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20** GNU General Public License for more details.
21**
22** You should have received a copy of the GNU General Public License
23** along with this program; if not, write to the Free Software
24** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25**
26**-----------------------------------------------------------------------------
27 */
28
29#include <linux/module.h>
30#include <linux/device.h>
31#include <linux/mca-legacy.h>
32#include <asm/io.h>
33
34/* NOTE: This structure is stack allocated */
35struct mca_find_adapter_info {
36 int id;
37 int slot;
38 struct mca_device *mca_dev;
39};
40
41/* The purpose of this iterator is to loop over all the devices and
42 * find the one with the smallest slot number that's just greater than
43 * or equal to the required slot with a matching id */
44static int mca_find_adapter_callback(struct device *dev, void *data)
45{
46 struct mca_find_adapter_info *info = data;
47 struct mca_device *mca_dev = to_mca_device(dev);
48
49 if(mca_dev->pos_id != info->id)
50 return 0;
51
52 if(mca_dev->slot < info->slot)
53 return 0;
54
55 if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
56 info->mca_dev = mca_dev;
57
58 return 0;
59}
60
61/**
62 * mca_find_adapter - scan for adapters
63 * @id: MCA identification to search for
64 * @start: starting slot
65 *
66 * Search the MCA configuration for adapters matching the 16bit
67 * ID given. The first time it should be called with start as zero
68 * and then further calls made passing the return value of the
69 * previous call until %MCA_NOTFOUND is returned.
70 *
71 * Disabled adapters are not reported.
72 */
73
74int mca_find_adapter(int id, int start)
75{
76 struct mca_find_adapter_info info;
77
78 if(id == 0xffff)
79 return MCA_NOTFOUND;
80
81 info.slot = start;
82 info.id = id;
83 info.mca_dev = NULL;
84
85 for(;;) {
86 bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
87
88 if(info.mca_dev == NULL)
89 return MCA_NOTFOUND;
90
91 if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
92 break;
93
94 /* OK, found adapter but it was disabled. Go around
95 * again, excluding the slot we just found */
96
97 info.slot = info.mca_dev->slot + 1;
98 info.mca_dev = NULL;
99 }
100
101 return info.mca_dev->slot;
102}
103EXPORT_SYMBOL(mca_find_adapter);
104
105/*--------------------------------------------------------------------*/
106
107/**
108 * mca_find_unused_adapter - scan for unused adapters
109 * @id: MCA identification to search for
110 * @start: starting slot
111 *
112 * Search the MCA configuration for adapters matching the 16bit
113 * ID given. The first time it should be called with start as zero
114 * and then further calls made passing the return value of the
115 * previous call until %MCA_NOTFOUND is returned.
116 *
117 * Adapters that have been claimed by drivers and those that
118 * are disabled are not reported. This function thus allows a driver
119 * to scan for further cards when some may already be driven.
120 */
121
122int mca_find_unused_adapter(int id, int start)
123{
124 struct mca_find_adapter_info info = { 0 };
125
126 if (!MCA_bus || id == 0xffff)
127 return MCA_NOTFOUND;
128
129 info.slot = start;
130 info.id = id;
131 info.mca_dev = NULL;
132
133 for(;;) {
134 bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
135
136 if(info.mca_dev == NULL)
137 return MCA_NOTFOUND;
138
139 if(info.mca_dev->status != MCA_ADAPTER_DISABLED
140 && !info.mca_dev->driver_loaded)
141 break;
142
143 /* OK, found adapter but it was disabled or already in
144 * use. Go around again, excluding the slot we just
145 * found */
146
147 info.slot = info.mca_dev->slot + 1;
148 info.mca_dev = NULL;
149 }
150
151 return info.mca_dev->slot;
152}
153EXPORT_SYMBOL(mca_find_unused_adapter);
154
155/* NOTE: stack allocated structure */
156struct mca_find_device_by_slot_info {
157 int slot;
158 struct mca_device *mca_dev;
159};
160
161static int mca_find_device_by_slot_callback(struct device *dev, void *data)
162{
163 struct mca_find_device_by_slot_info *info = data;
164 struct mca_device *mca_dev = to_mca_device(dev);
165
166 if(mca_dev->slot == info->slot)
167 info->mca_dev = mca_dev;
168
169 return 0;
170}
171
172struct mca_device *mca_find_device_by_slot(int slot)
173{
174 struct mca_find_device_by_slot_info info;
175
176 info.slot = slot;
177 info.mca_dev = NULL;
178
179 bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
180
181 return info.mca_dev;
182}
183EXPORT_SYMBOL(mca_find_device_by_slot);
184
185/**
186 * mca_read_stored_pos - read POS register from boot data
187 * @slot: slot number to read from
188 * @reg: register to read from
189 *
190 * Fetch a POS value that was stored at boot time by the kernel
191 * when it scanned the MCA space. The register value is returned.
192 * Missing or invalid registers report 0.
193 */
194unsigned char mca_read_stored_pos(int slot, int reg)
195{
196 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
197
198 if(!mca_dev)
199 return 0;
200
201 return mca_device_read_stored_pos(mca_dev, reg);
202}
203EXPORT_SYMBOL(mca_read_stored_pos);
204
205
206/**
207 * mca_read_pos - read POS register from card
208 * @slot: slot number to read from
209 * @reg: register to read from
210 *
211 * Fetch a POS value directly from the hardware to obtain the
212 * current value. This is much slower than mca_read_stored_pos and
213 * may not be invoked from interrupt context. It handles the
214 * deep magic required for onboard devices transparently.
215 */
216
217unsigned char mca_read_pos(int slot, int reg)
218{
219 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
220
221 if(!mca_dev)
222 return 0;
223
224 return mca_device_read_pos(mca_dev, reg);
225}
226EXPORT_SYMBOL(mca_read_pos);
227
228
229/**
230 * mca_write_pos - read POS register from card
231 * @slot: slot number to read from
232 * @reg: register to read from
233 * @byte: byte to write to the POS registers
234 *
235 * Store a POS value directly from the hardware. You should not
236 * normally need to use this function and should have a very good
237 * knowledge of MCA bus before you do so. Doing this wrongly can
238 * damage the hardware.
239 *
240 * This function may not be used from interrupt context.
241 *
242 * Note that this a technically a Bad Thing, as IBM tech stuff says
243 * you should only set POS values through their utilities.
244 * However, some devices such as the 3c523 recommend that you write
245 * back some data to make sure the configuration is consistent.
246 * I'd say that IBM is right, but I like my drivers to work.
247 *
248 * This function can't do checks to see if multiple devices end up
249 * with the same resources, so you might see magic smoke if someone
250 * screws up.
251 */
252
253void mca_write_pos(int slot, int reg, unsigned char byte)
254{
255 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
256
257 if(!mca_dev)
258 return;
259
260 mca_device_write_pos(mca_dev, reg, byte);
261}
262EXPORT_SYMBOL(mca_write_pos);
263
264/**
265 * mca_set_adapter_name - Set the description of the card
266 * @slot: slot to name
267 * @name: text string for the namen
268 *
269 * This function sets the name reported via /proc for this
270 * adapter slot. This is for user information only. Setting a
271 * name deletes any previous name.
272 */
273
274void mca_set_adapter_name(int slot, char* name)
275{
276 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
277
278 if(!mca_dev)
279 return;
280
281 mca_device_set_name(mca_dev, name);
282}
283EXPORT_SYMBOL(mca_set_adapter_name);
284
285/**
286 * mca_is_adapter_used - check if claimed by driver
287 * @slot: slot to check
288 *
289 * Returns 1 if the slot has been claimed by a driver
290 */
291
292int mca_is_adapter_used(int slot)
293{
294 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
295
296 if(!mca_dev)
297 return 0;
298
299 return mca_device_claimed(mca_dev);
300}
301EXPORT_SYMBOL(mca_is_adapter_used);
302
303/**
304 * mca_mark_as_used - claim an MCA device
305 * @slot: slot to claim
306 * FIXME: should we make this threadsafe
307 *
308 * Claim an MCA slot for a device driver. If the
309 * slot is already taken the function returns 1,
310 * if it is not taken it is claimed and 0 is
311 * returned.
312 */
313
314int mca_mark_as_used(int slot)
315{
316 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
317
318 if(!mca_dev)
319 /* FIXME: this is actually a severe error */
320 return 1;
321
322 if(mca_device_claimed(mca_dev))
323 return 1;
324
325 mca_device_set_claim(mca_dev, 1);
326
327 return 0;
328}
329EXPORT_SYMBOL(mca_mark_as_used);
330
331/**
332 * mca_mark_as_unused - release an MCA device
333 * @slot: slot to claim
334 *
335 * Release the slot for other drives to use.
336 */
337
338void mca_mark_as_unused(int slot)
339{
340 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
341
342 if(!mca_dev)
343 return;
344
345 mca_device_set_claim(mca_dev, 0);
346}
347EXPORT_SYMBOL(mca_mark_as_unused);
348
diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c
new file mode 100644
index 000000000000..33d5e0820cc5
--- /dev/null
+++ b/drivers/mca/mca-proc.c
@@ -0,0 +1,249 @@
1/* -*- mode: c; c-basic-offset: 8 -*- */
2
3/*
4 * MCA bus support functions for the proc fs.
5 *
6 * NOTE: this code *requires* the legacy MCA api.
7 *
8 * Legacy API means the API that operates in terms of MCA slot number
9 *
10 * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
11 *
12**-----------------------------------------------------------------------------
13**
14** This program is free software; you can redistribute it and/or modify
15** it under the terms of the GNU General Public License as published by
16** the Free Software Foundation; either version 2 of the License, or
17** (at your option) any later version.
18**
19** This program is distributed in the hope that it will be useful,
20** but WITHOUT ANY WARRANTY; without even the implied warranty of
21** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22** GNU General Public License for more details.
23**
24** You should have received a copy of the GNU General Public License
25** along with this program; if not, write to the Free Software
26** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27**
28**-----------------------------------------------------------------------------
29 */
30#include <linux/module.h>
31#include <linux/init.h>
32#include <linux/proc_fs.h>
33#include <linux/mca.h>
34
35static int get_mca_info_helper(struct mca_device *mca_dev, char *page, int len)
36{
37 int j;
38
39 for(j=0; j<8; j++)
40 len += sprintf(page+len, "%02x ",
41 mca_dev ? mca_dev->pos[j] : 0xff);
42 len += sprintf(page+len, " %s\n", mca_dev ? mca_dev->name : "");
43 return len;
44}
45
46static int get_mca_info(char *page, char **start, off_t off,
47 int count, int *eof, void *data)
48{
49 int i, len = 0;
50
51 if(MCA_bus) {
52 struct mca_device *mca_dev;
53 /* Format POS registers of eight MCA slots */
54
55 for(i=0; i<MCA_MAX_SLOT_NR; i++) {
56 mca_dev = mca_find_device_by_slot(i);
57
58 len += sprintf(page+len, "Slot %d: ", i+1);
59 len = get_mca_info_helper(mca_dev, page, len);
60 }
61
62 /* Format POS registers of integrated video subsystem */
63
64 mca_dev = mca_find_device_by_slot(MCA_INTEGVIDEO);
65 len += sprintf(page+len, "Video : ");
66 len = get_mca_info_helper(mca_dev, page, len);
67
68 /* Format POS registers of integrated SCSI subsystem */
69
70 mca_dev = mca_find_device_by_slot(MCA_INTEGSCSI);
71 len += sprintf(page+len, "SCSI : ");
72 len = get_mca_info_helper(mca_dev, page, len);
73
74 /* Format POS registers of motherboard */
75
76 mca_dev = mca_find_device_by_slot(MCA_MOTHERBOARD);
77 len += sprintf(page+len, "Planar: ");
78 len = get_mca_info_helper(mca_dev, page, len);
79 } else {
80 /* Leave it empty if MCA not detected - this should *never*
81 * happen!
82 */
83 }
84
85 if (len <= off+count) *eof = 1;
86 *start = page + off;
87 len -= off;
88 if (len>count) len = count;
89 if (len<0) len = 0;
90 return len;
91}
92
93/*--------------------------------------------------------------------*/
94
95static int mca_default_procfn(char* buf, struct mca_device *mca_dev)
96{
97 int len = 0, i;
98 int slot = mca_dev->slot;
99
100 /* Print out the basic information */
101
102 if(slot < MCA_MAX_SLOT_NR) {
103 len += sprintf(buf+len, "Slot: %d\n", slot+1);
104 } else if(slot == MCA_INTEGSCSI) {
105 len += sprintf(buf+len, "Integrated SCSI Adapter\n");
106 } else if(slot == MCA_INTEGVIDEO) {
107 len += sprintf(buf+len, "Integrated Video Adapter\n");
108 } else if(slot == MCA_MOTHERBOARD) {
109 len += sprintf(buf+len, "Motherboard\n");
110 }
111 if (mca_dev->name[0]) {
112
113 /* Drivers might register a name without /proc handler... */
114
115 len += sprintf(buf+len, "Adapter Name: %s\n",
116 mca_dev->name);
117 } else {
118 len += sprintf(buf+len, "Adapter Name: Unknown\n");
119 }
120 len += sprintf(buf+len, "Id: %02x%02x\n",
121 mca_dev->pos[1], mca_dev->pos[0]);
122 len += sprintf(buf+len, "Enabled: %s\nPOS: ",
123 mca_device_status(mca_dev) == MCA_ADAPTER_NORMAL ?
124 "Yes" : "No");
125 for(i=0; i<8; i++) {
126 len += sprintf(buf+len, "%02x ", mca_dev->pos[i]);
127 }
128 len += sprintf(buf+len, "\nDriver Installed: %s",
129 mca_device_claimed(mca_dev) ? "Yes" : "No");
130 buf[len++] = '\n';
131 buf[len] = 0;
132
133 return len;
134} /* mca_default_procfn() */
135
136static int get_mca_machine_info(char* page, char **start, off_t off,
137 int count, int *eof, void *data)
138{
139 int len = 0;
140
141 len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
142 len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
143 len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
144
145 if (len <= off+count) *eof = 1;
146 *start = page + off;
147 len -= off;
148 if (len>count) len = count;
149 if (len<0) len = 0;
150 return len;
151}
152
153static int mca_read_proc(char *page, char **start, off_t off,
154 int count, int *eof, void *data)
155{
156 struct mca_device *mca_dev = (struct mca_device *)data;
157 int len = 0;
158
159 /* Get the standard info */
160
161 len = mca_default_procfn(page, mca_dev);
162
163 /* Do any device-specific processing, if there is any */
164
165 if(mca_dev->procfn) {
166 len += mca_dev->procfn(page+len, mca_dev->slot,
167 mca_dev->proc_dev);
168 }
169 if (len <= off+count) *eof = 1;
170 *start = page + off;
171 len -= off;
172 if (len>count) len = count;
173 if (len<0) len = 0;
174 return len;
175} /* mca_read_proc() */
176
177/*--------------------------------------------------------------------*/
178
179void __init mca_do_proc_init(void)
180{
181 int i;
182 struct proc_dir_entry *proc_mca;
183 struct proc_dir_entry* node = NULL;
184 struct mca_device *mca_dev;
185
186 proc_mca = proc_mkdir("mca", &proc_root);
187 create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
188 create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
189
190 /* Initialize /proc/mca entries for existing adapters */
191
192 for(i = 0; i < MCA_NUMADAPTERS; i++) {
193 enum MCA_AdapterStatus status;
194 mca_dev = mca_find_device_by_slot(i);
195 if(!mca_dev)
196 continue;
197
198 mca_dev->procfn = NULL;
199
200 if(i < MCA_MAX_SLOT_NR) sprintf(mca_dev->procname,"slot%d", i+1);
201 else if(i == MCA_INTEGVIDEO) sprintf(mca_dev->procname,"video");
202 else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi");
203 else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar");
204
205 status = mca_device_status(mca_dev);
206 if (status != MCA_ADAPTER_NORMAL &&
207 status != MCA_ADAPTER_DISABLED)
208 continue;
209
210 node = create_proc_read_entry(mca_dev->procname, 0, proc_mca,
211 mca_read_proc, (void *)mca_dev);
212
213 if(node == NULL) {
214 printk("Failed to allocate memory for MCA proc-entries!");
215 return;
216 }
217 }
218
219} /* mca_do_proc_init() */
220
221/**
222 * mca_set_adapter_procfn - Set the /proc callback
223 * @slot: slot to configure
224 * @procfn: callback function to call for /proc
225 * @dev: device information passed to the callback
226 *
227 * This sets up an information callback for /proc/mca/slot?. The
228 * function is called with the buffer, slot, and device pointer (or
229 * some equally informative context information, or nothing, if you
230 * prefer), and is expected to put useful information into the
231 * buffer. The adapter name, ID, and POS registers get printed
232 * before this is called though, so don't do it again.
233 *
234 * This should be called with a %NULL @procfn when a module
235 * unregisters, thus preventing kernel crashes and other such
236 * nastiness.
237 */
238
239void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* proc_dev)
240{
241 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
242
243 if(!mca_dev)
244 return;
245
246 mca_dev->procfn = procfn;
247 mca_dev->proc_dev = proc_dev;
248}
249EXPORT_SYMBOL(mca_set_adapter_procfn);