]> err.no Git - linux-2.6/commitdiff
[PATCH] bcm43xx: Move TX/RX related functions to its own file. Add basic RTS/CTS...
authorMichael Buesch <mbuesch@freenet.de>
Thu, 23 Feb 2006 20:15:39 +0000 (21:15 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 27 Mar 2006 16:18:40 +0000 (11:18 -0500)
Signed-off-by: Michael Buesch <mbuesch@freenet.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/bcm43xx/Makefile
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
drivers/net/wireless/bcm43xx/bcm43xx_dma.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_main.h
drivers/net/wireless/bcm43xx/bcm43xx_pio.c
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c [new file with mode: 0644]
drivers/net/wireless/bcm43xx/bcm43xx_xmit.h [new file with mode: 0644]

index c87c1525b39fb7687ab054102305d55d64bd9119..2962b5f9e3e78b2604dab5ebd1d34bef2e4a497c 100644 (file)
@@ -8,4 +8,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \
                bcm43xx_radio.o bcm43xx_phy.o \
                bcm43xx_power.o bcm43xx_wx.o \
                bcm43xx_leds.o bcm43xx_ethtool.o \
+               bcm43xx_xmit.o \
                $(bcm43xx-obj-y)
index 848717513b5f6984aba1e96554fe4d93f0392b56..21c75cae14bf1e86d9a0999aa00f1704a50e6425 100644 (file)
 /* Initial default iw_mode */
 #define BCM43xx_INITIAL_IWMODE                 IW_MODE_INFRA
 
-/* Values/Masks for the device TX header */
-#define BCM43xx_TXHDRFLAG_EXPECTACK            0x0001
-#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT                0x0008
-#define BCM43xx_TXHDRFLAG_DESTPSMODE           0x0020
-#define BCM43xx_TXHDRFLAG_FALLBACKOFDM         0x0100
-#define BCM43xx_TXHDRFLAG_FRAMEBURST           0x0800
-
-#define BCM43xx_TXHDRCTL_OFDM                  0x0001
-#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE                0x0010
-#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK       0x0030
-#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT      8
-
-#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK       0x00F0
-#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT      4
-#define BCM43xx_TXHDR_WSEC_ALGO_MASK           0x0003
-#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT          0
-
 /* Bus type PCI. */
 #define BCM43xx_BUSTYPE_PCI    0
 /* Bus type Silicone Backplane Bus. */
@@ -952,4 +935,10 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu
                __value;                                \
        })
 
+/** Helpers to print MAC addresses. */
+#define BCM43xx_MACFMT         "%02x:%02x:%02x:%02x:%02x:%02x"
+#define BCM43xx_MACARG(x)      ((u8*)(x))[0], ((u8*)(x))[1], \
+                               ((u8*)(x))[2], ((u8*)(x))[3], \
+                               ((u8*)(x))[4], ((u8*)(x))[5]
+
 #endif /* BCM43xx_H_ */
index 5a7dc43cd6763798e95253f76cf3b5fc3aa53440..0bae0be4be2e1d043cb7e8c7ebfe3685e3771b0e 100644 (file)
@@ -37,6 +37,7 @@
 #include "bcm43xx_debugfs.h"
 #include "bcm43xx_dma.h"
 #include "bcm43xx_pio.h"
+#include "bcm43xx_xmit.h"
 
 #define REALLY_BIG_BUFFER_SIZE (1024*256)
 
index af5c27f9bfda00d291ed705abd942d77ec1053ee..e20fbaf29e0b5190612159f1d7ce5257383ad876 100644 (file)
@@ -32,6 +32,7 @@
 #include "bcm43xx_main.h"
 #include "bcm43xx_debugfs.h"
 #include "bcm43xx_power.h"
+#include "bcm43xx_xmit.h"
 
 #include <linux/dmapool.h>
 #include <linux/pci.h>
index 899c06fe0bf54e22951f542fe15af948cbf21d69..f1ac9940f14c6a16cb0b1801f945743a7abc02e1 100644 (file)
@@ -50,6 +50,7 @@
 #include "bcm43xx_power.h"
 #include "bcm43xx_wx.h"
 #include "bcm43xx_ethtool.h"
+#include "bcm43xx_xmit.h"
 
 
 MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
@@ -342,234 +343,6 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
 }
 
