aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/zd1211rw
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
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')
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h8
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c75
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c11
5 files changed, 94 insertions, 4 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index db96adf90ae2..0acb5c345734 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -809,6 +809,7 @@ static int hw_init_hmac(struct zd_chip *chip)
809 { CR_AFTER_PNP, 0x1 }, 809 { CR_AFTER_PNP, 0x1 },
810 { CR_WEP_PROTECT, 0x114 }, 810 { CR_WEP_PROTECT, 0x114 },
811 { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, 811 { CR_IFS_VALUE, IFS_VALUE_DEFAULT },
812 { CR_CAM_MODE, MODE_AP_WDS},
812 }; 813 };
813 814
814 ZD_ASSERT(mutex_is_locked(&chip->mutex)); 815 ZD_ASSERT(mutex_is_locked(&chip->mutex));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 5b6e3a3751ba..f8c061a9b6ec 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -489,6 +489,7 @@ enum {
489 489
490#define CR_RX_OFFSET CTL_REG(0x065c) 490#define CR_RX_OFFSET CTL_REG(0x065c)
491 491
492#define CR_BCN_LENGTH CTL_REG(0x0664)
492#define CR_PHY_DELAY CTL_REG(0x066C) 493#define CR_PHY_DELAY CTL_REG(0x066C)
493#define CR_BCN_FIFO CTL_REG(0x0670) 494#define CR_BCN_FIFO CTL_REG(0x0670)
494#define CR_SNIFFER_ON CTL_REG(0x0674) 495#define CR_SNIFFER_ON CTL_REG(0x0674)
@@ -545,6 +546,8 @@ enum {
545#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ 546#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \
546 RX_FILTER_CFEND | RX_FILTER_CFACK) 547 RX_FILTER_CFEND | RX_FILTER_CFACK)
547 548
549#define BCN_MODE_IBSS 0x2000000
550
548/* Monitor mode sets filter to 0xfffff */ 551/* Monitor mode sets filter to 0xfffff */
549 552
550#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) 553#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
@@ -578,6 +581,11 @@ enum {
578 581
579/* CAM: Continuous Access Mode (power management) */ 582/* CAM: Continuous Access Mode (power management) */
580#define CR_CAM_MODE CTL_REG(0x0700) 583#define CR_CAM_MODE CTL_REG(0x0700)
584#define MODE_IBSS 0x0
585#define MODE_AP 0x1
586#define MODE_STA 0x2
587#define MODE_AP_WDS 0x3
588
581#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704) 589#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
582#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708) 590#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
583#define CR_CAM_ADDRESS CTL_REG(0x070C) 591#define CR_CAM_ADDRESS CTL_REG(0x070C)
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;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 67dea9739c8f..71170244d2c9 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -172,12 +172,15 @@ struct zd_tx_skb_control_block {
172struct zd_mac { 172struct zd_mac {
173 struct zd_chip chip; 173 struct zd_chip chip;
174 spinlock_t lock; 174 spinlock_t lock;
175 spinlock_t intr_lock;
175 struct ieee80211_hw *hw; 176 struct ieee80211_hw *hw;
176 struct housekeeping housekeeping; 177 struct housekeeping housekeeping;
177 struct work_struct set_multicast_hash_work; 178 struct work_struct set_multicast_hash_work;
178 struct work_struct set_rts_cts_work; 179 struct work_struct set_rts_cts_work;
179 struct work_struct set_rx_filter_work; 180 struct work_struct set_rx_filter_work;
181 struct work_struct process_intr;
180 struct zd_mc_hash multicast_hash; 182 struct zd_mc_hash multicast_hash;
183 u8 intr_buffer[USB_MAX_EP_INT_BUFFER];
181 u8 regdomain; 184 u8 regdomain;
182 u8 default_regdomain; 185 u8 default_regdomain;
183 int type; 186 int type;
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 7942b15acfe7..e34675c2f8fc 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -97,6 +97,7 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
97#define FW_ZD1211B_PREFIX "zd1211/zd1211b_" 97#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
98 98
99/* USB device initialization */ 99/* USB device initialization */
100static void int_urb_complete(struct urb *urb);
100 101
101static int request_fw_file( 102static int request_fw_file(
102 const struct firmware **fw, const char *name, struct device *device) 103 const struct firmware **fw, const char *name, struct device *device)
@@ -336,11 +337,18 @@ static inline void handle_regs_int(struct urb *urb)
336 struct zd_usb *usb = urb->context; 337 struct zd_usb *usb = urb->context;
337 struct zd_usb_interrupt *intr = &usb->intr; 338 struct zd_usb_interrupt *intr = &usb->intr;
338 int len; 339 int len;
340 u16 int_num;
339 341
340 ZD_ASSERT(in_interrupt()); 342 ZD_ASSERT(in_interrupt());
341 spin_lock(&intr->lock); 343 spin_lock(&intr->lock);
342 344
343 if (intr->read_regs_enabled) { 345 int_num = le16_to_cpu(*(u16 *)(urb->transfer_buffer+2));
346 if (int_num == CR_INTERRUPT) {
347 struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context));
348 memcpy(&mac->intr_buffer, urb->transfer_buffer,
349 USB_MAX_EP_INT_BUFFER);
350 schedule_work(&mac->process_intr);
351 } else if (intr->read_regs_enabled) {
344 intr->read_regs.length = len = urb->actual_length; 352 intr->read_regs.length = len = urb->actual_length;
345 353
346 if (len > sizeof(intr->read_regs.buffer)) 354 if (len > sizeof(intr->read_regs.buffer))
@@ -351,7 +359,6 @@ static inline void handle_regs_int(struct urb *urb)
351 goto out; 359 goto out;
352 } 360 }
353 361
354 dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
355out: 362out:
356 spin_unlock(&intr->lock); 363 spin_unlock(&intr->lock);
357} 364}