orinoco: Fix transmit for Agere/Lucent with fw 9.x
authorDavid Kilroy <kilroyd@gmail.com>
Thu, 21 Aug 2008 22:27:56 +0000 (23:27 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 22 Aug 2008 23:28:05 +0000 (19:28 -0400)
The tx control word has moved into the 802.11 header area on these
firmwares.

Signed-off-by: David Kilroy <kilroyd@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/hermes.h
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.h

index 287f5363fda298bb0f0fc8b1148f44252a5eab83..1d0c5840f825963839e867ab4c52a994f31a174e 100644 (file)
 #define HERMES_802_11_OFFSET           (14)
 #define HERMES_802_3_OFFSET            (14+32)
 #define HERMES_802_2_OFFSET            (14+32+14)
+#define HERMES_TXCNTL2_OFFSET          (HERMES_802_3_OFFSET - 2)
 
 #define HERMES_RXSTAT_ERR              (0x0003)
 #define        HERMES_RXSTAT_BADCRC            (0x0001)
index 306697aa3330f9875328660369691e62cd3b3c27..b83415daa723ef069d915e6b85e5ae831e3daf74 100644 (file)
@@ -722,7 +722,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        u16 txfid = priv->txfid;
        struct ethhdr *eh;
        int data_off;
-       struct hermes_tx_descriptor desc;
+       int tx_control;
        unsigned long flags;
 
        if (! netif_running(dev)) {
@@ -756,21 +756,48 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 
        eh = (struct ethhdr *)skb->data;
 
-       memset(&desc, 0, sizeof(desc));
-       desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX);
-       err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0);
-       if (err) {
-               if (net_ratelimit())
-                       printk(KERN_ERR "%s: Error %d writing Tx descriptor "
-                              "to BAP\n", dev->name, err);
-               goto busy;
-       }
+       tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
 
-       /* Clear the 802.11 header and data length fields - some
-        * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
-        * if this isn't done. */
-       hermes_clear_words(hw, HERMES_DATA0,
-                          HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
+       if (priv->has_alt_txcntl) {
+               /* WPA enabled firmwares have tx_cntl at the end of
+                * the 802.11 header.  So write zeroed descriptor and
+                * 802.11 header at the same time
+                */
+               char desc[HERMES_802_3_OFFSET];
+               __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
+
+               memset(&desc, 0, sizeof(desc));
+
+               *txcntl = cpu_to_le16(tx_control);
+               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                       txfid, 0);
+               if (err) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "%s: Error %d writing Tx "
+                                      "descriptor to BAP\n", dev->name, err);
+                       goto busy;
+               }
+       } else {
+               struct hermes_tx_descriptor desc;
+
+               memset(&desc, 0, sizeof(desc));
+
+               desc.tx_control = cpu_to_le16(tx_control);
+               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                       txfid, 0);
+               if (err) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "%s: Error %d writing Tx "
+                                      "descriptor to BAP\n", dev->name, err);
+                       goto busy;
+               }
+
+               /* Clear the 802.11 header and data length fields - some
+                * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
+                * if this isn't done. */
+               hermes_clear_words(hw, HERMES_DATA0,
+                                  HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
+       }
 
        /* Encapsulate Ethernet-II frames */
        if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
@@ -2528,6 +2555,7 @@ static int determine_firmware(struct net_device *dev)
        priv->has_ibss = 1;
        priv->has_wep = 0;
        priv->has_big_wep = 0;
+       priv->has_alt_txcntl = 0;
        priv->do_fw_download = 0;
 
        /* Determine capabilities from the firmware version */
@@ -2550,6 +2578,7 @@ static int determine_firmware(struct net_device *dev)
                priv->has_hostscan = (firmver >= 0x8000a);
                priv->do_fw_download = 1;
                priv->broken_monitor = (firmver >= 0x80000);
+               priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
 
                /* Tested with Agere firmware :
                 *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
index e0acb633e9d56cc96605fe6d5f3ffe1e1e94a9c3..f93752ffb07cbf5bd5c3fa4a4fbf359a6b5e4643 100644 (file)
@@ -85,6 +85,7 @@ struct orinoco_private {
        unsigned int has_preamble:1;
        unsigned int has_sensitivity:1;
        unsigned int has_hostscan:1;
+       unsigned int has_alt_txcntl:1;
        unsigned int do_fw_download:1;
        unsigned int broken_disableport:1;
        unsigned int broken_monitor:1;