diff options
author | Ulrich Kunitz <kune@deine-taler.de> | 2006-09-12 21:42:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-09-25 16:52:17 -0400 |
commit | 583afd1e4f25c87000c85ad7d03f5299fd4155dc (patch) | |
tree | e5ceeee697091a1b9a654ae3e6411cd4674a47c2 | |
parent | bc5f06a8aaa29a79c9da2cedb5b9779b8081289c (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>
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.c | 117 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.h | 23 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 50 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.h | 5 |
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; |
336 | error: | 345 | error: |
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 | ||
1292 | static u16 led_mask(int led) | 1301 | int 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 | |||
1304 | static 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 | |||
1310 | static 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 | ||
1316 | int 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, ®); | 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 | } |
1351 | out: | ||
1352 | mutex_unlock(&chip->mutex); | ||
1353 | return r; | ||
1354 | } | ||
1355 | 1346 | ||
1356 | int 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; | |
1373 | out: | 1353 | out: |
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 | |||
632 | enum { | 637 | enum { |
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 | ||
670 | static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) | 678 | static 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); | |||
812 | int zd_chip_unlock_phy_regs(struct zd_chip *chip); | 820 | int zd_chip_unlock_phy_regs(struct zd_chip *chip); |
813 | 821 | ||
814 | enum led_status { | 822 | enum 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 | ||
821 | int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status); | 828 | int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); |
822 | int zd_chip_led_flip(struct zd_chip *chip, int led, | ||
823 | const unsigned int *phases_msecs, unsigned int count); | ||
824 | 829 | ||
825 | int zd_set_beacon_interval(struct zd_chip *chip, u32 interval); | 830 | int 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 @@ | |||
33 | static void ieee_init(struct ieee80211_device *ieee); | 33 | static void ieee_init(struct ieee80211_device *ieee); |
34 | static void softmac_init(struct ieee80211softmac_device *sm); | 34 | static void softmac_init(struct ieee80211softmac_device *sm); |
35 | 35 | ||
36 | static void housekeeping_init(struct zd_mac *mac); | ||
37 | static void housekeeping_enable(struct zd_mac *mac); | ||
38 | static void housekeeping_disable(struct zd_mac *mac); | ||
39 | |||
36 | int zd_mac_init(struct zd_mac *mac, | 40 | int 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; |
183 | disable_rx: | 189 | disable_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 | |||
1093 | static 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 | |||
1114 | static void housekeeping_init(struct zd_mac *mac) | ||
1115 | { | ||
1116 | INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac); | ||
1117 | } | ||
1118 | |||
1119 | static 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 | |||
1126 | static 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 | ||
123 | struct 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 | ||
125 | struct zd_mac { | 129 | struct 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]; |