diff options
Diffstat (limited to 'drivers/net/wireless/orinoco/main.c')
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 297 |
1 files changed, 64 insertions, 233 deletions
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 0727b41a397..dab6649ad0c 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -210,9 +210,10 @@ struct orinoco_rx_data { | |||
210 | /* Function prototypes */ | 210 | /* Function prototypes */ |
211 | /********************************************************************/ | 211 | /********************************************************************/ |
212 | 212 | ||
213 | static void __orinoco_set_multicast_list(struct net_device *dev); | 213 | static int __orinoco_set_multicast_list(struct net_device *dev); |
214 | static int __orinoco_up(struct orinoco_private *priv); | 214 | static int __orinoco_up(struct orinoco_private *priv); |
215 | static int __orinoco_down(struct orinoco_private *priv); | 215 | static int __orinoco_down(struct orinoco_private *priv); |
216 | static int __orinoco_commit(struct orinoco_private *priv); | ||
216 | 217 | ||
217 | /********************************************************************/ | 218 | /********************************************************************/ |
218 | /* Internal helper functions */ | 219 | /* Internal helper functions */ |
@@ -1524,7 +1525,7 @@ static int __orinoco_up(struct orinoco_private *priv) | |||
1524 | 1525 | ||
1525 | netif_carrier_off(dev); /* just to make sure */ | 1526 | netif_carrier_off(dev); /* just to make sure */ |
1526 | 1527 | ||
1527 | err = __orinoco_program_rids(dev); | 1528 | err = __orinoco_commit(priv); |
1528 | if (err) { | 1529 | if (err) { |
1529 | printk(KERN_ERR "%s: Error %d configuring card\n", | 1530 | printk(KERN_ERR "%s: Error %d configuring card\n", |
1530 | dev->name, err); | 1531 | dev->name, err); |
@@ -1593,237 +1594,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv) | |||
1593 | return err; | 1594 | return err; |
1594 | } | 1595 | } |
1595 | 1596 | ||
1596 | int __orinoco_program_rids(struct net_device *dev) | 1597 | static int |
1597 | { | ||
1598 | struct orinoco_private *priv = ndev_priv(dev); | ||
1599 | hermes_t *hw = &priv->hw; | ||
1600 | int err; | ||
1601 | struct hermes_idstring idbuf; | ||
1602 | |||
1603 | /* Set the MAC address */ | ||
1604 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, | ||
1605 | HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); | ||
1606 | if (err) { | ||
1607 | printk(KERN_ERR "%s: Error %d setting MAC address\n", | ||
1608 | dev->name, err); | ||
1609 | return err; | ||
1610 | } | ||
1611 | |||
1612 | /* Set up the link mode */ | ||
1613 | err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, | ||
1614 | priv->port_type); | ||
1615 | if (err) { | ||
1616 | printk(KERN_ERR "%s: Error %d setting port type\n", | ||
1617 | dev->name, err); | ||
1618 | return err; | ||
1619 | } | ||
1620 | /* Set the channel/frequency */ | ||
1621 | if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { | ||
1622 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1623 | HERMES_RID_CNFOWNCHANNEL, | ||
1624 | priv->channel); | ||
1625 | if (err) { | ||
1626 | printk(KERN_ERR "%s: Error %d setting channel %d\n", | ||
1627 | dev->name, err, priv->channel); | ||
1628 | return err; | ||
1629 | } | ||
1630 | } | ||
1631 | |||
1632 | if (priv->has_ibss) { | ||
1633 | u16 createibss; | ||
1634 | |||
1635 | if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { | ||
1636 | printk(KERN_WARNING "%s: This firmware requires an " | ||
1637 | "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); | ||
1638 | /* With wvlan_cs, in this case, we would crash. | ||
1639 | * hopefully, this driver will behave better... | ||
1640 | * Jean II */ | ||
1641 | createibss = 0; | ||
1642 | } else { | ||
1643 | createibss = priv->createibss; | ||
1644 | } | ||
1645 | |||
1646 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1647 | HERMES_RID_CNFCREATEIBSS, | ||
1648 | createibss); | ||
1649 | if (err) { | ||
1650 | printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", | ||
1651 | dev->name, err); | ||
1652 | return err; | ||
1653 | } | ||
1654 | } | ||
1655 | |||
1656 | /* Set the desired BSSID */ | ||
1657 | err = __orinoco_hw_set_wap(priv); | ||
1658 | if (err) { | ||
1659 | printk(KERN_ERR "%s: Error %d setting AP address\n", | ||
1660 | dev->name, err); | ||
1661 | return err; | ||
1662 | } | ||
1663 | /* Set the desired ESSID */ | ||
1664 | idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); | ||
1665 | memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); | ||
1666 | /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ | ||
1667 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, | ||
1668 | HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), | ||
1669 | &idbuf); | ||
1670 | if (err) { | ||
1671 | printk(KERN_ERR "%s: Error %d setting OWNSSID\n", | ||
1672 | dev->name, err); | ||
1673 | return err; | ||
1674 | } | ||
1675 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, | ||
1676 | HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), | ||
1677 | &idbuf); | ||
1678 | if (err) { | ||
1679 | printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", | ||
1680 | dev->name, err); | ||
1681 | return err; | ||
1682 | } | ||
1683 | |||
1684 | /* Set the station name */ | ||
1685 | idbuf.len = cpu_to_le16(strlen(priv->nick)); | ||
1686 | memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); | ||
1687 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, | ||
1688 | HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), | ||
1689 | &idbuf); | ||
1690 | if (err) { | ||
1691 | printk(KERN_ERR "%s: Error %d setting nickname\n", | ||
1692 | dev->name, err); | ||
1693 | return err; | ||
1694 | } | ||
1695 | |||
1696 | /* Set AP density */ | ||
1697 | if (priv->has_sensitivity) { | ||
1698 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1699 | HERMES_RID_CNFSYSTEMSCALE, | ||
1700 | priv->ap_density); | ||
1701 | if (err) { | ||
1702 | printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " | ||
1703 | "Disabling sensitivity control\n", | ||
1704 | dev->name, err); | ||
1705 | |||
1706 | priv->has_sensitivity = 0; | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | /* Set RTS threshold */ | ||
1711 | err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, | ||
1712 | priv->rts_thresh); | ||
1713 | if (err) { | ||
1714 | printk(KERN_ERR "%s: Error %d setting RTS threshold\n", | ||
1715 | dev->name, err); | ||
1716 | return err; | ||
1717 | } | ||
1718 | |||
1719 | /* Set fragmentation threshold or MWO robustness */ | ||
1720 | if (priv->has_mwo) | ||
1721 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1722 | HERMES_RID_CNFMWOROBUST_AGERE, | ||
1723 | priv->mwo_robust); | ||
1724 | else | ||
1725 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1726 | HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, | ||
1727 | priv->frag_thresh); | ||
1728 | if (err) { | ||
1729 | printk(KERN_ERR "%s: Error %d setting fragmentation\n", | ||
1730 | dev->name, err); | ||
1731 | return err; | ||
1732 | } | ||
1733 | |||
1734 | /* Set bitrate */ | ||
1735 | err = __orinoco_hw_set_bitrate(priv); | ||
1736 | if (err) { | ||
1737 | printk(KERN_ERR "%s: Error %d setting bitrate\n", | ||
1738 | dev->name, err); | ||
1739 | return err; | ||
1740 | } | ||
1741 | |||
1742 | /* Set power management */ | ||
1743 | if (priv->has_pm) { | ||
1744 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1745 | HERMES_RID_CNFPMENABLED, | ||
1746 | priv->pm_on); | ||
1747 | if (err) { | ||
1748 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1749 | dev->name, err); | ||
1750 | return err; | ||
1751 | } | ||
1752 | |||
1753 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1754 | HERMES_RID_CNFMULTICASTRECEIVE, | ||
1755 | priv->pm_mcast); | ||
1756 | if (err) { | ||
1757 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1758 | dev->name, err); | ||
1759 | return err; | ||
1760 | } | ||
1761 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1762 | HERMES_RID_CNFMAXSLEEPDURATION, | ||
1763 | priv->pm_period); | ||
1764 | if (err) { | ||
1765 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1766 | dev->name, err); | ||
1767 | return err; | ||
1768 | } | ||
1769 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1770 | HERMES_RID_CNFPMHOLDOVERDURATION, | ||
1771 | priv->pm_timeout); | ||
1772 | if (err) { | ||
1773 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1774 | dev->name, err); | ||
1775 | return err; | ||
1776 | } | ||
1777 | } | ||
1778 | |||
1779 | /* Set preamble - only for Symbol so far... */ | ||
1780 | if (priv->has_preamble) { | ||
1781 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1782 | HERMES_RID_CNFPREAMBLE_SYMBOL, | ||
1783 | priv->preamble); | ||
1784 | if (err) { | ||
1785 | printk(KERN_ERR "%s: Error %d setting preamble\n", | ||
1786 | dev->name, err); | ||
1787 | return err; | ||
1788 | } | ||
1789 | } | ||
1790 | |||
1791 | /* Set up encryption */ | ||
1792 | if (priv->has_wep || priv->has_wpa) { | ||
1793 | err = __orinoco_hw_setup_enc(priv); | ||
1794 | if (err) { | ||
1795 | printk(KERN_ERR "%s: Error %d activating encryption\n", | ||
1796 | dev->name, err); | ||
1797 | return err; | ||
1798 | } | ||
1799 | } | ||
1800 | |||
1801 | if (priv->iw_mode == IW_MODE_MONITOR) { | ||
1802 | /* Enable monitor mode */ | ||
1803 | dev->type = ARPHRD_IEEE80211; | ||
1804 | err = hermes_docmd_wait(hw, HERMES_CMD_TEST | | ||
1805 | HERMES_TEST_MONITOR, 0, NULL); | ||
1806 | } else { | ||
1807 | /* Disable monitor mode */ | ||
1808 | dev->type = ARPHRD_ETHER; | ||
1809 | err = hermes_docmd_wait(hw, HERMES_CMD_TEST | | ||
1810 | HERMES_TEST_STOP, 0, NULL); | ||
1811 | } | ||
1812 | if (err) | ||
1813 | return err; | ||
1814 | |||
1815 | /* Set promiscuity / multicast*/ | ||
1816 | priv->promiscuous = 0; | ||
1817 | priv->mc_count = 0; | ||
1818 | |||
1819 | /* FIXME: what about netif_tx_lock */ | ||
1820 | __orinoco_set_multicast_list(dev); | ||
1821 | |||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | /* FIXME: return int? */ | ||
1826 | static void | ||
1827 | __orinoco_set_multicast_list(struct net_device *dev) | 1598 | __orinoco_set_multicast_list(struct net_device *dev) |
1828 | { | 1599 | { |
1829 | struct orinoco_private *priv = ndev_priv(dev); | 1600 | struct orinoco_private *priv = ndev_priv(dev); |
@@ -1843,6 +1614,8 @@ __orinoco_set_multicast_list(struct net_device *dev) | |||
1843 | 1614 | ||
1844 | err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count, | 1615 | err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count, |
1845 | promisc); | 1616 | promisc); |
1617 | |||
1618 | return err; | ||
1846 | } | 1619 | } |
1847 | 1620 | ||
1848 | /* This must be called from user context, without locks held - use | 1621 | /* This must be called from user context, without locks held - use |
@@ -1920,6 +1693,64 @@ void orinoco_reset(struct work_struct *work) | |||
1920 | printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); | 1693 | printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); |
1921 | } | 1694 | } |
1922 | 1695 | ||
1696 | static int __orinoco_commit(struct orinoco_private *priv) | ||
1697 | { | ||
1698 | struct net_device *dev = priv->ndev; | ||
1699 | int err = 0; | ||
1700 | |||
1701 | err = orinoco_hw_program_rids(priv); | ||
1702 | |||
1703 | /* FIXME: what about netif_tx_lock */ | ||
1704 | (void) __orinoco_set_multicast_list(dev); | ||
1705 | |||
1706 | return err; | ||
1707 | } | ||
1708 | |||
1709 | /* Ensures configuration changes are applied. May result in a reset. | ||
1710 | * The caller should hold priv->lock | ||
1711 | */ | ||
1712 | int orinoco_commit(struct orinoco_private *priv) | ||
1713 | { | ||
1714 | struct net_device *dev = priv->ndev; | ||
1715 | hermes_t *hw = &priv->hw; | ||
1716 | int err; | ||
1717 | |||
1718 | if (priv->broken_disableport) { | ||
1719 | schedule_work(&priv->reset_work); | ||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1723 | err = hermes_disable_port(hw, 0); | ||
1724 | if (err) { | ||
1725 | printk(KERN_WARNING "%s: Unable to disable port " | ||
1726 | "while reconfiguring card\n", dev->name); | ||
1727 | priv->broken_disableport = 1; | ||
1728 | goto out; | ||
1729 | } | ||
1730 | |||
1731 | err = __orinoco_commit(priv); | ||
1732 | if (err) { | ||
1733 | printk(KERN_WARNING "%s: Unable to reconfigure card\n", | ||
1734 | dev->name); | ||
1735 | goto out; | ||
1736 | } | ||
1737 | |||
1738 | err = hermes_enable_port(hw, 0); | ||
1739 | if (err) { | ||
1740 | printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", | ||
1741 | dev->name); | ||
1742 | goto out; | ||
1743 | } | ||
1744 | |||
1745 | out: | ||
1746 | if (err) { | ||
1747 | printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); | ||
1748 | schedule_work(&priv->reset_work); | ||
1749 | err = 0; | ||
1750 | } | ||
1751 | return err; | ||
1752 | } | ||
1753 | |||
1923 | /********************************************************************/ | 1754 | /********************************************************************/ |
1924 | /* Interrupt handler */ | 1755 | /* Interrupt handler */ |
1925 | /********************************************************************/ | 1756 | /********************************************************************/ |