diff options
Diffstat (limited to 'drivers/scsi/pcmcia/nsp_cs.c')
-rw-r--r-- | drivers/scsi/pcmcia/nsp_cs.c | 194 |
1 files changed, 95 insertions, 99 deletions
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 24e6cb8396e3..11a61ea8d5d9 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c | |||
@@ -1606,133 +1606,129 @@ static void nsp_cs_detach(struct pcmcia_device *link) | |||
1606 | is received, to configure the PCMCIA socket, and to make the | 1606 | is received, to configure the PCMCIA socket, and to make the |
1607 | ethernet device available to the system. | 1607 | ethernet device available to the system. |
1608 | ======================================================================*/ | 1608 | ======================================================================*/ |
1609 | #define CS_CHECK(fn, ret) \ | ||
1610 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
1611 | /*====================================================================*/ | ||
1612 | static int nsp_cs_config(struct pcmcia_device *link) | ||
1613 | { | ||
1614 | int ret; | ||
1615 | scsi_info_t *info = link->priv; | ||
1616 | tuple_t tuple; | ||
1617 | cisparse_t parse; | ||
1618 | int last_ret, last_fn; | ||
1619 | unsigned char tuple_data[64]; | ||
1620 | config_info_t conf; | ||
1621 | win_req_t req; | ||
1622 | memreq_t map; | ||
1623 | cistpl_cftable_entry_t dflt = { 0 }; | ||
1624 | struct Scsi_Host *host; | ||
1625 | nsp_hw_data *data = &nsp_data_base; | ||
1626 | |||
1627 | nsp_dbg(NSP_DEBUG_INIT, "in"); | ||
1628 | |||
1629 | tuple.Attributes = 0; | ||
1630 | tuple.TupleData = tuple_data; | ||
1631 | tuple.TupleDataMax = sizeof(tuple_data); | ||
1632 | tuple.TupleOffset = 0; | ||
1633 | |||
1634 | /* Look up the current Vcc */ | ||
1635 | CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); | ||
1636 | 1609 | ||
1637 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 1610 | struct nsp_cs_configdata { |
1638 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | 1611 | nsp_hw_data *data; |
1639 | while (1) { | 1612 | win_req_t req; |
1640 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | 1613 | }; |
1641 | 1614 | ||
1642 | if (pcmcia_get_tuple_data(link, &tuple) != 0 || | 1615 | static int nsp_cs_config_check(struct pcmcia_device *p_dev, |
1643 | pcmcia_parse_tuple(link, &tuple, &parse) != 0) | 1616 | cistpl_cftable_entry_t *cfg, |
1644 | goto next_entry; | 1617 | cistpl_cftable_entry_t *dflt, |
1618 | unsigned int vcc, | ||
1619 | void *priv_data) | ||
1620 | { | ||
1621 | struct nsp_cs_configdata *cfg_mem = priv_data; | ||
1645 | 1622 | ||
1646 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } | 1623 | if (cfg->index == 0) |
1647 | if (cfg->index == 0) { goto next_entry; } | 1624 | return -ENODEV; |
1648 | link->conf.ConfigIndex = cfg->index; | ||
1649 | 1625 | ||
1650 | /* Does this card need audio output? */ | 1626 | /* Does this card need audio output? */ |
1651 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | 1627 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { |
1652 | link->conf.Attributes |= CONF_ENABLE_SPKR; | 1628 | p_dev->conf.Attributes |= CONF_ENABLE_SPKR; |
1653 | link->conf.Status = CCSR_AUDIO_ENA; | 1629 | p_dev->conf.Status = CCSR_AUDIO_ENA; |
1654 | } | 1630 | } |
1655 | 1631 | ||
1656 | /* Use power settings for Vcc and Vpp if present */ | 1632 | /* Use power settings for Vcc and Vpp if present */ |
1657 | /* Note that the CIS values need to be rescaled */ | 1633 | /* Note that the CIS values need to be rescaled */ |
1658 | if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { | 1634 | if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { |
1659 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) { | 1635 | if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) |
1660 | goto next_entry; | 1636 | return -ENODEV; |
1661 | } | 1637 | else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) { |
1662 | } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) { | 1638 | if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000) |
1663 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) { | 1639 | return -ENODEV; |
1664 | goto next_entry; | ||
1665 | } | ||
1666 | } | 1640 | } |
1667 | 1641 | ||
1668 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) { | 1642 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) { |
1669 | link->conf.Vpp = | 1643 | p_dev->conf.Vpp = |
1670 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | 1644 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; |
1671 | } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) { | 1645 | } else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) { |
1672 | link->conf.Vpp = | 1646 | p_dev->conf.Vpp = |
1673 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | 1647 | dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; |
1674 | } | 1648 | } |
1675 | 1649 | ||
1676 | /* Do we need to allocate an interrupt? */ | 1650 | /* Do we need to allocate an interrupt? */ |
1677 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) { | 1651 | if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) |
1678 | link->conf.Attributes |= CONF_ENABLE_IRQ; | 1652 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; |
1679 | } | ||
1680 | 1653 | ||
1681 | /* IO window settings */ | 1654 | /* IO window settings */ |
1682 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | 1655 | p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; |
1683 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | 1656 | if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { |
1684 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | 1657 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; |
1685 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | 1658 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; |
1686 | if (!(io->flags & CISTPL_IO_8BIT)) | 1659 | if (!(io->flags & CISTPL_IO_8BIT)) |
1687 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | 1660 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; |
1688 | if (!(io->flags & CISTPL_IO_16BIT)) | 1661 | if (!(io->flags & CISTPL_IO_16BIT)) |
1689 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | 1662 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; |
1690 | link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | 1663 | p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; |
1691 | link->io.BasePort1 = io->win[0].base; | 1664 | p_dev->io.BasePort1 = io->win[0].base; |
1692 | link->io.NumPorts1 = io->win[0].len; | 1665 | p_dev->io.NumPorts1 = io->win[0].len; |
1693 | if (io->nwin > 1) { | 1666 | if (io->nwin > 1) { |
1694 | link->io.Attributes2 = link->io.Attributes1; | 1667 | p_dev->io.Attributes2 = p_dev->io.Attributes1; |
1695 | link->io.BasePort2 = io->win[1].base; | 1668 | p_dev->io.BasePort2 = io->win[1].base; |
1696 | link->io.NumPorts2 = io->win[1].len; | 1669 | p_dev->io.NumPorts2 = io->win[1].len; |
1697 | } | 1670 | } |
1698 | /* This reserves IO space but doesn't actually enable it */ | 1671 | /* This reserves IO space but doesn't actually enable it */ |
1699 | if (pcmcia_request_io(link, &link->io) != 0) | 1672 | if (pcmcia_request_io(p_dev, &p_dev->io) != 0) |
1700 | goto next_entry; | 1673 | goto next_entry; |
1701 | } | 1674 | } |
1702 | 1675 | ||
1703 | if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { | 1676 | if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { |
1704 | cistpl_mem_t *mem = | 1677 | memreq_t map; |
1705 | (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; | 1678 | cistpl_mem_t *mem = |
1706 | req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; | 1679 | (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; |
1707 | req.Attributes |= WIN_ENABLE; | 1680 | cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; |
1708 | req.Base = mem->win[0].host_addr; | 1681 | cfg_mem->req.Attributes |= WIN_ENABLE; |
1709 | req.Size = mem->win[0].len; | 1682 | cfg_mem->req.Base = mem->win[0].host_addr; |
1710 | if (req.Size < 0x1000) { | 1683 | cfg_mem->req.Size = mem->win[0].len; |
1711 | req.Size = 0x1000; | 1684 | if (cfg_mem->req.Size < 0x1000) |
1712 | } | 1685 | cfg_mem->req.Size = 0x1000; |
1713 | req.AccessSpeed = 0; | 1686 | cfg_mem->req.AccessSpeed = 0; |
1714 | if (pcmcia_request_window(&link, &req, &link->win) != 0) | 1687 | if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0) |
1715 | goto next_entry; | 1688 | goto next_entry; |
1716 | map.Page = 0; map.CardOffset = mem->win[0].card_addr; | 1689 | map.Page = 0; map.CardOffset = mem->win[0].card_addr; |
1717 | if (pcmcia_map_mem_page(link->win, &map) != 0) | 1690 | if (pcmcia_map_mem_page(p_dev->win, &map) != 0) |
1718 | goto next_entry; | 1691 | goto next_entry; |
1719 | 1692 | ||
1720 | data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size); | 1693 | cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size); |
1721 | data->MmioLength = req.Size; | 1694 | cfg_mem->data->MmioLength = cfg_mem->req.Size; |
1722 | } | 1695 | } |
1723 | /* If we got this far, we're cool! */ | 1696 | /* If we got this far, we're cool! */ |
1724 | break; | 1697 | return 0; |
1725 | |||
1726 | next_entry: | ||
1727 | nsp_dbg(NSP_DEBUG_INIT, "next"); | ||
1728 | pcmcia_disable_device(link); | ||
1729 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); | ||
1730 | } | 1698 | } |
1731 | 1699 | ||
1700 | next_entry: | ||
1701 | nsp_dbg(NSP_DEBUG_INIT, "next"); | ||
1702 | pcmcia_disable_device(p_dev); | ||
1703 | return -ENODEV; | ||
1704 | } | ||
1705 | |||
1706 | static int nsp_cs_config(struct pcmcia_device *link) | ||
1707 | { | ||
1708 | int ret; | ||
1709 | scsi_info_t *info = link->priv; | ||
1710 | struct nsp_cs_configdata *cfg_mem; | ||
1711 | struct Scsi_Host *host; | ||
1712 | nsp_hw_data *data = &nsp_data_base; | ||
1713 | |||
1714 | nsp_dbg(NSP_DEBUG_INIT, "in"); | ||
1715 | |||
1716 | cfg_mem = kzalloc(sizeof(cfg_mem), GFP_KERNEL); | ||
1717 | if (!cfg_mem) | ||
1718 | return -ENOMEM; | ||
1719 | cfg_mem->data = data; | ||
1720 | |||
1721 | ret = pcmcia_loop_config(link, nsp_cs_config_check, cfg_mem); | ||
1722 | goto cs_failed; | ||
1723 | |||
1732 | if (link->conf.Attributes & CONF_ENABLE_IRQ) { | 1724 | if (link->conf.Attributes & CONF_ENABLE_IRQ) { |
1733 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); | 1725 | if (pcmcia_request_irq(link, &link->irq)) |
1726 | goto cs_failed; | ||
1734 | } | 1727 | } |
1735 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); | 1728 | |
1729 | ret = pcmcia_request_configuration(link, &link->conf); | ||
1730 | if (ret) | ||
1731 | goto cs_failed; | ||
1736 | 1732 | ||
1737 | if (free_ports) { | 1733 | if (free_ports) { |
1738 | if (link->io.BasePort1) { | 1734 | if (link->io.BasePort1) { |
@@ -1790,20 +1786,20 @@ static int nsp_cs_config(struct pcmcia_device *link) | |||
1790 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | 1786 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, |
1791 | link->io.BasePort2+link->io.NumPorts2-1); | 1787 | link->io.BasePort2+link->io.NumPorts2-1); |
1792 | if (link->win) | 1788 | if (link->win) |
1793 | printk(", mem 0x%06lx-0x%06lx", req.Base, | 1789 | printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base, |
1794 | req.Base+req.Size-1); | 1790 | cfg_mem->req.Base+cfg_mem->req.Size-1); |
1795 | printk("\n"); | 1791 | printk("\n"); |
1796 | 1792 | ||
1793 | kfree(cfg_mem); | ||
1797 | return 0; | 1794 | return 0; |
1798 | 1795 | ||
1799 | cs_failed: | 1796 | cs_failed: |
1800 | nsp_dbg(NSP_DEBUG_INIT, "config fail"); | 1797 | nsp_dbg(NSP_DEBUG_INIT, "config fail"); |
1801 | cs_error(link, last_fn, last_ret); | ||
1802 | nsp_cs_release(link); | 1798 | nsp_cs_release(link); |
1799 | kfree(cfg_mem); | ||
1803 | 1800 | ||
1804 | return -ENODEV; | 1801 | return -ENODEV; |
1805 | } /* nsp_cs_config */ | 1802 | } /* nsp_cs_config */ |
1806 | #undef CS_CHECK | ||
1807 | 1803 | ||
1808 | 1804 | ||
1809 | /*====================================================================== | 1805 | /*====================================================================== |