summaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-pnp.c
blob: d193135f55719d715db20ca59aa521a06feb6899 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * linux/drivers/ide/ide-pnp.c
 *
 * This file provides autodetection for ISA PnP IDE interfaces.
 * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
 *
 * Copyright (C) 2000 Andrey Panin <pazke@orbita.don.sitek.net>
 *
 * 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, or (at your option)
 * any later version.
 *
 * You should have received a copy of the GNU General Public License
 * (for example /usr/src/linux/COPYING); if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */

#include <linux/ide.h>
#include <linux/init.h>

#include <linux/isapnp.h>

#ifndef PREPARE_FUNC
#define PREPARE_FUNC(dev)  (dev->prepare)
#define ACTIVATE_FUNC(dev)  (dev->activate)
#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
#endif

#define DEV_IO(dev, index) (dev->resource[index].start)
#define DEV_IRQ(dev, index) (dev->irq_resource[index].start)

#define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP")

#define GENERIC_HD_DATA		0
#define GENERIC_HD_ERROR	1
#define GENERIC_HD_NSECTOR	2
#define GENERIC_HD_SECTOR	3
#define GENERIC_HD_LCYL		4
#define GENERIC_HD_HCYL		5
#define GENERIC_HD_SELECT	6
#define GENERIC_HD_STATUS	7

static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
	GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR, 
	GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
	GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
};

/* ISA PnP device table entry */
struct pnp_dev_t {
	unsigned int vendor, device;
	int (*init_fn)(struct pci_dev *dev, int enable);
};

/* Generic initialisation function for ISA PnP IDE interface */
static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
{
	hw_regs_t hw;
	int index;

	if (!enable)
		return 0;

	if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0)))
		return 1;

	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
			0, NULL, DEV_IRQ(dev, 0));

	index = ide_register_hw(&hw, NULL);

	if (index != -1) {
	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
		return 0;
	}

	return 1;
}

/* Add your devices here :)) */
struct pnp_dev_t idepnp_devices[] __initdata = {
	/* Generic ESDI/IDE/ATA compatible hard disk controller
 */
	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
		pnpide_generic_init },
	{	0 }
};

#ifdef MODULE
#define NR_PNP_DEVICES 8
struct pnp_dev_inst {
	struct pci_dev *dev;
	struct pnp_dev_t *dev_type;
};
static struct pnp_dev_inst devices[NR_PNP_DEVICES];
static int pnp_ide_dev_idx = 0;
#endif

/*
 * Probe for ISA PnP IDE interfaces.
 */
void __init pnpide_init(int enable)
{
	struct pci_dev *dev = NULL;
	struct pnp_dev_t *dev_type;

	if (!isapnp_present())
		return;

#ifdef MODULE
	/* Module unload, deactivate all registered devices. */
	if (!enable) {
		int i;
		for (i = 0; i < pnp_ide_dev_idx; i++) {
			devices[i].dev_type->init_fn(dev, 0);

			if (DEACTIVATE_FUNC(devices[i].dev))
				DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
		}
		return;
	}
#endif
	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
			dev_type->device, dev))) {

			if (dev->active)
				continue;

       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
				printk("ide: %s prepare failed\n", DEV_NAME(dev));
				continue;
			}

			if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
				printk("ide: %s activate failed\n", DEV_NAME(dev));
				continue;
			}

			/* Call device initialization function */
			if (dev_type->init_fn(dev, 1)) {
				if (DEACTIVATE_FUNC(dev))
					DEACTIVATE_FUNC(dev)(dev);
			} else {
#ifdef MODULE
				/*
				 * Register device in the array to
				 * deactivate it on a module unload.
				 */
				if (pnp_ide_dev_idx >= NR_PNP_DEVICES)
					return;
				devices[pnp_ide_dev_idx].dev = dev;
				devices[pnp_ide_dev_idx].dev_type = dev_type;
				pnp_ide_dev_idx++;
#endif
			}
		}
	}
}