1/* 2 * linux/drivers/ide/ide-pnp.c 3 * 4 * This file provides autodetection for ISA PnP IDE interfaces. 5 * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface. 6 * 7 * Copyright (C) 2000 Andrey Panin <pazke@orbita.don.sitek.net> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2, or (at your option) 12 * any later version. 13 * 14 * You should have received a copy of the GNU General Public License 15 * (for example /usr/src/linux/COPYING); if not, write to the Free 16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19#include <linux/ide.h> 20#include <linux/init.h> 21 22#include <linux/isapnp.h> 23 24#ifndef PREPARE_FUNC 25#define PREPARE_FUNC(dev) (dev->prepare) 26#define ACTIVATE_FUNC(dev) (dev->activate) 27#define DEACTIVATE_FUNC(dev) (dev->deactivate) 28#endif 29 30#define DEV_IO(dev, index) (dev->resource[index].start) 31#define DEV_IRQ(dev, index) (dev->irq_resource[index].start) 32 33#define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP") 34 35#define GENERIC_HD_DATA 0 36#define GENERIC_HD_ERROR 1 37#define GENERIC_HD_NSECTOR 2 38#define GENERIC_HD_SECTOR 3 39#define GENERIC_HD_LCYL 4 40#define GENERIC_HD_HCYL 5 41#define GENERIC_HD_SELECT 6 42#define GENERIC_HD_STATUS 7 43 44static int generic_ide_offsets[IDE_NR_PORTS] __initdata = { 45 GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR, 46 GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL, 47 GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1 48}; 49 50/* ISA PnP device table entry */ 51struct pnp_dev_t { 52 unsigned short card_vendor, card_device, vendor, device; 53 int (*init_fn)(struct pci_dev *dev, int enable); 54}; 55 56/* Generic initialisation function for ISA PnP IDE interface */ 57static int __init pnpide_generic_init(struct pci_dev *dev, int enable) 58{ 59 hw_regs_t hw; 60 int index; 61 62 if (!enable) 63 return 0; 64 65 if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0))) 66 return 1; 67 68 ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0), 69 generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1), 70 0, NULL, DEV_IRQ(dev, 0)); 71 72 index = ide_register_hw(&hw, NULL); 73 74 if (index != -1) { 75 printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev)); 76 return 0; 77 } 78 79 return 1; 80} 81 82/* Add your devices here :)) */ 83struct pnp_dev_t idepnp_devices[] __initdata = { 84 /* Generic ESDI/IDE/ATA compatible hard disk controller */ 85 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, 86 ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), 87 pnpide_generic_init }, 88 { 0 } 89}; 90 91#ifdef MODULE 92#define NR_PNP_DEVICES 8 93struct pnp_dev_inst { 94 struct pci_dev *dev; 95 struct pnp_dev_t *dev_type; 96}; 97static struct pnp_dev_inst devices[NR_PNP_DEVICES]; 98static int pnp_ide_dev_idx = 0; 99#endif 100 101/* 102 * Probe for ISA PnP IDE interfaces. 103 */ 104void __init pnpide_init(int enable) 105{ 106 struct pci_dev *dev = NULL; 107 struct pnp_dev_t *dev_type; 108 109 if (!isapnp_present()) 110 return; 111 112#ifdef MODULE 113 /* Module unload, deactivate all registered devices. */ 114 if (!enable) { 115 int i; 116 for (i = 0; i < pnp_ide_dev_idx; i++) { 117 devices[i].dev_type->init_fn(dev, 0); 118 119 if (DEACTIVATE_FUNC(devices[i].dev)) 120 DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev); 121 } 122 return; 123 } 124#endif 125 for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) { 126 while ((dev = isapnp_find_dev(NULL, dev_type->vendor, 127 dev_type->device, dev))) { 128 129 if (dev->active) 130 continue; 131 132 if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) { 133 printk("ide: %s prepare failed\n", DEV_NAME(dev)); 134 continue; 135 } 136 137 if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) { 138 printk("ide: %s activate failed\n", DEV_NAME(dev)); 139 continue; 140 } 141 142 /* Call device initialization function */ 143 if (dev_type->init_fn(dev, 1)) { 144 if (DEACTIVATE_FUNC(dev)) 145 DEACTIVATE_FUNC(dev)(dev); 146 } else { 147#ifdef MODULE 148 /* 149 * Register device in the array to 150 * deactivate it on a module unload. 151 */ 152 if (pnp_ide_dev_idx >= NR_PNP_DEVICES) 153 return; 154 devices[pnp_ide_dev_idx].dev = dev; 155 devices[pnp_ide_dev_idx].dev_type = dev_type; 156 pnp_ide_dev_idx++; 157#endif 158 } 159 } 160 } 161} 162