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} 183 184/** 185 * mca_read_stored_pos - read POS register from boot data 186 * @slot: slot number to read from 187 * @reg: register to read from 188 * 189 * Fetch a POS value that was stored at boot time by the kernel 190 * when it scanned the MCA space. The register value is returned. 191 * Missing or invalid registers report 0. 192 */ 193unsigned char mca_read_stored_pos(int slot, int reg) 194{ 195 struct mca_device *mca_dev = mca_find_device_by_slot(slot); 196 197 if(!mca_dev) 198 return 0; 199 200 return mca_device_read_stored_pos(mca_dev, reg); 201} 202EXPORT_SYMBOL(mca_read_stored_pos); 203 204 205/** 206 * mca_read_pos - read POS register from card 207 * @slot: slot number to read from 208 * @reg: register to read from 209 * 210 * Fetch a POS value directly from the hardware to obtain the 211 * current value. This is much slower than mca_read_stored_pos and 212 * may not be invoked from interrupt context. It handles the 213 * deep magic required for onboard devices transparently. 214 */ 215 216unsigned char mca_read_pos(int slot, int reg) 217{ 218 struct mca_device *mca_dev = mca_find_device_by_slot(slot); 219 220 if(!mca_dev) 221 return 0; 222 223 return mca_device_read_pos(mca_dev, reg); 224} 225EXPORT_SYMBOL(mca_read_pos); 226 227 228/** 229 * mca_write_pos - read POS register from card 230 * @slot: slot number to read from 231 * @reg: register to read from 232 * @byte: byte to write to the POS registers 233 * 234 * Store a POS value directly from the hardware. You should not 235 * normally need to use this function and should have a very good 236 * knowledge of MCA bus before you do so. Doing this wrongly can 237 * damage the hardware. 238 * 239 * This function may not be used from interrupt context. 240 * 241 * Note that this a technically a Bad Thing, as IBM tech stuff says 242 * you should only set POS values through their utilities. 243 * However, some devices such as the 3c523 recommend that you write 244 * back some data to make sure the configuration is consistent. 245 * I'd say that IBM is right, but I like my drivers to work. 246 * 247 * This function can't do checks to see if multiple devices end up 248 * with the same resources, so you might see magic smoke if someone 249 * screws up. 250 */ 251 252void mca_write_pos(int slot, int reg, unsigned char byte) 253{ 254 struct mca_device *mca_dev = mca_find_device_by_slot(slot); 255 256 if(!mca_dev) 257 return; 258 259 mca_device_write_pos(mca_dev, reg, byte); 260} 261EXPORT_SYMBOL(mca_write_pos); 262 263/** 264 * mca_set_adapter_name - Set the description of the card 265 * @slot: slot to name 266 * @name: text string for the namen 267 * 268 * This function sets the name reported via /proc for this 269 * adapter slot. This is for user information only. Setting a 270 * name deletes any previous name. 271 */ 272 273void mca_set_adapter_name(int slot, char* name) 274{ 275 struct mca_device *mca_dev = mca_find_device_by_slot(slot); 276 277 if(!mca_dev) 278 return; 279 280 mca_device_set_name(mca_dev, name); 281} 282EXPORT_SYMBOL(mca_set_adapter_name); 283 284/** 285 * mca_mark_as_used - claim an MCA device 286 * @slot: slot to claim 287 * FIXME: should we make this threadsafe 288 * 289 * Claim an MCA slot for a device driver. If the 290 * slot is already taken the function returns 1, 291 * if it is not taken it is claimed and 0 is 292 * returned. 293 */ 294 295int mca_mark_as_used(int slot) 296{ 297 struct mca_device *mca_dev = mca_find_device_by_slot(slot); 298 299 if(!mca_dev) 300 /* FIXME: this is actually a severe error */ 301 return 1; 302 303 if(mca_device_claimed(mca_dev)) 304 return 1; 305 306 mca_device_set_claim(mca_dev, 1); 307 308 return 0; 309} 310EXPORT_SYMBOL(mca_mark_as_used); 311 312/** 313 * mca_mark_as_unused - release an MCA device 314 * @slot: slot to claim 315 * 316 * Release the slot for other drives to use. 317 */ 318 319void mca_mark_as_unused(int slot) 320{ 321 struct mca_device *mca_dev = mca_find_device_by_slot(slot); 322 323 if(!mca_dev) 324 return; 325 326 mca_device_set_claim(mca_dev, 0); 327} 328EXPORT_SYMBOL(mca_mark_as_unused); 329 330