18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * generic/default IDE host driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz 58c2ecf20Sopenharmony_ci * This code was split off from ide.c. See it for original copyrights. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * May be copied or modified under the terms of the GNU General Public License. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/ide.h> 148c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* FIXME: convert arm to use ide_platform host driver */ 178c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM 188c2ecf20Sopenharmony_ci#include <asm/irq.h> 198c2ecf20Sopenharmony_ci#endif 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define DRV_NAME "ide_generic" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int probe_mask; 248c2ecf20Sopenharmony_cimodule_param(probe_mask, int, 0); 258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports"); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const struct ide_port_info ide_generic_port_info = { 288c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_NO_DMA, 298c2ecf20Sopenharmony_ci .chipset = ide_generic, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM 338c2ecf20Sopenharmony_cistatic const u16 legacy_bases[] = { 0x1f0 }; 348c2ecf20Sopenharmony_cistatic const int legacy_irqs[] = { IRQ_HARDDISK }; 358c2ecf20Sopenharmony_ci#elif defined(CONFIG_ALPHA) 368c2ecf20Sopenharmony_cistatic const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 }; 378c2ecf20Sopenharmony_cistatic const int legacy_irqs[] = { 14, 15, 11, 10 }; 388c2ecf20Sopenharmony_ci#else 398c2ecf20Sopenharmony_cistatic const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; 408c2ecf20Sopenharmony_cistatic const int legacy_irqs[] = { 14, 15, 11, 10, 8, 12 }; 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 468c2ecf20Sopenharmony_ci struct pci_dev *p = NULL; 478c2ecf20Sopenharmony_ci u16 val; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci for_each_pci_dev(p) { 508c2ecf20Sopenharmony_ci if (pci_resource_start(p, 0) == 0x1f0) 518c2ecf20Sopenharmony_ci *primary = 1; 528c2ecf20Sopenharmony_ci if (pci_resource_start(p, 2) == 0x170) 538c2ecf20Sopenharmony_ci *secondary = 1; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */ 568c2ecf20Sopenharmony_ci if (p->vendor == PCI_VENDOR_ID_CYRIX && 578c2ecf20Sopenharmony_ci (p->device == PCI_DEVICE_ID_CYRIX_5510 || 588c2ecf20Sopenharmony_ci p->device == PCI_DEVICE_ID_CYRIX_5520)) 598c2ecf20Sopenharmony_ci *primary = *secondary = 1; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Intel MPIIX - PIO ATA on non PCI side of bridge */ 628c2ecf20Sopenharmony_ci if (p->vendor == PCI_VENDOR_ID_INTEL && 638c2ecf20Sopenharmony_ci p->device == PCI_DEVICE_ID_INTEL_82371MX) { 648c2ecf20Sopenharmony_ci pci_read_config_word(p, 0x6C, &val); 658c2ecf20Sopenharmony_ci if (val & 0x8000) { 668c2ecf20Sopenharmony_ci /* ATA port enabled */ 678c2ecf20Sopenharmony_ci if (val & 0x4000) 688c2ecf20Sopenharmony_ci *secondary = 1; 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci *primary = 1; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci#endif 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int __init ide_generic_init(void) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct ide_hw hw, *hws[] = { &hw }; 808c2ecf20Sopenharmony_ci unsigned long io_addr; 818c2ecf20Sopenharmony_ci int i, rc = 0, primary = 0, secondary = 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ide_generic_check_pci_legacy_iobases(&primary, &secondary); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (!probe_mask) { 868c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" " 878c2ecf20Sopenharmony_ci "module parameter for probing all legacy ISA IDE ports\n"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (primary == 0) 908c2ecf20Sopenharmony_ci probe_mask |= 0x1; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (secondary == 0) 938c2ecf20Sopenharmony_ci probe_mask |= 0x2; 948c2ecf20Sopenharmony_ci } else 958c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports " 968c2ecf20Sopenharmony_ci "upon user request\n"); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) { 998c2ecf20Sopenharmony_ci io_addr = legacy_bases[i]; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if ((probe_mask & (1 << i)) && io_addr) { 1028c2ecf20Sopenharmony_ci if (!request_region(io_addr, 8, DRV_NAME)) { 1038c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX " 1048c2ecf20Sopenharmony_ci "not free.\n", 1058c2ecf20Sopenharmony_ci DRV_NAME, io_addr, io_addr + 7); 1068c2ecf20Sopenharmony_ci rc = -EBUSY; 1078c2ecf20Sopenharmony_ci continue; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!request_region(io_addr + 0x206, 1, DRV_NAME)) { 1118c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: I/O resource 0x%lX " 1128c2ecf20Sopenharmony_ci "not free.\n", 1138c2ecf20Sopenharmony_ci DRV_NAME, io_addr + 0x206); 1148c2ecf20Sopenharmony_ci release_region(io_addr, 8); 1158c2ecf20Sopenharmony_ci rc = -EBUSY; 1168c2ecf20Sopenharmony_ci continue; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci memset(&hw, 0, sizeof(hw)); 1208c2ecf20Sopenharmony_ci ide_std_init_ports(&hw, io_addr, io_addr + 0x206); 1218c2ecf20Sopenharmony_ci#ifdef CONFIG_IA64 1228c2ecf20Sopenharmony_ci hw.irq = isa_irq_to_vector(legacy_irqs[i]); 1238c2ecf20Sopenharmony_ci#else 1248c2ecf20Sopenharmony_ci hw.irq = legacy_irqs[i]; 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL); 1278c2ecf20Sopenharmony_ci if (rc) { 1288c2ecf20Sopenharmony_ci release_region(io_addr + 0x206, 1); 1298c2ecf20Sopenharmony_ci release_region(io_addr, 8); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return rc; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cimodule_init(ide_generic_init); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 140