diff options
| -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]; |
