-struct ata_legacy_devres {
- unsigned int mask;
- unsigned long cmd_port[2];
- void __iomem * cmd_addr[2];
- void __iomem * ctl_addr[2];
- unsigned int irq[2];
- void * irq_dev_id[2];
-};
-
-static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- if (!legacy_dr->irq[i])
- continue;
-
- free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
- legacy_dr->irq[i] = 0;
- legacy_dr->irq_dev_id[i] = NULL;
- }
-}
-
-static void ata_legacy_release(struct device *gdev, void *res)
-{
- struct ata_legacy_devres *this = res;
- int i;
-
- ata_legacy_free_irqs(this);
-
- for (i = 0; i < 2; i++) {
- if (this->cmd_addr[i])
- ioport_unmap(this->cmd_addr[i]);
- if (this->ctl_addr[i])
- ioport_unmap(this->ctl_addr[i]);
- if (this->cmd_port[i])
- release_region(this->cmd_port[i], 8);
- }
-}
-
-static int ata_init_legacy_port(struct ata_port *ap,
- struct ata_legacy_devres *legacy_dr)
-{
- struct ata_host *host = ap->host;
- int port_no = ap->port_no;
- unsigned long cmd_port, ctl_port;
-
- if (port_no == 0) {
- cmd_port = ATA_PRIMARY_CMD;
- ctl_port = ATA_PRIMARY_CTL;
- } else {
- cmd_port = ATA_SECONDARY_CMD;
- ctl_port = ATA_SECONDARY_CTL;
- }
-
- /* request cmd_port */
- if (request_region(cmd_port, 8, "libata"))
- legacy_dr->cmd_port[port_no] = cmd_port;
- else {
- dev_printk(KERN_WARNING, host->dev,
- "0x%0lX IDE port busy\n", cmd_port);
- return -EBUSY;
- }
-
- /* iomap cmd and ctl ports */
- legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
- legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
- if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no]) {
- dev_printk(KERN_WARNING, host->dev,
- "failed to map cmd/ctl ports\n");
- return -ENOMEM;
- }
-
- /* init IO addresses */
- ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
- ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
- ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
- ata_std_ports(&ap->ioaddr);
-
- return 0;
-}
-
-/**
- * ata_init_legacy_host - acquire legacy ATA resources and init ATA host
- * @host: target ATA host
- * @was_busy: out parameter, indicates whether any port was busy
- *
- * Acquire legacy ATA resources for the first two ports of @host
- * and initialize it accordingly. Ports marked dummy are skipped
- * and resource acquistion failure makes the port dummy.
- *
- * LOCKING:
- * Inherited from calling layer (may sleep).
- *
- * RETURNS:
- * 0 if at least one port is initialized, -ENODEV if no port is
- * available.
- */
-static int ata_init_legacy_host(struct ata_host *host, int *was_busy)
-{
- struct device *gdev = host->dev;
- struct ata_legacy_devres *legacy_dr;
- int i, rc;
-
- if (!devres_open_group(gdev, NULL, GFP_KERNEL))
- return -ENOMEM;
-
- rc = -ENOMEM;
- legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
- GFP_KERNEL);
- if (!legacy_dr)
- goto err_out;
- devres_add(gdev, legacy_dr);
-
- for (i = 0; i < 2; i++) {
- if (ata_port_is_dummy(host->ports[i]))
- continue;
-
- rc = ata_init_legacy_port(host->ports[i], legacy_dr);
- if (rc == 0)
- legacy_dr->mask |= 1 << i;
- else {
- if (rc == -EBUSY)
- (*was_busy)++;
- host->ports[i]->ops = &ata_dummy_port_ops;
- }
- }
-
- if (!legacy_dr->mask) {
- dev_printk(KERN_ERR, gdev, "no available legacy port\n");
- return -ENODEV;
- }
-
- devres_remove_group(gdev, NULL);
- return 0;
-
- err_out:
- devres_release_group(gdev, NULL);
- return rc;
-}
-
-/**
- * ata_request_legacy_irqs - request legacy ATA IRQs
- * @host: target ATA host
- * @handler: array of IRQ handlers
- * @irq_flags: array of IRQ flags
- * @dev_id: array of IRQ dev_ids
- *
- * Request legacy IRQs for non-dummy legacy ports in @host. All
- * IRQ parameters are passed as array to allow ports to have
- * separate IRQ handlers.
- *
- * LOCKING:
- * Inherited from calling layer (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-static int ata_request_legacy_irqs(struct ata_host *host,
- irq_handler_t const *handler,
- const unsigned int *irq_flags,
- void * const *dev_id)
-{
- struct device *gdev = host->dev;
- struct ata_legacy_devres *legacy_dr;
- int i, rc;
-
- legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
- BUG_ON(!legacy_dr);
-
- for (i = 0; i < 2; i++) {
- unsigned int irq;
-
- /* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
- if (i == 0)
- irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
- else
- irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
-
- if (!(legacy_dr->mask & (1 << i)))
- continue;
-
- if (!handler[i]) {
- dev_printk(KERN_ERR, gdev,
- "NULL handler specified for port %d\n", i);
- rc = -EINVAL;
- goto err_out;
- }
-
- rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
- dev_id[i]);
- if (rc) {
- dev_printk(KERN_ERR, gdev,
- "irq %u request failed (errno=%d)\n", irq, rc);
- goto err_out;
- }
-
- /* record irq allocation in legacy_dr */
- legacy_dr->irq[i] = irq;
- legacy_dr->irq_dev_id[i] = dev_id[i];
-
- /* only used to print info */
- if (i == 0)
- host->irq = irq;
- else
- host->irq2 = irq;
- }
-
- return 0;
-
- err_out:
- ata_legacy_free_irqs(legacy_dr);
- return rc;
-}
-