-static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp,
-                                  const int ofdm_modulation)
-{
-       u8 rate;
-
-       if (ofdm_modulation) {
-               switch (plcp->raw[0] & 0xF) {
-               case 0xB:
-                       rate = IEEE80211_OFDM_RATE_6MB;
-                       break;
-               case 0xF:
-                       rate = IEEE80211_OFDM_RATE_9MB;
-                       break;
-               case 0xA:
-                       rate = IEEE80211_OFDM_RATE_12MB;
-                       break;
-               case 0xE:
-                       rate = IEEE80211_OFDM_RATE_18MB;
-                       break;
-               case 0x9:
-                       rate = IEEE80211_OFDM_RATE_24MB;
-                       break;
-               case 0xD:
-                       rate = IEEE80211_OFDM_RATE_36MB;
-                       break;
-               case 0x8:
-                       rate = IEEE80211_OFDM_RATE_48MB;
-                       break;
-               case 0xC:
-                       rate = IEEE80211_OFDM_RATE_54MB;
-                       break;
-               default:
-                       rate = 0;
-                       assert(0);
-               }
-       } else {
-               switch (plcp->raw[0]) {
-               case 0x0A:
-                       rate = IEEE80211_CCK_RATE_1MB;
-                       break;
-               case 0x14:
-                       rate = IEEE80211_CCK_RATE_2MB;
-                       break;
-               case 0x37:
-                       rate = IEEE80211_CCK_RATE_5MB;
-                       break;
-               case 0x6E:
-                       rate = IEEE80211_CCK_RATE_11MB;
-                       break;
-               default:
-                       rate = 0;
-                       assert(0);
-               }
-       }
-
-       return rate;
-}
-
-static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
-{
-       switch (bitrate) {
-       case IEEE80211_CCK_RATE_1MB:
-               return 0x0A;
-       case IEEE80211_CCK_RATE_2MB:
-               return 0x14;
-       case IEEE80211_CCK_RATE_5MB:
-               return 0x37;
-       case IEEE80211_CCK_RATE_11MB:
-               return 0x6E;
-       }
-       assert(0);
-       return 0;
-}
-
-static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
-{
-       switch (bitrate) {
-       case IEEE80211_OFDM_RATE_6MB:
-               return 0xB;
-       case IEEE80211_OFDM_RATE_9MB:
-               return 0xF;
-       case IEEE80211_OFDM_RATE_12MB:
-               return 0xA;
-       case IEEE80211_OFDM_RATE_18MB:
-               return 0xE;
-       case IEEE80211_OFDM_RATE_24MB:
-               return 0x9;
-       case IEEE80211_OFDM_RATE_36MB:
-               return 0xD;
-       case IEEE80211_OFDM_RATE_48MB:
-               return 0x8;
-       case IEEE80211_OFDM_RATE_54MB:
-               return 0xC;
-       }
-       assert(0);
-       return 0;
-}
-
-static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
-                                     u16 octets, const u8 bitrate,
-                                     const int ofdm_modulation)
-{
-       __le32 *data = &(plcp->data);
-       __u8 *raw = plcp->raw;
-
-       /* Account for hardware-appended FCS. */
-       octets += IEEE80211_FCS_LEN;
-
-       if (ofdm_modulation) {
-               *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
-               assert(!(octets & 0xF000));
-               *data |= (octets << 5);
-               *data = cpu_to_le32(*data);
-       } else {
-               u32 plen;
-
-               plen = octets * 16 / bitrate;
-               if ((octets * 16 % bitrate) > 0) {
-                       plen++;
-                       if ((bitrate == IEEE80211_CCK_RATE_11MB)
-                           && ((octets * 8 % 11) < 4)) {
-                               raw[1] = 0x84;
-                       } else
-                               raw[1] = 0x04;
-               } else
-                       raw[1] = 0x04;
-               *data |= cpu_to_le32(plen << 16);
-               raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
-       }
-
-//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP");
-}
-
-void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
-                           struct bcm43xx_txhdr *txhdr,
-                           const unsigned char *fragment_data,
-                           unsigned int fragment_len,
-                           const int is_first_fragment,
-                           const u16 cookie)
-{
-       const struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
-       const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data;
-       const struct ieee80211_security *secinfo = &bcm->ieee->sec;
-       u8 bitrate;
-       int ofdm_modulation;
-       u8 fallback_bitrate;
-       int fallback_ofdm_modulation;
-       u16 tmp;
-       u16 encrypt_frame;
-
-       /* Now construct the TX header. */
-       memset(txhdr, 0, sizeof(*txhdr));
-
-       //TODO: Some RTS/CTS stuff has to be done.
-       //TODO: Encryption stuff.
-       //TODO: others?
-
-       bitrate = bcm->softmac->txrates.default_rate;
-       ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
-       fallback_bitrate = bcm->softmac->txrates.default_fallback;
-       fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
-
-       /* Set Frame Control from 80211 header. */
-       txhdr->frame_control = wireless_header->frame_ctl;
-       /* Copy address1 from 80211 header. */
-       memcpy(txhdr->mac1, wireless_header->addr1, 6);
-       /* Set the fallback duration ID. */
-       //FIXME: We use the original durid for now.
-       txhdr->fallback_dur_id = wireless_header->duration_id;
-
-       /* Set the cookie (used as driver internal ID for the frame) */
-       txhdr->cookie = cpu_to_le16(cookie);
-
-       encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
-       if (encrypt_frame && !bcm->ieee->host_encrypt) {
-               const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
-               if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) {
-                       dprintkl(KERN_ERR PFX "invalid packet with PROTECTED"
-                                             "flag set discarded");
-                       return;
-               }
-               memcpy(txhdr->wep_iv, hdr->payload, 4);
-               /* Hardware appends ICV. */
-               fragment_len += 4;
-       }
-
-       /* Generate the PLCP header and the fallback PLCP header. */
-       bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
-                                 fragment_len,
-                                 bitrate, ofdm_modulation);
-       bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len,
-                                 fallback_bitrate, fallback_ofdm_modulation);
-
-       /* Set the CONTROL field */
-       tmp = 0;
-       if (ofdm_modulation)
-               tmp |= BCM43xx_TXHDRCTL_OFDM;
-       if (bcm->short_preamble) //FIXME: could be the other way around, please test
-               tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
-       tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
-               & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
-       txhdr->control = cpu_to_le16(tmp);
-
-       /* Set the FLAGS field */
-       tmp = 0;
-       if (!is_multicast_ether_addr(wireless_header->addr1) &&
-           !is_broadcast_ether_addr(wireless_header->addr1))
-               tmp |= BCM43xx_TXHDRFLAG_EXPECTACK;
-       if (1 /* FIXME: PS poll?? */)
-               tmp |= 0x10; // FIXME: unknown meaning.
-       if (fallback_ofdm_modulation)
-               tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
-       if (is_first_fragment)
-               tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
-       txhdr->flags = cpu_to_le16(tmp);
-
-       /* Set WSEC/RATE field */
-       if (encrypt_frame && !bcm->ieee->host_encrypt) {
-               tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
-                      & BCM43xx_TXHDR_WSEC_ALGO_MASK;
-               tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
-                       & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
-               txhdr->wsec_rate = cpu_to_le16(tmp);
-       }
-
-//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header");
-}
-
 static
 void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
                           u16 offset,
@@ -3773,207 +3546,6 @@ err_pci_disable:
        goto out;
 }
 
-static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
-                                  u8 in_rssi, int ofdm,
-                                  int adjust_2053, int adjust_2050)
-{
-       s32 tmp;
-
-       switch (bcm->current_core->radio->version) {
-       case 0x2050:
-               if (ofdm) {
-                       tmp = in_rssi;
-                       if (tmp > 127)
-                               tmp -= 256;
-                       tmp *= 73;
-                       tmp /= 64;
-                       if (adjust_2050)
-                               tmp += 25;
-                       else
-                               tmp -= 3;
-               } else {
-                       if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
-                               if (in_rssi > 63)
-                                       in_rssi = 63;
-                               tmp = bcm->current_core->radio->nrssi_lt[in_rssi];
-                               tmp = 31 - tmp;
-                               tmp *= -131;
-                               tmp /= 128;
-                               tmp -= 57;
-                       } else {
-                               tmp = in_rssi;
-                               tmp = 31 - tmp;
-                               tmp *= -149;
-                               tmp /= 128;
-                               tmp -= 68;
-                       }
-                       if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
-                           adjust_2050)
-                               tmp += 25;
-               }
-               break;
-       case 0x2060:
-               if (in_rssi > 127)
-                       tmp = in_rssi - 256;
-               else
-                       tmp = in_rssi;
-               break;
-       default:
-               tmp = in_rssi;
-               tmp -= 11;
-               tmp *= 103;
-               tmp /= 64;
-               if (adjust_2053)
-                       tmp -= 109;
-               else
-                       tmp -= 83;
-       }
-
-       return (s8)tmp;
-}
-
-static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
-                                       u8 in_rssi)
-{
-       s8 ret;
-
-       if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
-               //TODO: Incomplete specs.
-               ret = 0;
-       } else
-               ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
-
-       return ret;
-}
-
-static inline
-int bcm43xx_rx_packet(struct bcm43xx_private *bcm,
-                     struct sk_buff *skb,
-                     struct ieee80211_rx_stats *stats)
-{
-       int err;
-
-       err = ieee80211_rx(bcm->ieee, skb, stats);
-       if (unlikely(err == 0))
-               return -EINVAL;
-       return 0;
-}
-
-int bcm43xx_rx(struct bcm43xx_private *bcm,
-              struct sk_buff *skb,
-              struct bcm43xx_rxhdr *rxhdr)
-{
-       struct bcm43xx_plcp_hdr4 *plcp;
-       struct ieee80211_rx_stats stats;
-       struct ieee80211_hdr_4addr *wlhdr;
-       u16 frame_ctl;
-       int is_packet_for_us = 0;
-       int err = -EINVAL;
-       const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
-       const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
-       const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
-       const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
-
-       if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
-               plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
-               /* Skip two unknown bytes and the PLCP header. */
-               skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
-       } else {
-               plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
-               /* Skip the PLCP header. */
-               skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
-       }
-       /* The SKB contains the PAYLOAD (wireless header + data)
-        * at this point. The FCS at the end is stripped.
-        */
-
-       memset(&stats, 0, sizeof(stats));
-       stats.mac_time = le16_to_cpu(rxhdr->mactime);
-       stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
-                                             !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
-                                             !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
-       stats.signal = rxhdr->signal_quality;   //FIXME
-//TODO stats.noise = 
-       stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm);
-//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
-       stats.received_channel = bcm->current_core->radio->channel;
-//TODO stats.control = 
-       stats.mask = IEEE80211_STATMASK_SIGNAL |
-//TODO              IEEE80211_STATMASK_NOISE |
-                    IEEE80211_STATMASK_RATE |
-                    IEEE80211_STATMASK_RSSI;
-       if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
-               stats.freq = IEEE80211_52GHZ_BAND;
-       else
-               stats.freq = IEEE80211_24GHZ_BAND;
-       stats.len = skb->len;
-
-       bcm->stats.last_rx = jiffies;
-       if (bcm->ieee->iw_mode == IW_MODE_MONITOR)
-               return bcm43xx_rx_packet(bcm, skb, &stats);
-
-       wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
-
-       switch (bcm->ieee->iw_mode) {
-       case IW_MODE_ADHOC:
-               if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
-                   memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
-                   is_broadcast_ether_addr(wlhdr->addr1) ||
-                   is_multicast_ether_addr(wlhdr->addr1) ||
-                   bcm->net_dev->flags & IFF_PROMISC)
-                       is_packet_for_us = 1;
-               break;
-       case IW_MODE_INFRA:
-       default:
-               /* When receiving multicast or broadcast packets, filter out
-                  the packets we send ourself; we shouldn't see those */
-               if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
-                   memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
-                   (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
-                    (is_broadcast_ether_addr(wlhdr->addr1) ||
-                     is_multicast_ether_addr(wlhdr->addr1) ||
-                     bcm->net_dev->flags & IFF_PROMISC)))
-                       is_packet_for_us = 1;
-               break;
-       }
-
-       frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
-       if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
-               frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
-               wlhdr->frame_ctl = cpu_to_le16(frame_ctl);              
-               /* trim IV and ICV */
-               /* FIXME: this must be done only for WEP encrypted packets */
-               if (skb->len < 32) {
-                       dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
-                                             "set and length < 32)\n");
-                       return -EINVAL;
-               } else {                
-                       memmove(skb->data + 4, skb->data, 24);
-                       skb_pull(skb, 4);
-                       skb_trim(skb, skb->len - 4);
-                       stats.len -= 8;
-               }
-               wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
-       }
-       
-       switch (WLAN_FC_GET_TYPE(frame_ctl)) {
-       case IEEE80211_FTYPE_MGMT:
-               ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
-               break;
-       case IEEE80211_FTYPE_DATA:
-               if (is_packet_for_us)
-                       err = bcm43xx_rx_packet(bcm, skb, &stats);
-               break;
-       case IEEE80211_FTYPE_CTL:
-               break;
-       default:
-               assert(0);
-               return -EINVAL;
-       }
-
-       return err;
-}
-
 /* Do the Hardware IO operations to send the txb */
 static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
                             struct ieee80211_txb *txb)
index d460393ed343538d1696f1dfdbcda73a2e0f0592..086136c3d01f53f5d31f3bb943ec5c7676c2381d 100644 (file)
@@ -52,134 +52,12 @@ static inline void e_aton(char *str, char *dest)
 }
 #endif
 
-
-#define _bcm43xx_declare_plcp_hdr(size) \
-       struct bcm43xx_plcp_hdr##size {         \
-               union {                         \
-                       __le32 data;            \
-                       __u8 raw[size];         \
-               } __attribute__((__packed__));  \
-       } __attribute__((__packed__))
-
-/* struct bcm43xx_plcp_hdr4 */
-_bcm43xx_declare_plcp_hdr(4);
-/* struct bcm430c_plcp_hdr6 */
-_bcm43xx_declare_plcp_hdr(6);
-
-#undef _bcm43xx_declare_plcp_hdr
-
-
 #define P4D_BYT3S(magic, nr_bytes)     u8 __p4dding##magic[nr_bytes]
 #define P4D_BYTES(line, nr_bytes)      P4D_BYT3S(line, nr_bytes)
 /* Magic helper macro to pad structures. Ignore those above. It's magic. */
 #define PAD_BYTES(nr_bytes)            P4D_BYTES( __LINE__ , (nr_bytes))
 
 
-/* Device specific TX header. To be prepended to TX frames. */
-struct bcm43xx_txhdr {
-       union {
-               struct {
-                       u16 flags;
-                       u16 wsec_rate;
-                       u16 frame_control;
-                       u16 unknown_zeroed_0;
-                       u16 control;
-                       unsigned char wep_iv[10];
-                       unsigned char unknown_wsec_tkip_data[3]; //FIXME
-                       PAD_BYTES(3);
-                       unsigned char mac1[6];
-                       u16 unknown_zeroed_1;
-                       struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
-                       u16 rts_cts_dur_fallback;
-                       struct bcm43xx_plcp_hdr4 fallback_plcp;
-                       u16 fallback_dur_id;
-                       PAD_BYTES(2);
-                       u16 cookie;
-                       u16 unknown_scb_stuff; //FIXME
-                       struct bcm43xx_plcp_hdr6 rts_cts_plcp;
-                       u16 rts_cts_frame_type;
-                       u16 rts_cts_dur;
-                       unsigned char rts_cts_mac1[6];
-                       unsigned char rts_cts_mac2[6];
-                       PAD_BYTES(2);
-                       struct bcm43xx_plcp_hdr6 plcp;
-               } __attribute__((__packed__));
-
-               unsigned char raw[82];
-       } __attribute__((__packed__));
-} __attribute__((__packed__));
-
-struct sk_buff;
-
-void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
-                           struct bcm43xx_txhdr *txhdr,
-                           const unsigned char *fragment_data,
-                           const unsigned int fragment_len,
-                           const int is_first_fragment,
-                           const u16 cookie);
-
-/* RX header as received from the hardware. */
-struct bcm43xx_rxhdr {
-       /* Frame Length. Must be generated explicitely in PIO mode. */
-       __le16 frame_length;
-       PAD_BYTES(2);
-       /* Flags field 1 */
-       __le16 flags1;
-       u8 rssi;
-       u8 signal_quality;
-       PAD_BYTES(2);
-       /* Flags field 3 */
-       __le16 flags3;
-       /* Flags field 2 */
-       __le16 flags2;
-       /* Lower 16bits of the TSF at the time the frame started. */
-       __le16 mactime;
-       PAD_BYTES(14);
-} __attribute__((__packed__));
-
-#define BCM43xx_RXHDR_FLAGS1_OFDM              (1 << 0)
-/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL???       (1 << 3) FIXME */
-#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE     (1 << 7)
-#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ       (1 << 14)
-
-#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME      (1 << 0)
-#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME                (1 << 2)
-/*FIXME: WEP related flags */
-
-#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ       (1 << 10)
-
-/* Transmit Status as received from the hardware. */
-struct bcm43xx_hwxmitstatus {
-       PAD_BYTES(4);
-       __le16 cookie;
-       u8 flags;
-       u8 cnt1:4,
-          cnt2:4;
-       PAD_BYTES(2);
-       __le16 seq;
-       __le16 unknown; //FIXME
-} __attribute__((__packed__));
-
-/* Transmit Status in CPU byteorder. */
-struct bcm43xx_xmitstatus {
-       u16 cookie;
-       u8 flags;
-       u8 cnt1:4,
-          cnt2:4;
-       u16 seq;
-       u16 unknown; //FIXME
-};
-
-#define BCM43xx_TXSTAT_FLAG_ACK                0x01
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
-#define BCM43xx_TXSTAT_FLAG_IGNORE     0x20
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
-
-
 /* Lightweight function to convert a frequency (in Mhz) to a channel number. */
 static inline
 u8 bcm43xx_freq_to_channel_a(int freq)
@@ -259,10 +137,6 @@ int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
 void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
 
-int bcm43xx_rx(struct bcm43xx_private *bcm,
-              struct sk_buff *skb,
-              struct bcm43xx_rxhdr *rxhdr);
-
 void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
                        int iw_mode);
 
@@ -283,11 +157,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
 
 void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
 
-int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val);
-int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val);
-int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val);
-int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val);
-
 void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
 
index 0bf4b3e26f9dbf68486e52750b18ee15e0ebaf23..7b45fa1314c1c97c81180981415ac024e95edffc 100644 (file)
@@ -26,6 +26,7 @@
 #include "bcm43xx.h"
 #include "bcm43xx_pio.h"
 #include "bcm43xx_main.h"
+#include "bcm43xx_xmit.h"
 
 #include <linux/delay.h>
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
new file mode 100644 (file)
index 0000000..5ee572e
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Transmission (TX/RX) related functions.
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx_xmit.h"
+
+#include <linux/etherdevice.h>
+
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
+{
+       switch (plcp->raw[0]) {
+       case 0x0A:
+               return IEEE80211_CCK_RATE_1MB;
+       case 0x14:
+               return IEEE80211_CCK_RATE_2MB;
+       case 0x37:
+               return IEEE80211_CCK_RATE_5MB;
+       case 0x6E:
+               return IEEE80211_CCK_RATE_11MB;
+       }
+       assert(0);
+       return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
+{
+       switch (plcp->raw[0] & 0xF) {
+       case 0xB:
+               return IEEE80211_OFDM_RATE_6MB;
+       case 0xF:
+               return IEEE80211_OFDM_RATE_9MB;
+       case 0xA:
+               return IEEE80211_OFDM_RATE_12MB;
+       case 0xE:
+               return IEEE80211_OFDM_RATE_18MB;
+       case 0x9:
+               return IEEE80211_OFDM_RATE_24MB;
+       case 0xD:
+               return IEEE80211_OFDM_RATE_36MB;
+       case 0x8:
+               return IEEE80211_OFDM_RATE_48MB;
+       case 0xC:
+               return IEEE80211_OFDM_RATE_54MB;
+       }
+       assert(0);
+       return 0;
+}
+
+u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
+{
+       switch (bitrate) {
+       case IEEE80211_CCK_RATE_1MB:
+               return 0x0A;
+       case IEEE80211_CCK_RATE_2MB:
+               return 0x14;
+       case IEEE80211_CCK_RATE_5MB:
+               return 0x37;
+       case IEEE80211_CCK_RATE_11MB:
+               return 0x6E;
+       }
+       assert(0);
+       return 0;
+}
+
+u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+       switch (bitrate) {
+       case IEEE80211_OFDM_RATE_6MB:
+               return 0xB;
+       case IEEE80211_OFDM_RATE_9MB:
+               return 0xF;
+       case IEEE80211_OFDM_RATE_12MB:
+               return 0xA;
+       case IEEE80211_OFDM_RATE_18MB:
+               return 0xE;
+       case IEEE80211_OFDM_RATE_24MB:
+               return 0x9;
+       case IEEE80211_OFDM_RATE_36MB:
+               return 0xD;
+       case IEEE80211_OFDM_RATE_48MB:
+               return 0x8;
+       case IEEE80211_OFDM_RATE_54MB:
+               return 0xC;
+       }
+       assert(0);
+       return 0;
+}
+
+static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
+                                     const u16 octets, const u8 bitrate,
+                                     const int ofdm_modulation)
+{
+       __le32 *data = &(plcp->data);
+       __u8 *raw = plcp->raw;
+
+       if (ofdm_modulation) {
+               *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
+               assert(!(octets & 0xF000));
+               *data |= (octets << 5);
+               *data = cpu_to_le32(*data);
+       } else {
+               u32 plen;
+
+               plen = octets * 16 / bitrate;
+               if ((octets * 16 % bitrate) > 0) {
+                       plen++;
+                       if ((bitrate == IEEE80211_CCK_RATE_11MB)
+                           && ((octets * 8 % 11) < 4)) {
+                               raw[1] = 0x84;
+                       } else
+                               raw[1] = 0x04;
+               } else
+                       raw[1] = 0x04;
+               *data |= cpu_to_le32(plen << 16);
+               raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
+       }
+}
+
+static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
+{
+       switch (bitrate) {
+       case IEEE80211_CCK_RATE_1MB:
+               return IEEE80211_CCK_RATE_1MB;
+       case IEEE80211_CCK_RATE_2MB:
+               return IEEE80211_CCK_RATE_1MB;
+       case IEEE80211_CCK_RATE_5MB:
+               return IEEE80211_CCK_RATE_2MB;
+       case IEEE80211_CCK_RATE_11MB:
+               return IEEE80211_CCK_RATE_5MB;
+       case IEEE80211_OFDM_RATE_6MB:
+               return IEEE80211_CCK_RATE_5MB;
+       case IEEE80211_OFDM_RATE_9MB:
+               return IEEE80211_OFDM_RATE_6MB;
+       case IEEE80211_OFDM_RATE_12MB:
+               return IEEE80211_OFDM_RATE_9MB;
+       case IEEE80211_OFDM_RATE_18MB:
+               return IEEE80211_OFDM_RATE_12MB;
+       case IEEE80211_OFDM_RATE_24MB:
+               return IEEE80211_OFDM_RATE_18MB;
+       case IEEE80211_OFDM_RATE_36MB:
+               return IEEE80211_OFDM_RATE_24MB;
+       case IEEE80211_OFDM_RATE_48MB:
+               return IEEE80211_OFDM_RATE_36MB;
+       case IEEE80211_OFDM_RATE_54MB:
+               return IEEE80211_OFDM_RATE_48MB;
+       }
+       assert(0);
+       return 0;
+}
+
+static
+__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
+                               u8 bitrate)
+{
+       const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
+       __le16 duration_id = wireless_header->duration_id;
+
+       switch (WLAN_FC_GET_TYPE(frame_ctl)) {
+       case IEEE80211_FTYPE_DATA:
+       case IEEE80211_FTYPE_MGMT:
+               //TODO: Steal the code from ieee80211, once it is completed there.
+               break;
+       case IEEE80211_FTYPE_CTL:
+               /* Use the original duration/id. */
+               break;
+       default:
+               assert(0);
+       }
+
+       return duration_id;
+}
+
+static inline
+u16 ceiling_div(u16 dividend, u16 divisor)
+{
+       return ((dividend + divisor - 1) / divisor);
+}
+
+static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
+                                struct bcm43xx_txhdr *txhdr,
+                                u16 *flags,
+                                u8 bitrate,
+                                const struct ieee80211_hdr_4addr *wlhdr)
+{
+       u16 fctl;
+       u16 dur;
+       u8 fallback_bitrate;
+       int ofdm_modulation;
+       int fallback_ofdm_modulation;
+       u8 *sa, *da;
+       u16 flen;
+
+//FIXME        sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
+//FIXME        da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
+       fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
+       ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
+       fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
+
+       flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
+       bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
+                                 flen, bitrate,
+                                 !ieee80211_is_cck_rate(bitrate));
+       bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
+                                 flen, fallback_bitrate,
+                                 !ieee80211_is_cck_rate(fallback_bitrate));
+       fctl = IEEE80211_FTYPE_CTL;
+       fctl |= IEEE80211_STYPE_RTS;
+       dur = le16_to_cpu(wlhdr->duration_id);
+/*FIXME: should we test for dur==0 here and let it unmodified in this case?
+ *       The following assert checks for this case...
+ */
+assert(dur);
+/*FIXME: The duration calculation is not really correct.
+ *       I am not 100% sure which bitrate to use. We use the RTS rate here,
+ *       but this is likely to be wrong.
+ */
+       if (phy->type == BCM43xx_PHYTYPE_A) {
+               /* Three times SIFS */
+               dur += 16 * 3;
+               /* Add ACK duration. */
+               dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
+                                  bitrate * 4);
+               /* Add CTS duration. */
+               dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
+                                  bitrate * 4);
+       } else {
+               /* Three times SIFS */
+               dur += 10 * 3;
+               /* Add ACK duration. */
+               dur += ceiling_div(8 * (14 /*bytes*/) * 10,
+                                  bitrate);
+               /* Add CTS duration. */
+               dur += ceiling_div(8 * (14 /*bytes*/) * 10,
+                                  bitrate);
+       }
+
+       txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
+       txhdr->rts_cts_dur = cpu_to_le16(dur);
+//printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
+//printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
+       memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
+       memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
+
+       *flags |= BCM43xx_TXHDRFLAG_RTSCTS;
+       *flags |= BCM43xx_TXHDRFLAG_RTS;
+       if (ofdm_modulation)
+               *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
+       if (fallback_ofdm_modulation)
+               *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
+}
+                                
+void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
+                           struct bcm43xx_txhdr *txhdr,
+                           const unsigned char *fragment_data,
+                           const unsigned int fragment_len,
+                           const int is_first_fragment,
+                           const u16 cookie)
+{
+       const struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
+       const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
+       const struct ieee80211_security *secinfo = &bcm->ieee->sec;
+       u8 bitrate;
+       u8 fallback_bitrate;
+       int ofdm_modulation;
+       int fallback_ofdm_modulation;
+       u16 plcp_fragment_len = fragment_len;
+       u16 flags = 0;
+       u16 control = 0;
+       u16 wsec_rate = 0;
+       u16 encrypt_frame;
+
+       /* Now construct the TX header. */
+       memset(txhdr, 0, sizeof(*txhdr));
+
+       bitrate = bcm->softmac->txrates.default_rate;
+       ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
+       fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
+       fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
+
+       /* Set Frame Control from 80211 header. */
+       txhdr->frame_control = wireless_header->frame_ctl;
+       /* Copy address1 from 80211 header. */
+       memcpy(txhdr->mac1, wireless_header->addr1, 6);
+       /* Set the fallback duration ID. */
+       txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
+                                                         fallback_bitrate);
+       /* Set the cookie (used as driver internal ID for the frame) */
+       txhdr->cookie = cpu_to_le16(cookie);
+
+       /* Hardware appends FCS. */
+       plcp_fragment_len += IEEE80211_FCS_LEN;
+
+       /* Hardware encryption. */
+       encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
+       if (encrypt_frame && !bcm->ieee->host_encrypt) {
+               const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
+               memcpy(txhdr->wep_iv, hdr->payload, 4);
+               /* Hardware appends ICV. */
+               plcp_fragment_len += 4;
+
+               wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
+                            & BCM43xx_TXHDR_WSEC_ALGO_MASK;
+               wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
+                            & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
+       }
+
+       /* Generate the PLCP header and the fallback PLCP header. */
+       bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
+                                 plcp_fragment_len,
+                                 bitrate, ofdm_modulation);
+       bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
+                                 fallback_bitrate, fallback_ofdm_modulation);
+
+       /* Set the CONTROL field */
+       if (ofdm_modulation)
+               control |= BCM43xx_TXHDRCTL_OFDM;
+       if (bcm->short_preamble) //FIXME: could be the other way around, please test
+               control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
+       control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
+                  & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
+
+       /* Set the FLAGS field */
+       if (!is_multicast_ether_addr(wireless_header->addr1) &&
+           !is_broadcast_ether_addr(wireless_header->addr1))
+               flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
+       if (1 /* FIXME: PS poll?? */)
+               flags |= 0x10; // FIXME: unknown meaning.
+       if (fallback_ofdm_modulation)
+               flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
+       if (is_first_fragment)
+               flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
+
+       /* Set WSEC/RATE field */
+       wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
+                    & BCM43xx_TXHDR_RATE_MASK;
+
+       /* Generate the RTS/CTS packet, if required. */
+       /* FIXME: We should first try with CTS-to-self,
+        *        if we are on 80211g. If we get too many
+        *        failures (hidden nodes), we should switch back to RTS/CTS.
+        */
+       if (0/*FIXME txctl->use_rts_cts*/) {
+               bcm43xx_generate_rts(phy, txhdr, &flags,
+                                    0/*FIXME txctl->rts_cts_rate*/,
+                                    wireless_header);
+       }
+
+       txhdr->flags = cpu_to_le16(flags);
+       txhdr->control = cpu_to_le16(control);
+       txhdr->wsec_rate = cpu_to_le16(wsec_rate);
+}
+
+static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
+                                  u8 in_rssi, int ofdm,
+                                  int adjust_2053, int adjust_2050)
+{
+       struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
+       struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
+       s32 tmp;
+
+       switch (radio->version) {
+       case 0x2050:
+               if (ofdm) {
+                       tmp = in_rssi;
+                       if (tmp > 127)
+                               tmp -= 256;
+                       tmp *= 73;
+                       tmp /= 64;
+                       if (adjust_2050)
+                               tmp += 25;
+                       else
+                               tmp -= 3;
+               } else {
+                       if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+                               if (in_rssi > 63)
+                                       in_rssi = 63;
+                               tmp = radio->nrssi_lt[in_rssi];
+                               tmp = 31 - tmp;
+                               tmp *= -131;
+                               tmp /= 128;
+                               tmp -= 57;
+                       } else {
+                               tmp = in_rssi;
+                               tmp = 31 - tmp;
+                               tmp *= -149;
+                               tmp /= 128;
+                               tmp -= 68;
+                       }
+                       if (phy->type == BCM43xx_PHYTYPE_G &&
+                           adjust_2050)
+                               tmp += 25;
+               }
+               break;
+       case 0x2060:
+               if (in_rssi > 127)
+                       tmp = in_rssi - 256;
+               else
+                       tmp = in_rssi;
+               break;
+       default:
+               tmp = in_rssi;
+               tmp -= 11;
+               tmp *= 103;
+               tmp /= 64;
+               if (adjust_2053)
+                       tmp -= 109;
+               else
+                       tmp -= 83;
+       }
+
+       return (s8)tmp;
+}
+
+static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
+                                       u8 in_rssi)
+{
+       struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
+       s8 ret;
+
+       if (phy->type == BCM43xx_PHYTYPE_A) {
+               //TODO: Incomplete specs.
+               ret = 0;
+       } else
+               ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
+
+       return ret;
+}
+
+int bcm43xx_rx(struct bcm43xx_private *bcm,
+              struct sk_buff *skb,
+              struct bcm43xx_rxhdr *rxhdr)
+{
+       struct bcm43xx_plcp_hdr4 *plcp;
+       struct ieee80211_rx_stats stats;
+       struct ieee80211_hdr_4addr *wlhdr;
+       u16 frame_ctl;
+       int is_packet_for_us = 0;
+       int err = -EINVAL;
+       const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
+       const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
+       const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
+       const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
+
+       if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
+               plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
+               /* Skip two unknown bytes and the PLCP header. */
+               skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
+       } else {
+               plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
+               /* Skip the PLCP header. */
+               skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
+       }
+       /* The SKB contains the PAYLOAD (wireless header + data)
+        * at this point. The FCS at the end is stripped.
+        */
+
+       memset(&stats, 0, sizeof(stats));
+       stats.mac_time = le16_to_cpu(rxhdr->mactime);
+       stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+                                             !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
+                                             !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
+       stats.signal = rxhdr->signal_quality;   //FIXME
+//TODO stats.noise = 
+       if (is_ofdm)
+               stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
+       else
+               stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
+//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
+       stats.received_channel = bcm->current_core->radio->channel;
+//TODO stats.control = 
+       stats.mask = IEEE80211_STATMASK_SIGNAL |
+//TODO              IEEE80211_STATMASK_NOISE |
+                    IEEE80211_STATMASK_RATE |
+                    IEEE80211_STATMASK_RSSI;
+       if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
+               stats.freq = IEEE80211_52GHZ_BAND;
+       else
+               stats.freq = IEEE80211_24GHZ_BAND;
+       stats.len = skb->len;
+
+       bcm->stats.last_rx = jiffies;
+       if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
+               err = ieee80211_rx(bcm->ieee, skb, &stats);
+               return (err == 0) ? -EINVAL : 0;
+       }
+
+       wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
+
+       switch (bcm->ieee->iw_mode) {
+       case IW_MODE_ADHOC:
+               if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
+                   memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
+                   is_broadcast_ether_addr(wlhdr->addr1) ||
+                   is_multicast_ether_addr(wlhdr->addr1) ||
+                   bcm->net_dev->flags & IFF_PROMISC)
+                       is_packet_for_us = 1;
+               break;
+       case IW_MODE_INFRA:
+       default:
+               /* When receiving multicast or broadcast packets, filter out
+                  the packets we send ourself; we shouldn't see those */
+               if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
+                   memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
+                   (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
+                    (is_broadcast_ether_addr(wlhdr->addr1) ||
+                     is_multicast_ether_addr(wlhdr->addr1) ||
+                     bcm->net_dev->flags & IFF_PROMISC)))
+                       is_packet_for_us = 1;
+               break;
+       }
+
+       frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
+       if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
+               frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
+               wlhdr->frame_ctl = cpu_to_le16(frame_ctl);              
+               /* trim IV and ICV */
+               /* FIXME: this must be done only for WEP encrypted packets */
+               if (skb->len < 32) {
+                       dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
+                                             "set and length < 32)\n");
+                       return -EINVAL;
+               } else {                
+                       memmove(skb->data + 4, skb->data, 24);
+                       skb_pull(skb, 4);
+                       skb_trim(skb, skb->len - 4);
+                       stats.len -= 8;
+               }
+               wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
+       }
+       
+       switch (WLAN_FC_GET_TYPE(frame_ctl)) {
+       case IEEE80211_FTYPE_MGMT:
+               ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
+               break;
+       case IEEE80211_FTYPE_DATA:
+               if (is_packet_for_us) {
+                       err = ieee80211_rx(bcm->ieee, skb, &stats);
+                       err = (err == 0) ? -EINVAL : 0;
+               }
+               break;
+       case IEEE80211_FTYPE_CTL:
+               break;
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
new file mode 100644 (file)
index 0000000..2aed19e
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef BCM43xx_XMIT_H_
+#define BCM43xx_XMIT_H_
+
+#include "bcm43xx_main.h"
+
+
+#define _bcm43xx_declare_plcp_hdr(size) \
+       struct bcm43xx_plcp_hdr##size {         \
+               union {                         \
+                       __le32 data;            \
+                       __u8 raw[size];         \
+               } __attribute__((__packed__));  \
+       } __attribute__((__packed__))
+
+/* struct bcm43xx_plcp_hdr4 */
+_bcm43xx_declare_plcp_hdr(4);
+/* struct bcm43xx_plcp_hdr6 */
+_bcm43xx_declare_plcp_hdr(6);
+
+#undef _bcm43xx_declare_plcp_hdr
+
+/* Device specific TX header. To be prepended to TX frames. */
+struct bcm43xx_txhdr {
+       union {
+               struct {
+                       __le16 flags;
+                       __le16 wsec_rate;
+                       __le16 frame_control;
+                       u16 unknown_zeroed_0;
+                       __le16 control;
+                       u8 wep_iv[10];
+                       u8 unknown_wsec_tkip_data[3]; //FIXME
+                       PAD_BYTES(3);
+                       u8 mac1[6];
+                       u16 unknown_zeroed_1;
+                       struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
+                       __le16 rts_cts_dur_fallback;
+                       struct bcm43xx_plcp_hdr4 fallback_plcp;
+                       __le16 fallback_dur_id;
+                       PAD_BYTES(2);
+                       __le16 cookie;
+                       __le16 unknown_scb_stuff; //FIXME
+                       struct bcm43xx_plcp_hdr6 rts_cts_plcp;
+                       __le16 rts_cts_frame_control;
+                       __le16 rts_cts_dur;
+                       u8 rts_cts_mac1[6];
+                       u8 rts_cts_mac2[6];
+                       PAD_BYTES(2);
+                       struct bcm43xx_plcp_hdr6 plcp;
+               } __attribute__((__packed__));
+               u8 raw[82];
+       } __attribute__((__packed__));
+} __attribute__((__packed__));
+
+/* Values/Masks for the device TX header */
+#define BCM43xx_TXHDRFLAG_EXPECTACK            0x0001
+#define BCM43xx_TXHDRFLAG_RTSCTS               0x0002
+#define BCM43xx_TXHDRFLAG_RTS                  0x0004
+#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT                0x0008
+#define BCM43xx_TXHDRFLAG_DESTPSMODE           0x0020
+#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM          0x0080
+#define BCM43xx_TXHDRFLAG_FALLBACKOFDM         0x0100
+#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM  0x0200
+#define BCM43xx_TXHDRFLAG_CTS                  0x0400
+#define BCM43xx_TXHDRFLAG_FRAMEBURST           0x0800
+
+#define BCM43xx_TXHDRCTL_OFDM                  0x0001
+#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE                0x0010
+#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK       0x0030
+#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT      8
+
+#define BCM43xx_TXHDR_RATE_MASK                        0x0F00
+#define BCM43xx_TXHDR_RATE_SHIFT               8
+#define BCM43xx_TXHDR_RTSRATE_MASK             0xF000
+#define BCM43xx_TXHDR_RTSRATE_SHIFT            12
+#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK       0x00F0
+#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT      4
+#define BCM43xx_TXHDR_WSEC_ALGO_MASK           0x0003
+#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT          0
+
+void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
+                           struct bcm43xx_txhdr *txhdr,
+                           const unsigned char *fragment_data,
+                           const unsigned int fragment_len,
+                           const int is_first_fragment,
+                           const u16 cookie);
+
+/* RX header as received from the hardware. */
+struct bcm43xx_rxhdr {
+       /* Frame Length. Must be generated explicitely in PIO mode. */
+       __le16 frame_length;
+       PAD_BYTES(2);
+       /* Flags field 1 */
+       __le16 flags1;
+       u8 rssi;
+       u8 signal_quality;
+       PAD_BYTES(2);
+       /* Flags field 3 */
+       __le16 flags3;
+       /* Flags field 2 */
+       __le16 flags2;
+       /* Lower 16bits of the TSF at the time the frame started. */
+       __le16 mactime;
+       PAD_BYTES(14);
+} __attribute__((__packed__));
+
+#define BCM43xx_RXHDR_FLAGS1_OFDM              (1 << 0)
+/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL???       (1 << 3) FIXME */
+#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE     (1 << 7)
+#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ       (1 << 14)
+
+#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME      (1 << 0)
+#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME                (1 << 2)
+/*FIXME: WEP related flags */
+
+#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ       (1 << 10)
+
+/* Transmit Status as received from the hardware. */
+struct bcm43xx_hwxmitstatus {
+       PAD_BYTES(4);
+       __le16 cookie;
+       u8 flags;
+       u8 cnt1:4,
+          cnt2:4;
+       PAD_BYTES(2);
+       __le16 seq;
+       __le16 unknown; //FIXME
+} __attribute__((__packed__));
+
+/* Transmit Status in CPU byteorder. */
+struct bcm43xx_xmitstatus {
+       u16 cookie;
+       u8 flags;
+       u8 cnt1:4,
+          cnt2:4;
+       u16 seq;
+       u16 unknown; //FIXME
+};
+
+#define BCM43xx_TXSTAT_FLAG_ACK                0x01
+//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
+//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
+//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
+//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
+#define BCM43xx_TXSTAT_FLAG_IGNORE     0x20
+//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
+//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
+
+u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate);
+u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+int bcm43xx_rx(struct bcm43xx_private *bcm,
+              struct sk_buff *skb,
+              struct bcm43xx_rxhdr *rxhdr);
+
+#endif /* BCM43xx_XMIT_H_ */