📄 pata_legacy.c
字号:
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 + -