aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorUlrich Kunitz <kune@deine-taler.de>2006-09-12 21:42:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-09-25 16:52:17 -0400
commit583afd1e4f25c87000c85ad7d03f5299fd4155dc (patch)
treee5ceeee697091a1b9a654ae3e6411cd4674a47c2 /drivers/net
parentbc5f06a8aaa29a79c9da2cedb5b9779b8081289c (diff)
[PATCH] zd1211rw: Add LED support
This patch includes a big cleanup of the existing unused LED code, and adds support for controlling the LED. The link LED will blink if the device is not associated. The LED switches between 2 seconds on and 1 second off. If the device is associated the LED is switched on. The link LED also indicates packet TX. I do a little bit more led resetting than the vendor driver, but the device works now as expected for single LED and double LED devices. Signed-off-by: Ulrich Kunitz <kune@deine-taler.de> Signed-off-by: Daniel Drake <dsd@gentoo.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c117
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h23
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c50
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h5
4 files changed, 117 insertions, 78 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index c213a2e56e55..aa661b2b76c7 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -325,13 +325,22 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type)
325 chip->patch_cr157 = (value >> 13) & 0x1; 325 chip->patch_cr157 = (value >> 13) & 0x1;
326 chip->patch_6m_band_edge = (value >> 21) & 0x1; 326 chip->patch_6m_band_edge = (value >> 21) & 0x1;
327 chip->new_phy_layout = (value >> 31) & 0x1; 327 chip->new_phy_layout = (value >> 31) & 0x1;
328 chip->link_led = ((value >> 4) & 1) ? LED1 : LED2;
329 chip->supports_tx_led = 1;
330 if (value & (1 << 24)) { /* LED scenario */
331 if (value & (1 << 29))
332 chip->supports_tx_led = 0;
333 }
328 334
329 dev_dbg_f(zd_chip_dev(chip), 335 dev_dbg_f(zd_chip_dev(chip),
330 "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d " 336 "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
331 "patch 6M %d new PHY %d\n", 337 "patch 6M %d new PHY %d link LED%d tx led %d\n",
332 zd_rf_name(*rf_type), *rf_type, 338 zd_rf_name(*rf_type), *rf_type,
333 chip->pa_type, chip->patch_cck_gain, 339 chip->pa_type, chip->patch_cck_gain,
334 chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout); 340 chip->patch_cr157, chip->patch_6m_band_edge,
341 chip->new_phy_layout,
342 chip->link_led == LED1 ? 1 : 2,
343 chip->supports_tx_led);
335 return 0; 344 return 0;
336error: 345error:
337 *rf_type = 0; 346 *rf_type = 0;
@@ -1289,89 +1298,60 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
1289 return channel; 1298 return channel;
1290} 1299}
1291 1300
1292static u16 led_mask(int led) 1301int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
1293{
1294 switch (led) {
1295 case 1:
1296 return LED1;
1297 case 2:
1298 return LED2;
1299 default:
1300 return 0;
1301 }
1302}
1303
1304static int read_led_reg(struct zd_chip *chip, u16 *status)
1305{
1306 ZD_ASSERT(mutex_is_locked(&chip->mutex));
1307 return zd_ioread16_locked(chip, status, CR_LED);
1308}
1309
1310static int write_led_reg(struct zd_chip *chip, u16 status)
1311{ 1302{
1312 ZD_ASSERT(mutex_is_locked(&chip->mutex)); 1303 static const zd_addr_t a[] = {
1313 return zd_iowrite16_locked(chip, status, CR_LED); 1304 FW_LINK_STATUS,
1314} 1305 CR_LED,
1306 };
1315 1307
1316int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status) 1308 int r;
1317{ 1309 u16 v[ARRAY_SIZE(a)];
1318 int r, ret; 1310 struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
1319 u16 mask = led_mask(led); 1311 [0] = { FW_LINK_STATUS },
1320 u16 reg; 1312 [1] = { CR_LED },
1313 };
1314 u16 other_led;
1321 1315
1322 if (!mask)
1323 return -EINVAL;
1324 mutex_lock(&chip->mutex); 1316 mutex_lock(&chip->mutex);
1325 r = read_led_reg(chip, &reg); 1317 r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a));
1326 if (r) 1318 if (r)
1327 return r; 1319 goto out;
1320
1321 other_led = chip->link_led == LED1 ? LED2 : LED1;
1322
1328 switch (status) { 1323 switch (status) {
1329 case LED_STATUS:
1330 return (reg & mask) ? LED_ON : LED_OFF;
1331 case LED_OFF: 1324 case LED_OFF:
1332 reg &= ~mask; 1325 ioreqs[0].value = FW_LINK_OFF;
1333 ret = LED_OFF; 1326 ioreqs[1].value = v[1] & ~(LED1|LED2);
1334 break; 1327 break;
1335 case LED_FLIP: 1328 case LED_SCANNING:
1336 reg ^= mask; 1329 ioreqs[0].value = FW_LINK_OFF;
1337 ret = (reg&mask) ? LED_ON : LED_OFF; 1330 ioreqs[1].value = v[1] & ~other_led;
1331 if (get_seconds() % 3 == 0) {
1332 ioreqs[1].value &= ~chip->link_led;
1333 } else {
1334 ioreqs[1].value |= chip->link_led;
1335 }
1338 break; 1336 break;
1339 case LED_ON: 1337 case LED_ASSOCIATED:
1340 reg |= mask; 1338 ioreqs[0].value = FW_LINK_TX;
1341 ret = LED_ON; 1339 ioreqs[1].value = v[1] & ~other_led;
1340 ioreqs[1].value |= chip->link_led;
1342 break; 1341 break;
1343 default: 1342 default:
1344 return -EINVAL; 1343 r = -EINVAL;
1345 }
1346 r = write_led_reg(chip, reg);
1347 if (r) {
1348 ret = r;
1349 goto out; 1344 goto out;
1350 } 1345 }
1351out:
1352 mutex_unlock(&chip->mutex);
1353 return r;
1354}
1355 1346
1356int zd_chip_led_flip(struct zd_chip *chip, int led, 1347 if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) {
1357 const unsigned int *phases_msecs, unsigned int count) 1348 r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
1358{ 1349 if (r)
1359 int i, r;
1360 enum led_status status;
1361
1362 r = zd_chip_led_status(chip, led, LED_STATUS);
1363 if (r)
1364 return r;
1365 status = r;
1366 for (i = 0; i < count; i++) {
1367 r = zd_chip_led_status(chip, led, LED_FLIP);
1368 if (r < 0)
1369 goto out; 1350 goto out;
1370 msleep(phases_msecs[i]);
1371 } 1351 }
1372 1352 r = 0;
1373out: 1353out:
1374 zd_chip_led_status(chip, led, status); 1354 mutex_unlock(&chip->mutex);
1375 return r; 1355 return r;
1376} 1356}
1377 1357
@@ -1673,4 +1653,3 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip,
1673 1653
1674 return 0; 1654 return 0;
1675} 1655}
1676
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 4b1250859897..ae59597ce4e1 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -428,6 +428,7 @@
428/* masks for controlling LEDs */ 428/* masks for controlling LEDs */
429#define LED1 0x0100 429#define LED1 0x0100
430#define LED2 0x0200 430#define LED2 0x0200
431#define LED_SW 0x0400
431 432
432/* Seems to indicate that the configuration is over. 433/* Seems to indicate that the configuration is over.
433 */ 434 */
@@ -629,6 +630,10 @@
629#define FW_SOFT_RESET FW_REG(4) 630#define FW_SOFT_RESET FW_REG(4)
630#define FW_FLASH_CHK FW_REG(5) 631#define FW_FLASH_CHK FW_REG(5)
631 632
633#define FW_LINK_OFF 0x0
634#define FW_LINK_TX 0x1
635/* 0x2 - link led on? */
636
632enum { 637enum {
633 CR_BASE_OFFSET = 0x9000, 638 CR_BASE_OFFSET = 0x9000,
634 FW_START_OFFSET = 0xee00, 639 FW_START_OFFSET = 0xee00,
@@ -663,8 +668,11 @@ struct zd_chip {
663 u8 pwr_int_values[E2P_CHANNEL_COUNT]; 668 u8 pwr_int_values[E2P_CHANNEL_COUNT];
664 /* SetPointOFDM in the vendor driver */ 669 /* SetPointOFDM in the vendor driver */
665 u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT]; 670 u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
666 u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, 671 u16 link_led;
667 new_phy_layout:1, is_zd1211b:1; 672 unsigned int pa_type:4,
673 patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
674 new_phy_layout:1,
675 is_zd1211b:1, supports_tx_led:1;
668}; 676};
669 677
670static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) 678static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@@ -812,15 +820,12 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip);
812int zd_chip_unlock_phy_regs(struct zd_chip *chip); 820int zd_chip_unlock_phy_regs(struct zd_chip *chip);
813 821
814enum led_status { 822enum led_status {
815 LED_OFF = 0, 823 LED_OFF = 0,
816 LED_ON = 1, 824 LED_SCANNING = 1,
817 LED_FLIP = 2, 825 LED_ASSOCIATED = 2,
818 LED_STATUS = 3,
819}; 826};
820 827
821int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status); 828int zd_chip_control_leds(struct zd_chip *chip, enum led_status status);
822int zd_chip_led_flip(struct zd_chip *chip, int led,
823 const unsigned int *phases_msecs, unsigned int count);
824 829
825int zd_set_beacon_interval(struct zd_chip *chip, u32 interval); 830int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
826 831
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 1989f1c05fbe..2d12837052b0 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -33,6 +33,10 @@
33static void ieee_init(struct ieee80211_device *ieee); 33static void ieee_init(struct ieee80211_device *ieee);
34static void softmac_init(struct ieee80211softmac_device *sm); 34static void softmac_init(struct ieee80211softmac_device *sm);
35 35
36static void housekeeping_init(struct zd_mac *mac);
37static void housekeeping_enable(struct zd_mac *mac);
38static void housekeeping_disable(struct zd_mac *mac);
39
36int zd_mac_init(struct zd_mac *mac, 40int zd_mac_init(struct zd_mac *mac,
37 struct net_device *netdev, 41 struct net_device *netdev,
38 struct usb_interface *intf) 42 struct usb_interface *intf)
@@ -46,6 +50,7 @@ int zd_mac_init(struct zd_mac *mac,
46 ieee_init(ieee); 50 ieee_init(ieee);
47 softmac_init(ieee80211_priv(netdev)); 51 softmac_init(ieee80211_priv(netdev));
48 zd_chip_init(&mac->chip, netdev, intf); 52 zd_chip_init(&mac->chip, netdev, intf);
53 housekeeping_init(mac);
49 return 0; 54 return 0;
50} 55}
51 56
@@ -178,6 +183,7 @@ int zd_mac_open(struct net_device *netdev)
178 if (r < 0) 183 if (r < 0)
179 goto disable_rx; 184 goto disable_rx;
180 185
186 housekeeping_enable(mac);
181 ieee80211softmac_start(netdev); 187 ieee80211softmac_start(netdev);
182 return 0; 188 return 0;
183disable_rx: 189disable_rx:
@@ -204,6 +210,7 @@ int zd_mac_stop(struct net_device *netdev)
204 */ 210 */
205 211
206 zd_chip_disable_rx(chip); 212 zd_chip_disable_rx(chip);
213 housekeeping_disable(mac);
207 ieee80211softmac_stop(netdev); 214 ieee80211softmac_stop(netdev);
208 215
209 zd_chip_disable_hwint(chip); 216 zd_chip_disable_hwint(chip);
@@ -1080,3 +1087,46 @@ void zd_dump_rx_status(const struct rx_status *status)
1080 } 1087 }
1081} 1088}
1082#endif /* DEBUG */ 1089#endif /* DEBUG */
1090
1091#define LINK_LED_WORK_DELAY HZ
1092
1093static void link_led_handler(void *p)
1094{
1095 struct zd_mac *mac = p;
1096 struct zd_chip *chip = &mac->chip;
1097 struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
1098 int is_associated;
1099 int r;
1100
1101 spin_lock_irq(&mac->lock);
1102 is_associated = sm->associated != 0;
1103 spin_unlock_irq(&mac->lock);
1104
1105 r = zd_chip_control_leds(chip,
1106 is_associated ? LED_ASSOCIATED : LED_SCANNING);
1107 if (r)
1108 dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
1109
1110 queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
1111 LINK_LED_WORK_DELAY);
1112}
1113
1114static void housekeeping_init(struct zd_mac *mac)
1115{
1116 INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
1117}
1118
1119static void housekeeping_enable(struct zd_mac *mac)
1120{
1121 dev_dbg_f(zd_mac_dev(mac), "\n");
1122 queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
1123 0);
1124}
1125
1126static void housekeeping_disable(struct zd_mac *mac)
1127{
1128 dev_dbg_f(zd_mac_dev(mac), "\n");
1129 cancel_rearming_delayed_workqueue(zd_workqueue,
1130 &mac->housekeeping.link_led_work);
1131 zd_chip_control_leds(&mac->chip, LED_OFF);
1132}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 29b51fd7d4e5..b8ea3de7924a 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -120,6 +120,10 @@ enum mac_flags {
120 MAC_FIXED_CHANNEL = 0x01, 120 MAC_FIXED_CHANNEL = 0x01,
121}; 121};
122 122
123struct housekeeping {
124 struct work_struct link_led_work;
125};
126
123#define ZD_MAC_STATS_BUFFER_SIZE 16 127#define ZD_MAC_STATS_BUFFER_SIZE 16
124 128
125struct zd_mac { 129struct zd_mac {
@@ -128,6 +132,7 @@ struct zd_mac {
128 struct net_device *netdev; 132 struct net_device *netdev;
129 /* Unlocked reading possible */ 133 /* Unlocked reading possible */
130 struct iw_statistics iw_stats; 134 struct iw_statistics iw_stats;
135 struct housekeeping housekeeping;
131 unsigned int stats_count; 136 unsigned int stats_count;
132 u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; 137 u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
133 u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; 138 u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];