18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
38c2ecf20Sopenharmony_ci *  Portions (C) Copyright 2002  Red Hat Inc
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it
68c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the
78c2ecf20Sopenharmony_ci * Free Software Foundation; either version 2, or (at your option) any
88c2ecf20Sopenharmony_ci * later version.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
118c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
128c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
138c2ecf20Sopenharmony_ci * General Public License for more details.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * For the avoidance of doubt the "preferred form" of this code is one which
168c2ecf20Sopenharmony_ci * is in an open non patent encumbered format. Where cryptographic key signing
178c2ecf20Sopenharmony_ci * forms part of the process of creating an executable the information
188c2ecf20Sopenharmony_ci * including keys needed to generate an equivalently functional executable
198c2ecf20Sopenharmony_ci * are deemed to be part of the source code.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/types.h>
238c2ecf20Sopenharmony_ci#include <linux/module.h>
248c2ecf20Sopenharmony_ci#include <linux/kernel.h>
258c2ecf20Sopenharmony_ci#include <linux/pci.h>
268c2ecf20Sopenharmony_ci#include <linux/ide.h>
278c2ecf20Sopenharmony_ci#include <linux/init.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define DRV_NAME "ide_pci_generic"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic bool ide_generic_all;		/* Set to claim all devices */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cimodule_param_named(all_generic_ide, ide_generic_all, bool, 0444);
348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void netcell_quirkproc(ide_drive_t *drive)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	/* mark words 85-87 as valid */
398c2ecf20Sopenharmony_ci	drive->id[ATA_ID_CSF_DEFAULT] |= 0x4000;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const struct ide_port_ops netcell_port_ops = {
438c2ecf20Sopenharmony_ci	.quirkproc		= netcell_quirkproc,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define DECLARE_GENERIC_PCI_DEV(extra_flags) \
478c2ecf20Sopenharmony_ci	{ \
488c2ecf20Sopenharmony_ci		.name		= DRV_NAME, \
498c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_TRUST_BIOS_FOR_DMA | \
508c2ecf20Sopenharmony_ci				  extra_flags, \
518c2ecf20Sopenharmony_ci		.swdma_mask	= ATA_SWDMA2, \
528c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2, \
538c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA6, \
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic const struct ide_port_info generic_chipsets[] = {
578c2ecf20Sopenharmony_ci	/*  0: Unknown */
588c2ecf20Sopenharmony_ci	DECLARE_GENERIC_PCI_DEV(0),
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	{	/* 1: NS87410 */
618c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
628c2ecf20Sopenharmony_ci		.enablebits	= { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} },
638c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_TRUST_BIOS_FOR_DMA,
648c2ecf20Sopenharmony_ci		.swdma_mask	= ATA_SWDMA2,
658c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
668c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
678c2ecf20Sopenharmony_ci	},
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/*  2: SAMURAI / HT6565 / HINT_IDE */
708c2ecf20Sopenharmony_ci	DECLARE_GENERIC_PCI_DEV(0),
718c2ecf20Sopenharmony_ci	/*  3: UM8673F / UM8886A / UM8886BF */
728c2ecf20Sopenharmony_ci	DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_DMA),
738c2ecf20Sopenharmony_ci	/*  4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */
748c2ecf20Sopenharmony_ci	DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA),
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	{	/* 5: VIA8237SATA */
778c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
788c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_TRUST_BIOS_FOR_DMA |
798c2ecf20Sopenharmony_ci				  IDE_HFLAG_OFF_BOARD,
808c2ecf20Sopenharmony_ci		.swdma_mask	= ATA_SWDMA2,
818c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
828c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
838c2ecf20Sopenharmony_ci	},
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	{	/* 6: Revolution */
868c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
878c2ecf20Sopenharmony_ci		.port_ops	= &netcell_port_ops,
888c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_CLEAR_SIMPLEX |
898c2ecf20Sopenharmony_ci				  IDE_HFLAG_TRUST_BIOS_FOR_DMA |
908c2ecf20Sopenharmony_ci				  IDE_HFLAG_OFF_BOARD,
918c2ecf20Sopenharmony_ci		.swdma_mask	= ATA_SWDMA2,
928c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
938c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci *	generic_init_one	-	called when a PIIX is found
998c2ecf20Sopenharmony_ci *	@dev: the generic device
1008c2ecf20Sopenharmony_ci *	@id: the matching pci id
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci *	Called when the PCI registration layer (or the IDE initialization)
1038c2ecf20Sopenharmony_ci *	finds a device matching our IDE device tables.
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	const struct ide_port_info *d = &generic_chipsets[id->driver_data];
1098c2ecf20Sopenharmony_ci	int ret = -ENODEV;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Don't use the generic entry unless instructed to do so */
1128c2ecf20Sopenharmony_ci	if (id->driver_data == 0 && ide_generic_all == 0)
1138c2ecf20Sopenharmony_ci			goto out;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	switch (dev->vendor) {
1168c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_UMC:
1178c2ecf20Sopenharmony_ci		if (dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
1188c2ecf20Sopenharmony_ci				!(PCI_FUNC(dev->devfn) & 1))
1198c2ecf20Sopenharmony_ci			goto out; /* UM8886A/BF pair */
1208c2ecf20Sopenharmony_ci		break;
1218c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_OPTI:
1228c2ecf20Sopenharmony_ci		if (dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
1238c2ecf20Sopenharmony_ci				!(PCI_FUNC(dev->devfn) & 1))
1248c2ecf20Sopenharmony_ci			goto out;
1258c2ecf20Sopenharmony_ci		break;
1268c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_JMICRON:
1278c2ecf20Sopenharmony_ci		if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 &&
1288c2ecf20Sopenharmony_ci				PCI_FUNC(dev->devfn) != 1)
1298c2ecf20Sopenharmony_ci			goto out;
1308c2ecf20Sopenharmony_ci		break;
1318c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_NS:
1328c2ecf20Sopenharmony_ci		if (dev->device == PCI_DEVICE_ID_NS_87410 &&
1338c2ecf20Sopenharmony_ci				(dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
1348c2ecf20Sopenharmony_ci			goto out;
1358c2ecf20Sopenharmony_ci		break;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (dev->vendor != PCI_VENDOR_ID_JMICRON) {
1398c2ecf20Sopenharmony_ci		u16 command;
1408c2ecf20Sopenharmony_ci		pci_read_config_word(dev, PCI_COMMAND, &command);
1418c2ecf20Sopenharmony_ci		if (!(command & PCI_COMMAND_IO)) {
1428c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s %s: skipping disabled "
1438c2ecf20Sopenharmony_ci				"controller\n", d->name, pci_name(dev));
1448c2ecf20Sopenharmony_ci			goto out;
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	ret = ide_pci_init_one(dev, d, NULL);
1488c2ecf20Sopenharmony_ciout:
1498c2ecf20Sopenharmony_ci	return ret;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic const struct pci_device_id generic_pci_tbl[] = {
1538c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(NS,	PCI_DEVICE_ID_NS_87410),		 1 },
1548c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(PCTECH,	PCI_DEVICE_ID_PCTECH_SAMURAI_IDE),	 2 },
1558c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(HOLTEK,	PCI_DEVICE_ID_HOLTEK_6565),		 2 },
1568c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(UMC,	PCI_DEVICE_ID_UMC_UM8673F),		 3 },
1578c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(UMC,	PCI_DEVICE_ID_UMC_UM8886A),		 3 },
1588c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(UMC,	PCI_DEVICE_ID_UMC_UM8886BF),		 3 },
1598c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(HINT,	PCI_DEVICE_ID_HINT_VXPROII_IDE),	 2 },
1608c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(VIA,	PCI_DEVICE_ID_VIA_82C561),		 4 },
1618c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(OPTI,	PCI_DEVICE_ID_OPTI_82C558),		 4 },
1628c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_IDE_SATA
1638c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(VIA,	PCI_DEVICE_ID_VIA_8237_SATA),		 5 },
1648c2ecf20Sopenharmony_ci#endif
1658c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TOSHIBA,	PCI_DEVICE_ID_TOSHIBA_PICCOLO_1),	 4 },
1668c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TOSHIBA,	PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),	 4 },
1678c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TOSHIBA,	PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),	 4 },
1688c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TOSHIBA,	PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),	 4 },
1698c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(NETCELL,	PCI_DEVICE_ID_REVOLUTION),		 6 },
1708c2ecf20Sopenharmony_ci	/*
1718c2ecf20Sopenharmony_ci	 * Must come last.  If you add entries adjust
1728c2ecf20Sopenharmony_ci	 * this table and generic_chipsets[] appropriately.
1738c2ecf20Sopenharmony_ci	 */
1748c2ecf20Sopenharmony_ci	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 },
1758c2ecf20Sopenharmony_ci	{ 0, },
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, generic_pci_tbl);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic struct pci_driver generic_pci_driver = {
1808c2ecf20Sopenharmony_ci	.name		= "PCI_IDE",
1818c2ecf20Sopenharmony_ci	.id_table	= generic_pci_tbl,
1828c2ecf20Sopenharmony_ci	.probe		= generic_init_one,
1838c2ecf20Sopenharmony_ci	.remove		= ide_pci_remove,
1848c2ecf20Sopenharmony_ci	.suspend	= ide_pci_suspend,
1858c2ecf20Sopenharmony_ci	.resume		= ide_pci_resume,
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int __init generic_ide_init(void)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	return ide_pci_register_driver(&generic_pci_driver);
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic void __exit generic_ide_exit(void)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	pci_unregister_driver(&generic_pci_driver);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cimodule_init(generic_ide_init);
1998c2ecf20Sopenharmony_cimodule_exit(generic_ide_exit);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andre Hedrick");
2028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
2038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
204