18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * EISA bus support functions for sysfs.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (C) 2002, 2003 Marc Zyngier <maz@wild-wind.fr.eu.org>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/eisa.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/ioport.h>
168c2ecf20Sopenharmony_ci#include <asm/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define SLOT_ADDRESS(r,n) (r->bus_base_addr + (0x1000 * n))
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define EISA_DEVINFO(i,s) { .id = { .sig = i }, .name = s }
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct eisa_device_info {
238c2ecf20Sopenharmony_ci	struct eisa_device_id id;
248c2ecf20Sopenharmony_ci	char name[50];
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA_NAMES
288c2ecf20Sopenharmony_cistatic struct eisa_device_info __initdata eisa_table[] = {
298c2ecf20Sopenharmony_ci#include "devlist.h"
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci#define EISA_INFOS (sizeof (eisa_table) / (sizeof (struct eisa_device_info)))
328c2ecf20Sopenharmony_ci#endif
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define EISA_MAX_FORCED_DEV 16
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int enable_dev[EISA_MAX_FORCED_DEV];
378c2ecf20Sopenharmony_cistatic unsigned int enable_dev_count;
388c2ecf20Sopenharmony_cistatic int disable_dev[EISA_MAX_FORCED_DEV];
398c2ecf20Sopenharmony_cistatic unsigned int disable_dev_count;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic int is_forced_dev(int *forced_tab,
428c2ecf20Sopenharmony_ci			 int forced_count,
438c2ecf20Sopenharmony_ci			 struct eisa_root_device *root,
448c2ecf20Sopenharmony_ci			 struct eisa_device *edev)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	int i, x;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	for (i = 0; i < forced_count; i++) {
498c2ecf20Sopenharmony_ci		x = (root->bus_nr << 8) | edev->slot;
508c2ecf20Sopenharmony_ci		if (forced_tab[i] == x)
518c2ecf20Sopenharmony_ci			return 1;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return 0;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void __init eisa_name_device(struct eisa_device *edev)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA_NAMES
608c2ecf20Sopenharmony_ci	int i;
618c2ecf20Sopenharmony_ci	for (i = 0; i < EISA_INFOS; i++) {
628c2ecf20Sopenharmony_ci		if (!strcmp(edev->id.sig, eisa_table[i].id.sig)) {
638c2ecf20Sopenharmony_ci			strlcpy(edev->pretty_name,
648c2ecf20Sopenharmony_ci				eisa_table[i].name,
658c2ecf20Sopenharmony_ci				sizeof(edev->pretty_name));
668c2ecf20Sopenharmony_ci			return;
678c2ecf20Sopenharmony_ci		}
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* No name was found */
718c2ecf20Sopenharmony_ci	sprintf(edev->pretty_name, "EISA device %.7s", edev->id.sig);
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic char __init *decode_eisa_sig(unsigned long addr)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	static char sig_str[EISA_SIG_LEN];
788c2ecf20Sopenharmony_ci	u8 sig[4];
798c2ecf20Sopenharmony_ci	u16 rev;
808c2ecf20Sopenharmony_ci	int i;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
838c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA_VLB_PRIMING
848c2ecf20Sopenharmony_ci		/*
858c2ecf20Sopenharmony_ci		 * This ugly stuff is used to wake up VL-bus cards
868c2ecf20Sopenharmony_ci		 * (AHA-284x is the only known example), so we can
878c2ecf20Sopenharmony_ci		 * read the EISA id.
888c2ecf20Sopenharmony_ci		 *
898c2ecf20Sopenharmony_ci		 * Thankfully, this only exists on x86...
908c2ecf20Sopenharmony_ci		 */
918c2ecf20Sopenharmony_ci		outb(0x80 + i, addr);
928c2ecf20Sopenharmony_ci#endif
938c2ecf20Sopenharmony_ci		sig[i] = inb(addr + i);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		if (!i && (sig[0] & 0x80))
968c2ecf20Sopenharmony_ci			return NULL;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1);
1008c2ecf20Sopenharmony_ci	sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1);
1018c2ecf20Sopenharmony_ci	sig_str[2] = (sig[1] & 0x1f) + ('A' - 1);
1028c2ecf20Sopenharmony_ci	rev = (sig[2] << 8) | sig[3];
1038c2ecf20Sopenharmony_ci	sprintf(sig_str + 3, "%04X", rev);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return sig_str;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int eisa_bus_match(struct device *dev, struct device_driver *drv)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct eisa_device *edev = to_eisa_device(dev);
1118c2ecf20Sopenharmony_ci	struct eisa_driver *edrv = to_eisa_driver(drv);
1128c2ecf20Sopenharmony_ci	const struct eisa_device_id *eids = edrv->id_table;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (!eids)
1158c2ecf20Sopenharmony_ci		return 0;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	while (strlen(eids->sig)) {
1188c2ecf20Sopenharmony_ci		if (!strcmp(eids->sig, edev->id.sig) &&
1198c2ecf20Sopenharmony_ci		    edev->state & EISA_CONFIG_ENABLED) {
1208c2ecf20Sopenharmony_ci			edev->id.driver_data = eids->driver_data;
1218c2ecf20Sopenharmony_ci			return 1;
1228c2ecf20Sopenharmony_ci		}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		eids++;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return 0;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct eisa_device *edev = to_eisa_device(dev);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistruct bus_type eisa_bus_type = {
1398c2ecf20Sopenharmony_ci	.name  = "eisa",
1408c2ecf20Sopenharmony_ci	.match = eisa_bus_match,
1418c2ecf20Sopenharmony_ci	.uevent = eisa_bus_uevent,
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_bus_type);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ciint eisa_driver_register(struct eisa_driver *edrv)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	edrv->driver.bus = &eisa_bus_type;
1488c2ecf20Sopenharmony_ci	return driver_register(&edrv->driver);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_driver_register);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_civoid eisa_driver_unregister(struct eisa_driver *edrv)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	driver_unregister(&edrv->driver);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_driver_unregister);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic ssize_t eisa_show_sig(struct device *dev, struct device_attribute *attr,
1598c2ecf20Sopenharmony_ci			     char *buf)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct eisa_device *edev = to_eisa_device(dev);
1628c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", edev->id.sig);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic DEVICE_ATTR(signature, S_IRUGO, eisa_show_sig, NULL);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic ssize_t eisa_show_state(struct device *dev,
1688c2ecf20Sopenharmony_ci			       struct device_attribute *attr,
1698c2ecf20Sopenharmony_ci			       char *buf)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct eisa_device *edev = to_eisa_device(dev);
1728c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", edev->state & EISA_CONFIG_ENABLED);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic ssize_t eisa_show_modalias(struct device *dev,
1788c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
1798c2ecf20Sopenharmony_ci				  char *buf)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct eisa_device *edev = to_eisa_device(dev);
1828c2ecf20Sopenharmony_ci	return sprintf(buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int __init eisa_init_device(struct eisa_root_device *root,
1888c2ecf20Sopenharmony_ci				   struct eisa_device *edev,
1898c2ecf20Sopenharmony_ci				   int slot)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	char *sig;
1928c2ecf20Sopenharmony_ci	unsigned long sig_addr;
1938c2ecf20Sopenharmony_ci	int i;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	sig_addr = SLOT_ADDRESS(root, slot) + EISA_VENDOR_ID_OFFSET;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	sig = decode_eisa_sig(sig_addr);
1988c2ecf20Sopenharmony_ci	if (!sig)
1998c2ecf20Sopenharmony_ci		return -1;	/* No EISA device here */
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	memcpy(edev->id.sig, sig, EISA_SIG_LEN);
2028c2ecf20Sopenharmony_ci	edev->slot = slot;
2038c2ecf20Sopenharmony_ci	edev->state = inb(SLOT_ADDRESS(root, slot) + EISA_CONFIG_OFFSET)
2048c2ecf20Sopenharmony_ci		      & EISA_CONFIG_ENABLED;
2058c2ecf20Sopenharmony_ci	edev->base_addr = SLOT_ADDRESS(root, slot);
2068c2ecf20Sopenharmony_ci	edev->dma_mask = root->dma_mask; /* Default DMA mask */
2078c2ecf20Sopenharmony_ci	eisa_name_device(edev);
2088c2ecf20Sopenharmony_ci	edev->dev.parent = root->dev;
2098c2ecf20Sopenharmony_ci	edev->dev.bus = &eisa_bus_type;
2108c2ecf20Sopenharmony_ci	edev->dev.dma_mask = &edev->dma_mask;
2118c2ecf20Sopenharmony_ci	edev->dev.coherent_dma_mask = edev->dma_mask;
2128c2ecf20Sopenharmony_ci	dev_set_name(&edev->dev, "%02X:%02X", root->bus_nr, slot);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	for (i = 0; i < EISA_MAX_RESOURCES; i++) {
2158c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA_NAMES
2168c2ecf20Sopenharmony_ci		edev->res[i].name = edev->pretty_name;
2178c2ecf20Sopenharmony_ci#else
2188c2ecf20Sopenharmony_ci		edev->res[i].name = edev->id.sig;
2198c2ecf20Sopenharmony_ci#endif
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (is_forced_dev(enable_dev, enable_dev_count, root, edev))
2238c2ecf20Sopenharmony_ci		edev->state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (is_forced_dev(disable_dev, disable_dev_count, root, edev))
2268c2ecf20Sopenharmony_ci		edev->state = EISA_CONFIG_FORCED;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int __init eisa_register_device(struct eisa_device *edev)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	int rc = device_register(&edev->dev);
2348c2ecf20Sopenharmony_ci	if (rc) {
2358c2ecf20Sopenharmony_ci		put_device(&edev->dev);
2368c2ecf20Sopenharmony_ci		return rc;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	rc = device_create_file(&edev->dev, &dev_attr_signature);
2408c2ecf20Sopenharmony_ci	if (rc)
2418c2ecf20Sopenharmony_ci		goto err_devreg;
2428c2ecf20Sopenharmony_ci	rc = device_create_file(&edev->dev, &dev_attr_enabled);
2438c2ecf20Sopenharmony_ci	if (rc)
2448c2ecf20Sopenharmony_ci		goto err_sig;
2458c2ecf20Sopenharmony_ci	rc = device_create_file(&edev->dev, &dev_attr_modalias);
2468c2ecf20Sopenharmony_ci	if (rc)
2478c2ecf20Sopenharmony_ci		goto err_enab;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cierr_enab:
2528c2ecf20Sopenharmony_ci	device_remove_file(&edev->dev, &dev_attr_enabled);
2538c2ecf20Sopenharmony_cierr_sig:
2548c2ecf20Sopenharmony_ci	device_remove_file(&edev->dev, &dev_attr_signature);
2558c2ecf20Sopenharmony_cierr_devreg:
2568c2ecf20Sopenharmony_ci	device_unregister(&edev->dev);
2578c2ecf20Sopenharmony_ci	return rc;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int __init eisa_request_resources(struct eisa_root_device *root,
2618c2ecf20Sopenharmony_ci					 struct eisa_device *edev,
2628c2ecf20Sopenharmony_ci					 int slot)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	int i;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	for (i = 0; i < EISA_MAX_RESOURCES; i++) {
2678c2ecf20Sopenharmony_ci		/* Don't register resource for slot 0, since this is
2688c2ecf20Sopenharmony_ci		 * very likely to fail... :-( Instead, grab the EISA
2698c2ecf20Sopenharmony_ci		 * id, now we can display something in /proc/ioports.
2708c2ecf20Sopenharmony_ci		 */
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		/* Only one region for mainboard */
2738c2ecf20Sopenharmony_ci		if (!slot && i > 0) {
2748c2ecf20Sopenharmony_ci			edev->res[i].start = edev->res[i].end = 0;
2758c2ecf20Sopenharmony_ci			continue;
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		if (slot) {
2798c2ecf20Sopenharmony_ci			edev->res[i].name  = NULL;
2808c2ecf20Sopenharmony_ci			edev->res[i].start = SLOT_ADDRESS(root, slot)
2818c2ecf20Sopenharmony_ci					     + (i * 0x400);
2828c2ecf20Sopenharmony_ci			edev->res[i].end   = edev->res[i].start + 0xff;
2838c2ecf20Sopenharmony_ci			edev->res[i].flags = IORESOURCE_IO;
2848c2ecf20Sopenharmony_ci		} else {
2858c2ecf20Sopenharmony_ci			edev->res[i].name  = NULL;
2868c2ecf20Sopenharmony_ci			edev->res[i].start = SLOT_ADDRESS(root, slot)
2878c2ecf20Sopenharmony_ci					     + EISA_VENDOR_ID_OFFSET;
2888c2ecf20Sopenharmony_ci			edev->res[i].end   = edev->res[i].start + 3;
2898c2ecf20Sopenharmony_ci			edev->res[i].flags = IORESOURCE_IO | IORESOURCE_BUSY;
2908c2ecf20Sopenharmony_ci		}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		if (request_resource(root->res, &edev->res[i]))
2938c2ecf20Sopenharmony_ci			goto failed;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return 0;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci failed:
2998c2ecf20Sopenharmony_ci	while (--i >= 0)
3008c2ecf20Sopenharmony_ci		release_resource(&edev->res[i]);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return -1;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic void __init eisa_release_resources(struct eisa_device *edev)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int i;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	for (i = 0; i < EISA_MAX_RESOURCES; i++)
3108c2ecf20Sopenharmony_ci		if (edev->res[i].start || edev->res[i].end)
3118c2ecf20Sopenharmony_ci			release_resource(&edev->res[i]);
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int __init eisa_probe(struct eisa_root_device *root)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	int i, c;
3178c2ecf20Sopenharmony_ci	struct eisa_device *edev;
3188c2ecf20Sopenharmony_ci	char *enabled_str;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	dev_info(root->dev, "Probing EISA bus %d\n", root->bus_nr);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* First try to get hold of slot 0. If there is no device
3238c2ecf20Sopenharmony_ci	 * here, simply fail, unless root->force_probe is set. */
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	edev = kzalloc(sizeof(*edev), GFP_KERNEL);
3268c2ecf20Sopenharmony_ci	if (!edev)
3278c2ecf20Sopenharmony_ci		return -ENOMEM;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (eisa_request_resources(root, edev, 0)) {
3308c2ecf20Sopenharmony_ci		dev_warn(root->dev,
3318c2ecf20Sopenharmony_ci			 "EISA: Cannot allocate resource for mainboard\n");
3328c2ecf20Sopenharmony_ci		kfree(edev);
3338c2ecf20Sopenharmony_ci		if (!root->force_probe)
3348c2ecf20Sopenharmony_ci			return -EBUSY;
3358c2ecf20Sopenharmony_ci		goto force_probe;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (eisa_init_device(root, edev, 0)) {
3398c2ecf20Sopenharmony_ci		eisa_release_resources(edev);
3408c2ecf20Sopenharmony_ci		kfree(edev);
3418c2ecf20Sopenharmony_ci		if (!root->force_probe)
3428c2ecf20Sopenharmony_ci			return -ENODEV;
3438c2ecf20Sopenharmony_ci		goto force_probe;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	dev_info(&edev->dev, "EISA: Mainboard %s detected\n", edev->id.sig);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (eisa_register_device(edev)) {
3498c2ecf20Sopenharmony_ci		dev_err(&edev->dev, "EISA: Failed to register %s\n",
3508c2ecf20Sopenharmony_ci			edev->id.sig);
3518c2ecf20Sopenharmony_ci		eisa_release_resources(edev);
3528c2ecf20Sopenharmony_ci		kfree(edev);
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci force_probe:
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	for (c = 0, i = 1; i <= root->slots; i++) {
3588c2ecf20Sopenharmony_ci		edev = kzalloc(sizeof(*edev), GFP_KERNEL);
3598c2ecf20Sopenharmony_ci		if (!edev) {
3608c2ecf20Sopenharmony_ci			dev_err(root->dev, "EISA: Out of memory for slot %d\n",
3618c2ecf20Sopenharmony_ci				i);
3628c2ecf20Sopenharmony_ci			continue;
3638c2ecf20Sopenharmony_ci		}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		if (eisa_request_resources(root, edev, i)) {
3668c2ecf20Sopenharmony_ci			dev_warn(root->dev,
3678c2ecf20Sopenharmony_ci				 "Cannot allocate resource for EISA slot %d\n",
3688c2ecf20Sopenharmony_ci				 i);
3698c2ecf20Sopenharmony_ci			kfree(edev);
3708c2ecf20Sopenharmony_ci			continue;
3718c2ecf20Sopenharmony_ci		}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		if (eisa_init_device(root, edev, i)) {
3748c2ecf20Sopenharmony_ci			eisa_release_resources(edev);
3758c2ecf20Sopenharmony_ci			kfree(edev);
3768c2ecf20Sopenharmony_ci			continue;
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		if (edev->state == (EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED))
3808c2ecf20Sopenharmony_ci			enabled_str = " (forced enabled)";
3818c2ecf20Sopenharmony_ci		else if (edev->state == EISA_CONFIG_FORCED)
3828c2ecf20Sopenharmony_ci			enabled_str = " (forced disabled)";
3838c2ecf20Sopenharmony_ci		else if (edev->state == 0)
3848c2ecf20Sopenharmony_ci			enabled_str = " (disabled)";
3858c2ecf20Sopenharmony_ci		else
3868c2ecf20Sopenharmony_ci			enabled_str = "";
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		dev_info(&edev->dev, "EISA: slot %d: %s detected%s\n", i,
3898c2ecf20Sopenharmony_ci			 edev->id.sig, enabled_str);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		c++;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		if (eisa_register_device(edev)) {
3948c2ecf20Sopenharmony_ci			dev_err(&edev->dev, "EISA: Failed to register %s\n",
3958c2ecf20Sopenharmony_ci				edev->id.sig);
3968c2ecf20Sopenharmony_ci			eisa_release_resources(edev);
3978c2ecf20Sopenharmony_ci			kfree(edev);
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	dev_info(root->dev, "EISA: Detected %d card%s\n", c, c == 1 ? "" : "s");
4028c2ecf20Sopenharmony_ci	return 0;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic struct resource eisa_root_res = {
4068c2ecf20Sopenharmony_ci	.name  = "EISA root resource",
4078c2ecf20Sopenharmony_ci	.start = 0,
4088c2ecf20Sopenharmony_ci	.end   = 0xffffffff,
4098c2ecf20Sopenharmony_ci	.flags = IORESOURCE_IO,
4108c2ecf20Sopenharmony_ci};
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int eisa_bus_count;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ciint __init eisa_root_register(struct eisa_root_device *root)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	int err;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* Use our own resources to check if this bus base address has
4198c2ecf20Sopenharmony_ci	 * been already registered. This prevents the virtual root
4208c2ecf20Sopenharmony_ci	 * device from registering after the real one has, for
4218c2ecf20Sopenharmony_ci	 * example... */
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	root->eisa_root_res.name  = eisa_root_res.name;
4248c2ecf20Sopenharmony_ci	root->eisa_root_res.start = root->res->start;
4258c2ecf20Sopenharmony_ci	root->eisa_root_res.end   = root->res->end;
4268c2ecf20Sopenharmony_ci	root->eisa_root_res.flags = IORESOURCE_BUSY;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	err = request_resource(&eisa_root_res, &root->eisa_root_res);
4298c2ecf20Sopenharmony_ci	if (err)
4308c2ecf20Sopenharmony_ci		return err;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	root->bus_nr = eisa_bus_count++;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	err = eisa_probe(root);
4358c2ecf20Sopenharmony_ci	if (err)
4368c2ecf20Sopenharmony_ci		release_resource(&root->eisa_root_res);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	return err;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int __init eisa_init(void)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	int r;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	r = bus_register(&eisa_bus_type);
4468c2ecf20Sopenharmony_ci	if (r)
4478c2ecf20Sopenharmony_ci		return r;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	printk(KERN_INFO "EISA bus registered\n");
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cimodule_param_array(enable_dev, int, &enable_dev_count, 0444);
4548c2ecf20Sopenharmony_cimodule_param_array(disable_dev, int, &disable_dev_count, 0444);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cipostcore_initcall(eisa_init);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ciint EISA_bus;		/* for legacy drivers */
4598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(EISA_bus);
460