⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pata_legacy.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (pair) {		struct ata_timing tp;		ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);		ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);	}	active = FIT(t.active, 2, 17) - 2;	recover = FIT(t.recover, 1, 16) - 1;	setup = FIT(t.setup, 1, 4) - 1;	/* Select the right timing bank for write timing */	rc = ioread8(ap->ioaddr.lbal_addr);	rc &= 0x7F;	rc |= (adev->devno << 7);	iowrite8(rc, ap->ioaddr.lbal_addr);	/* Write the timings */	iowrite8(active << 4 | recover, ap->ioaddr.error_addr);	/* Select the right bank for read timings, also	   load the shared timings for address */	rc = ioread8(ap->ioaddr.device_addr);	rc &= 0xC0;	rc |= adev->devno;	/* Index select */	rc |= (setup << 4) | 0x04;	iowrite8(rc, ap->ioaddr.device_addr);	/* Load the read timings */	iowrite8(active << 4 | recover, ap->ioaddr.data_addr);	/* Ensure the timing register mode is right */	rc = ioread8(ap->ioaddr.lbal_addr);	rc &= 0x73;	rc |= 0x84;	iowrite8(rc, ap->ioaddr.lbal_addr);	/* Exit command mode */	iowrite8(0x83,  ap->ioaddr.nsect_addr);}static struct ata_port_operations opti82c611a_port_ops = {	.set_piomode	= opti82c611a_set_piomode,	.tf_load	= ata_tf_load,	.tf_read	= ata_tf_read,	.check_status 	= ata_check_status,	.exec_command	= ata_exec_command,	.dev_select 	= ata_std_dev_select,	.freeze		= ata_bmdma_freeze,	.thaw		= ata_bmdma_thaw,	.error_handler	= ata_bmdma_error_handler,	.post_internal_cmd = ata_bmdma_post_internal_cmd,	.cable_detect	= ata_cable_40wire,	.qc_prep 	= ata_qc_prep,	.qc_issue	= ata_qc_issue_prot,	.data_xfer	= ata_data_xfer,	.irq_handler	= ata_interrupt,	.irq_clear	= ata_bmdma_irq_clear,	.irq_on		= ata_irq_on,	.port_start	= ata_port_start,};/* *	Opti 82C465MV * *	This controller supports PIO0 to PIO3. Unlike the 611A the MVB *	version is dual channel but doesn't have a lot of unique registers. */static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev){	u8 active, recover, setup;	struct ata_timing t;	struct ata_device *pair = ata_dev_pair(adev);	int clock;	int khz[4] = { 50000, 40000, 33000, 25000 };	u8 rc;	u8 sysclk;	/* Get the clock */	sysclk = opti_syscfg(0xAC) & 0xC0;	/* BIOS set */	/* Enter configuration mode */	ioread16(ap->ioaddr.error_addr);	ioread16(ap->ioaddr.error_addr);	iowrite8(3, ap->ioaddr.nsect_addr);	/* Read VLB clock strapping */	clock = 1000000000 / khz[sysclk];	/* Get the timing data in cycles */	ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);	/* Setup timing is shared */	if (pair) {		struct ata_timing tp;		ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);		ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);	}	active = FIT(t.active, 2, 17) - 2;	recover = FIT(t.recover, 1, 16) - 1;	setup = FIT(t.setup, 1, 4) - 1;	/* Select the right timing bank for write timing */	rc = ioread8(ap->ioaddr.lbal_addr);	rc &= 0x7F;	rc |= (adev->devno << 7);	iowrite8(rc, ap->ioaddr.lbal_addr);	/* Write the timings */	iowrite8(active << 4 | recover, ap->ioaddr.error_addr);	/* Select the right bank for read timings, also	   load the shared timings for address */	rc = ioread8(ap->ioaddr.device_addr);	rc &= 0xC0;	rc |= adev->devno;	/* Index select */	rc |= (setup << 4) | 0x04;	iowrite8(rc, ap->ioaddr.device_addr);	/* Load the read timings */	iowrite8(active << 4 | recover, ap->ioaddr.data_addr);	/* Ensure the timing register mode is right */	rc = ioread8(ap->ioaddr.lbal_addr);	rc &= 0x73;	rc |= 0x84;	iowrite8(rc, ap->ioaddr.lbal_addr);	/* Exit command mode */	iowrite8(0x83,  ap->ioaddr.nsect_addr);	/* We need to know this for quad device on the MVB */	ap->host->private_data = ap;}/** *	opt82c465mv_qc_issue_prot	-	command issue *	@qc: command pending * *	Called when the libata layer is about to issue a command. We wrap *	this interface so that we can load the correct ATA timings. The *	MVB has a single set of timing registers and these are shared *	across channels. As there are two registers we really ought to *	track the last two used values as a sort of register window. For *	now we just reload on a channel switch. On the single channel *	setup this condition never fires so we do nothing extra. * *	FIXME: dual channel needs ->serialize support */static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct ata_device *adev = qc->dev;	/* If timings are set and for the wrong channel (2nd test is	   due to a libata shortcoming and will eventually go I hope) */	if (ap->host->private_data != ap->host	    && ap->host->private_data != NULL)		opti82c46x_set_piomode(ap, adev);	return ata_qc_issue_prot(qc);}static struct ata_port_operations opti82c46x_port_ops = {	.set_piomode	= opti82c46x_set_piomode,	.tf_load	= ata_tf_load,	.tf_read	= ata_tf_read,	.check_status 	= ata_check_status,	.exec_command	= ata_exec_command,	.dev_select 	= ata_std_dev_select,	.freeze		= ata_bmdma_freeze,	.thaw		= ata_bmdma_thaw,	.error_handler	= ata_bmdma_error_handler,	.post_internal_cmd = ata_bmdma_post_internal_cmd,	.cable_detect	= ata_cable_40wire,	.qc_prep 	= ata_qc_prep,	.qc_issue	= opti82c46x_qc_issue_prot,	.data_xfer	= ata_data_xfer,	.irq_handler	= ata_interrupt,	.irq_clear	= ata_bmdma_irq_clear,	.irq_on		= ata_irq_on,	.port_start	= ata_port_start,};/** *	legacy_init_one		-	attach a legacy interface *	@port: port number *	@io: I/O port start *	@ctrl: control port *	@irq: interrupt line * *	Register an ISA bus IDE interface. Such interfaces are PIO and we *	assume do not support IRQ sharing. */static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq){	struct legacy_data *ld = &legacy_data[nr_legacy_host];	struct ata_host *host;	struct ata_port *ap;	struct platform_device *pdev;	struct ata_port_operations *ops = &legacy_port_ops;	void __iomem *io_addr, *ctrl_addr;	int pio_modes = pio_mask;	u32 mask = (1 << port);	u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;	int ret;	pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);	if (IS_ERR(pdev))		return PTR_ERR(pdev);	ret = -EBUSY;	if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||	    devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL)		goto fail;	ret = -ENOMEM;	io_addr = devm_ioport_map(&pdev->dev, io, 8);	ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1);	if (!io_addr || !ctrl_addr)		goto fail;	if (ht6560a & mask) {		ops = &ht6560a_port_ops;		pio_modes = 0x07;		iordy = ATA_FLAG_NO_IORDY;	}	if (ht6560b & mask) {		ops = &ht6560b_port_ops;		pio_modes = 0x1F;	}	if (opti82c611a & mask) {		ops = &opti82c611a_port_ops;		pio_modes = 0x0F;	}	if (opti82c46x & mask) {		ops = &opti82c46x_port_ops;		pio_modes = 0x0F;	}	/* Probe for automatically detectable controllers */	if (io == 0x1F0 && ops == &legacy_port_ops) {		unsigned long flags;		local_irq_save(flags);		/* Probes */		inb(0x1F5);		outb(inb(0x1F2) | 0x80, 0x1F2);		inb(0x1F2);		inb(0x3F6);		inb(0x3F6);		inb(0x1F2);		inb(0x1F2);		if ((inb(0x1F2) & 0x80) == 0) {			/* PDC20230c or 20630 ? */			printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");				pio_modes = 0x07;			ops = &pdc20230_port_ops;			iordy = ATA_FLAG_NO_IORDY;			udelay(100);			inb(0x1F5);		} else {			outb(0x55, 0x1F2);			inb(0x1F2);			inb(0x1F2);			if (inb(0x1F2) == 0x00) {				printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n");			}		}		local_irq_restore(flags);	}	/* Chip does mode setting by command snooping */	if (ops == &legacy_port_ops && (autospeed & mask))		ops = &simple_port_ops;	ret = -ENOMEM;	host = ata_host_alloc(&pdev->dev, 1);	if (!host)		goto fail;	ap = host->ports[0];	ap->ops = ops;	ap->pio_mask = pio_modes;	ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;	ap->ioaddr.cmd_addr = io_addr;	ap->ioaddr.altstatus_addr = ctrl_addr;	ap->ioaddr.ctl_addr = ctrl_addr;	ata_std_ports(&ap->ioaddr);	ap->private_data = ld;	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);	ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);	if (ret)		goto fail;	legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);	ld->platform_dev = pdev;	return 0;fail:	platform_device_unregister(pdev);	return ret;}/** *	legacy_check_special_cases	-	ATA special cases *	@p: PCI device to check *	@master: set this if we find an ATA master *	@master: set this if we find an ATA secondary * *	A small number of vendors implemented early PCI ATA interfaces on bridge logic *	without the ATA interface being PCI visible. Where we have a matching PCI driver *	we must skip the relevant device here. If we don't know about it then the legacy *	driver is the right driver anyway. */static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary){	/* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */	if (p->vendor == 0x1078 && p->device == 0x0000) {		*primary = *secondary = 1;		return;	}	/* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */	if (p->vendor == 0x1078 && p->device == 0x0002) {		*primary = *secondary = 1;		return;	}	/* Intel MPIIX - PIO ATA on non PCI side of bridge */	if (p->vendor == 0x8086 && p->device == 0x1234) {		u16 r;		pci_read_config_word(p, 0x6C, &r);		if (r & 0x8000) {	/* ATA port enabled */			if (r & 0x4000)				*secondary = 1;			else				*primary = 1;		}		return;	}}/** *	legacy_init		-	attach legacy interfaces * *	Attach legacy IDE interfaces by scanning the usual IRQ/port suspects. *	Right now we do not scan the ide0 and ide1 address but should do so *	for non PCI systems or systems with no PCI IDE legacy mode devices. *	If you fix that note there are special cases to consider like VLB *	drivers and CS5510/20. */static __init int legacy_init(void){	int i;	int ct = 0;	int primary = 0;	int secondary = 0;	int last_port = NR_HOST;	struct pci_dev *p = NULL;	for_each_pci_dev(p) {		int r;		/* Check for any overlap of the system ATA mappings. Native mode controllers		   stuck on these addresses or some devices in 'raid' mode won't be found by		   the storage class test */		for (r = 0; r < 6; r++) {			if (pci_resource_start(p, r) == 0x1f0)				primary = 1;			if (pci_resource_start(p, r) == 0x170)				secondary = 1;		}		/* Check for special cases */		legacy_check_special_cases(p, &primary, &secondary);		/* If PCI bus is present then don't probe for tertiary legacy ports */		if (probe_all == 0)			last_port = 2;	}	/* If an OPTI 82C46X is present find out where the channels are */	if (opti82c46x) {		static const char *optis[4] = {			"3/463MV", "5MV",			"5MVA", "5MVB"		};		u8 chans = 1;		u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;		opti82c46x = 3;	/* Assume master and slave first */		printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]);		if (ctrl == 3)			chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;		ctrl = opti_syscfg(0xAC);		/* Check enabled and this port is the 465MV port. On the		   MVB we may have two channels */		if (ctrl & 8) {			if (ctrl & 4)				opti82c46x = 2;	/* Slave */			else				opti82c46x = 1;	/* Master */			if (chans == 2)				opti82c46x = 3; /* Master and Slave */		}	/* Slave only */		else if (chans == 1)			opti82c46x = 1;	}	for (i = 0; i < last_port; i++) {		/* Skip primary if we have seen a PCI one */		if (i == 0 && primary == 1)			continue;		/* Skip secondary if we have seen a PCI one */		if (i == 1 && secondary == 1)			continue;		if (legacy_init_one(i, legacy_port[i],				   legacy_port[i] + 0x0206,				   legacy_irq[i]) == 0)			ct++;	}	if (ct != 0)		return 0;	return -ENODEV;}static __exit void legacy_exit(void){	int i;	for (i = 0; i < nr_legacy_host; i++) {		struct legacy_data *ld = &legacy_data[i];		ata_host_detach(legacy_host[i]);		platform_device_unregister(ld->platform_dev);		if (ld->timing)			release_region(ld->timing, 2);	}}MODULE_AUTHOR("Alan Cox");MODULE_DESCRIPTION("low-level driver for legacy ATA");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);module_param(probe_all, int, 0);module_param(autospeed, int, 0);module_param(ht6560a, int, 0);module_param(ht6560b, int, 0);module_param(opti82c611a, int, 0);module_param(opti82c46x, int, 0);module_param(pio_mask, int, 0);module_param(iordy_mask, int, 0);module_init(legacy_init);module_exit(legacy_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -