aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/zd1211rw/zd_mac.c
diff options
context:
space:
mode:
authorLuis Carlos Cobo <luisca@cozybit.com>2008-03-03 15:32:15 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 17:19:47 -0500
commit72e77a8a7921d952bdef2468d9315616eca6b464 (patch)
tree752dfd038edb0a76257eda3b7e04db74ecfe1a7e /drivers/net/wireless/zd1211rw/zd_mac.c
parentf137e05468f2a648aba11377dc824d788683dff4 (diff)
zd1211rw: support for mesh interface and beaconing
The previously unused CR_CAM_MODE register is set to MODE_AP_WDS. This makes the driver ack mesh (WDS) frames. It does not affect Infra functionality of the driver. Previously missing beaconing support has been added. This might also help implement a currently missing ah-hoc mode. Support for interrupts from the device have been added, but we are not handling most of them. Mesh interfaces are considered associated as long as the interface is up. Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_mac.c')
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c75
1 files changed, 73 insertions, 2 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index f90f03f676de..69c45ca99051 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -475,6 +475,46 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
475 /* FIXME: Management frame? */ 475 /* FIXME: Management frame? */
476} 476}
477 477
478void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
479{
480 struct zd_mac *mac = zd_hw_mac(hw);
481 u32 tmp, j = 0;
482 /* 4 more bytes for tail CRC */
483 u32 full_len = beacon->len + 4;
484 zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
485 zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
486 while (tmp & 0x2) {
487 zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
488 if ((++j % 100) == 0) {
489 printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n");
490 if (j >= 500) {
491 printk(KERN_ERR "Giving up beacon config.\n");
492 return;
493 }
494 }
495 msleep(1);
496 }
497
498 zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1);
499 if (zd_chip_is_zd1211b(&mac->chip))
500 zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
501
502 for (j = 0 ; j < beacon->len; j++)
503 zd_iowrite32(&mac->chip, CR_BCN_FIFO,
504 *((u8 *)(beacon->data + j)));
505
506 for (j = 0; j < 4; j++)
507 zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
508
509 zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
510 /* 802.11b/g 2.4G CCK 1Mb
511 * 802.11a, not yet implemented, uses different values (see GPL vendor
512 * driver)
513 */
514 zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
515 (full_len << 19));
516}
517
478static int fill_ctrlset(struct zd_mac *mac, 518static int fill_ctrlset(struct zd_mac *mac,
479 struct sk_buff *skb, 519 struct sk_buff *skb,
480 struct ieee80211_tx_control *control) 520 struct ieee80211_tx_control *control)
@@ -709,6 +749,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
709 749
710 switch (conf->type) { 750 switch (conf->type) {
711 case IEEE80211_IF_TYPE_MNTR: 751 case IEEE80211_IF_TYPE_MNTR:
752 case IEEE80211_IF_TYPE_MESH_POINT:
712 case IEEE80211_IF_TYPE_STA: 753 case IEEE80211_IF_TYPE_STA:
713 mac->type = conf->type; 754 mac->type = conf->type;
714 break; 755 break;
@@ -738,15 +779,43 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
738 struct ieee80211_if_conf *conf) 779 struct ieee80211_if_conf *conf)
739{ 780{
740 struct zd_mac *mac = zd_hw_mac(hw); 781 struct zd_mac *mac = zd_hw_mac(hw);
782 int associated;
783
784 if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) {
785 associated = true;
786 if (conf->beacon) {
787 zd_mac_config_beacon(hw, conf->beacon);
788 kfree_skb(conf->beacon);
789 zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
790 hw->conf.beacon_int);
791 }
792 } else
793 associated = is_valid_ether_addr(conf->bssid);
741 794
742 spin_lock_irq(&mac->lock); 795 spin_lock_irq(&mac->lock);
743 mac->associated = is_valid_ether_addr(conf->bssid); 796 mac->associated = associated;
744 spin_unlock_irq(&mac->lock); 797 spin_unlock_irq(&mac->lock);
745 798
746 /* TODO: do hardware bssid filtering */ 799 /* TODO: do hardware bssid filtering */
747 return 0; 800 return 0;
748} 801}
749 802
803void zd_process_intr(struct work_struct *work)
804{
805 u16 int_status;
806 struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
807
808 int_status = le16_to_cpu(*(u16 *)(mac->intr_buffer+4));
809 if (int_status & INT_CFG_NEXT_BCN) {
810 if (net_ratelimit())
811 dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
812 } else
813 dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
814
815 zd_chip_enable_hwint(&mac->chip);
816}
817
818
750static void set_multicast_hash_handler(struct work_struct *work) 819static void set_multicast_hash_handler(struct work_struct *work)
751{ 820{
752 struct zd_mac *mac = 821 struct zd_mac *mac =
@@ -912,7 +981,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
912 981
913 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; 982 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
914 983
915 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; 984 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
985 IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
916 hw->max_rssi = 100; 986 hw->max_rssi = 100;
917 hw->max_signal = 100; 987 hw->max_signal = 100;
918 988
@@ -926,6 +996,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
926 INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); 996 INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
927 INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); 997 INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
928 INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); 998 INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler);
999 INIT_WORK(&mac->process_intr, zd_process_intr);
929 1000
930 SET_IEEE80211_DEV(hw, &intf->dev); 1001 SET_IEEE80211_DEV(hw, &intf->dev);
931 return hw; 1002 return hw;