ide-generic.c 4.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * generic/default IDE host driver
 *
4
 * Copyright (C) 2004, 2008 Bartlomiej Zolnierkiewicz
L
Linus Torvalds 已提交
5 6 7 8 9
 * This code was split off from ide.c.  See it for original copyrights.
 *
 * May be copied or modified under the terms of the GNU General Public License.
 */

10 11 12 13 14 15 16 17
/*
 * For special cases new interfaces may be added using sysfs, i.e.
 *
 *	echo -n "0x168:0x36e:10" > /sys/class/ide_generic/add
 *
 * will add an interface using I/O ports 0x168-0x16f/0x36e and IRQ 10.
 */

L
Linus Torvalds 已提交
18 19 20 21
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ide.h>
22
#include <linux/pci_ids.h>
L
Linus Torvalds 已提交
23

24 25 26 27 28
/* FIXME: convert m32r to use ide_platform host driver */
#ifdef CONFIG_M32R
#include <asm/m32r.h>
#endif

29 30
#define DRV_NAME	"ide_generic"

31
static int probe_mask;
32 33 34
module_param(probe_mask, int, 0);
MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");

35 36 37
static ssize_t store_add(struct class *cls, const char *buf, size_t n)
{
	unsigned int base, ctl;
38
	int irq, rc;
39
	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
40 41 42 43 44 45 46 47 48

	if (sscanf(buf, "%x:%x:%d", &base, &ctl, &irq) != 3)
		return -EINVAL;

	memset(&hw, 0, sizeof(hw));
	ide_std_init_ports(&hw, base, ctl);
	hw.irq = irq;
	hw.chipset = ide_generic;

49 50 51
	rc = ide_host_add(NULL, hws, NULL);
	if (rc)
		return rc;
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

	return n;
};

static struct class_attribute ide_generic_class_attrs[] = {
	__ATTR(add, S_IWUSR, NULL, store_add),
	__ATTR_NULL
};

static void ide_generic_class_release(struct class *cls)
{
	kfree(cls);
}

static int __init ide_generic_sysfs_init(void)
{
	struct class *cls;
	int rc;

	cls = kzalloc(sizeof(*cls), GFP_KERNEL);
	if (!cls)
		return -ENOMEM;

	cls->name = DRV_NAME;
	cls->owner = THIS_MODULE;
	cls->class_release = ide_generic_class_release;
	cls->class_attrs = ide_generic_class_attrs;

	rc = class_register(cls);
	if (rc) {
		kfree(cls);
		return rc;
	}

	return 0;
}

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \
	|| defined(CONFIG_PLAT_OPSPUT)
static const u16 legacy_bases[] = { 0x1f0 };
static const int legacy_irqs[]  = { PLD_IRQ_CFIREQ };
#elif defined(CONFIG_PLAT_MAPPI3)
static const u16 legacy_bases[] = { 0x1f0, 0x170 };
static const int legacy_irqs[]  = { PLD_IRQ_CFIREQ, PLD_IRQ_IDEIREQ };
#elif defined(CONFIG_ALPHA)
static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 };
static const int legacy_irqs[]  = { 14, 15, 11, 10 };
#else
static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
static const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
#endif

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
{
	struct pci_dev *p = NULL;
	u16 val;

	for_each_pci_dev(p) {

		if (pci_resource_start(p, 0) == 0x1f0)
			*primary = 1;
		if (pci_resource_start(p, 2) == 0x170)
			*secondary = 1;

		/* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
		if (p->vendor == PCI_VENDOR_ID_CYRIX &&
		    (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
		     p->device == PCI_DEVICE_ID_CYRIX_5520))
			*primary = *secondary = 1;

		/* Intel MPIIX - PIO ATA on non PCI side of bridge */
		if (p->vendor == PCI_VENDOR_ID_INTEL &&
		    p->device == PCI_DEVICE_ID_INTEL_82371MX) {

			pci_read_config_word(p, 0x6C, &val);
			if (val & 0x8000) {
				/* ATA port enabled */
				if (val & 0x4000)
					*secondary = 1;
				else
					*primary = 1;
			}
		}
	}
}

L
Linus Torvalds 已提交
138 139
static int __init ide_generic_init(void)
{
140
	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
141
	unsigned long io_addr;
142
	int i, rc = 0, primary = 0, secondary = 0;
143

144 145 146 147 148 149 150 151 152 153 154 155 156 157
	ide_generic_check_pci_legacy_iobases(&primary, &secondary);

	if (!probe_mask) {
		printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
		     "module parameter for probing all legacy ISA IDE ports\n");

		if (primary == 0)
			probe_mask |= 0x1;

		if (secondary == 0)
			probe_mask |= 0x2;
	} else
		printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
			"upon user request\n");
158

159 160
	for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
		io_addr = legacy_bases[i];
161

162
		if ((probe_mask & (1 << i)) && io_addr) {
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
			if (!request_region(io_addr, 8, DRV_NAME)) {
				printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
						"not free.\n",
						DRV_NAME, io_addr, io_addr + 7);
				continue;
			}

			if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
				printk(KERN_ERR "%s: I/O resource 0x%lX "
						"not free.\n",
						DRV_NAME, io_addr + 0x206);
				release_region(io_addr, 8);
				continue;
			}

178 179
			memset(&hw, 0, sizeof(hw));
			ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
180
#ifdef CONFIG_IA64
181
			hw.irq = isa_irq_to_vector(legacy_irqs[i]);
182
#else
183
			hw.irq = legacy_irqs[i];
184
#endif
185
			hw.chipset = ide_generic;
186

187 188 189 190 191
			rc = ide_host_add(NULL, hws, NULL);
			if (rc) {
				release_region(io_addr + 0x206, 1);
				release_region(io_addr, 8);
			}
192
		}
193
	}
194

195 196 197 198
	if (ide_generic_sysfs_init())
		printk(KERN_ERR DRV_NAME ": failed to create ide_generic "
					 "class\n");

199
	return rc;
L
Linus Torvalds 已提交
200 201 202 203 204
}

module_init(ide_generic_init);

MODULE_LICENSE("GPL");