diff options
-rw-r--r-- | drivers/net/wireless/p54/p54.h | 25 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 124 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.h | 7 |
3 files changed, 143 insertions, 13 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 071cbe965377..2dda5fe418b6 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h | |||
@@ -14,6 +14,10 @@ | |||
14 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #ifdef CONFIG_MAC80211_LEDS | ||
18 | #include <linux/leds.h> | ||
19 | #endif /* CONFIG_MAC80211_LEDS */ | ||
20 | |||
17 | enum p54_control_frame_types { | 21 | enum p54_control_frame_types { |
18 | P54_CONTROL_TYPE_SETUP = 0, | 22 | P54_CONTROL_TYPE_SETUP = 0, |
19 | P54_CONTROL_TYPE_SCAN, | 23 | P54_CONTROL_TYPE_SCAN, |
@@ -112,6 +116,21 @@ enum fw_state { | |||
112 | FW_STATE_RESETTING, | 116 | FW_STATE_RESETTING, |
113 | }; | 117 | }; |
114 | 118 | ||
119 | #ifdef CONFIG_MAC80211_LEDS | ||
120 | |||
121 | #define P54_LED_MAX_NAME_LEN 31 | ||
122 | |||
123 | struct p54_led_dev { | ||
124 | struct ieee80211_hw *hw_dev; | ||
125 | struct led_classdev led_dev; | ||
126 | char name[P54_LED_MAX_NAME_LEN + 1]; | ||
127 | |||
128 | unsigned int index; | ||
129 | unsigned int registered; | ||
130 | }; | ||
131 | |||
132 | #endif /* CONFIG_MAC80211_LEDS */ | ||
133 | |||
115 | struct p54_common { | 134 | struct p54_common { |
116 | struct ieee80211_hw *hw; | 135 | struct ieee80211_hw *hw; |
117 | u32 rx_start; | 136 | u32 rx_start; |
@@ -157,6 +176,12 @@ struct p54_common { | |||
157 | struct completion eeprom_comp; | 176 | struct completion eeprom_comp; |
158 | u8 privacy_caps; | 177 | u8 privacy_caps; |
159 | u8 rx_keycache_size; | 178 | u8 rx_keycache_size; |
179 | /* LED management */ | ||
180 | #ifdef CONFIG_MAC80211_LEDS | ||
181 | struct p54_led_dev assoc_led; | ||
182 | struct p54_led_dev tx_led; | ||
183 | #endif /* CONFIG_MAC80211_LEDS */ | ||
184 | u16 softled_state; /* bit field of glowing LEDs */ | ||
160 | }; | 185 | }; |
161 | 186 | ||
162 | int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); | 187 | int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); |
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index f76365057172..93abe49f4bde 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
22 | 22 | ||
23 | #include <net/mac80211.h> | 23 | #include <net/mac80211.h> |
24 | #ifdef CONFIG_MAC80211_LEDS | ||
25 | #include <linux/leds.h> | ||
26 | #endif /* CONFIG_MAC80211_LEDS */ | ||
24 | 27 | ||
25 | #include "p54.h" | 28 | #include "p54.h" |
26 | #include "p54common.h" | 29 | #include "p54common.h" |
@@ -1871,7 +1874,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) | |||
1871 | return -EINVAL; | 1874 | return -EINVAL; |
1872 | } | 1875 | } |
1873 | 1876 | ||
1874 | static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) | 1877 | static int p54_set_leds(struct ieee80211_hw *dev) |
1875 | { | 1878 | { |
1876 | struct p54_common *priv = dev->priv; | 1879 | struct p54_common *priv = dev->priv; |
1877 | struct sk_buff *skb; | 1880 | struct sk_buff *skb; |
@@ -1882,11 +1885,11 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) | |||
1882 | if (!skb) | 1885 | if (!skb) |
1883 | return -ENOMEM; | 1886 | return -ENOMEM; |
1884 | 1887 | ||
1885 | led = (struct p54_led *)skb_put(skb, sizeof(*led)); | 1888 | led = (struct p54_led *) skb_put(skb, sizeof(*led)); |
1886 | led->mode = cpu_to_le16(mode); | 1889 | led->flags = cpu_to_le16(0x0003); |
1887 | led->led_permanent = cpu_to_le16(link); | 1890 | led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); |
1888 | led->led_temporary = cpu_to_le16(act); | 1891 | led->delay[0] = cpu_to_le16(1); |
1889 | led->duration = cpu_to_le16(1000); | 1892 | led->delay[1] = cpu_to_le16(0); |
1890 | priv->tx(dev, skb); | 1893 | priv->tx(dev, skb); |
1891 | return 0; | 1894 | return 0; |
1892 | } | 1895 | } |
@@ -2070,6 +2073,9 @@ static int p54_start(struct ieee80211_hw *dev) | |||
2070 | 2073 | ||
2071 | queue_delayed_work(dev->workqueue, &priv->work, 0); | 2074 | queue_delayed_work(dev->workqueue, &priv->work, 0); |
2072 | 2075 | ||
2076 | priv->softled_state = 0; | ||
2077 | err = p54_set_leds(dev); | ||
2078 | |||
2073 | out: | 2079 | out: |
2074 | mutex_unlock(&priv->conf_mutex); | 2080 | mutex_unlock(&priv->conf_mutex); |
2075 | return err; | 2081 | return err; |
@@ -2082,6 +2088,9 @@ static void p54_stop(struct ieee80211_hw *dev) | |||
2082 | 2088 | ||
2083 | mutex_lock(&priv->conf_mutex); | 2089 | mutex_lock(&priv->conf_mutex); |
2084 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | 2090 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; |
2091 | priv->softled_state = 0; | ||
2092 | p54_set_leds(dev); | ||
2093 | |||
2085 | cancel_delayed_work_sync(&priv->work); | 2094 | cancel_delayed_work_sync(&priv->work); |
2086 | if (priv->cached_beacon) | 2095 | if (priv->cached_beacon) |
2087 | p54_tx_cancel(dev, priv->cached_beacon); | 2096 | p54_tx_cancel(dev, priv->cached_beacon); |
@@ -2119,7 +2128,6 @@ static int p54_add_interface(struct ieee80211_hw *dev, | |||
2119 | 2128 | ||
2120 | memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); | 2129 | memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); |
2121 | p54_setup_mac(dev); | 2130 | p54_setup_mac(dev); |
2122 | p54_set_leds(dev, 1, 0, 0); | ||
2123 | mutex_unlock(&priv->conf_mutex); | 2131 | mutex_unlock(&priv->conf_mutex); |
2124 | return 0; | 2132 | return 0; |
2125 | } | 2133 | } |
@@ -2199,8 +2207,6 @@ static int p54_config_interface(struct ieee80211_hw *dev, | |||
2199 | goto out; | 2207 | goto out; |
2200 | } | 2208 | } |
2201 | 2209 | ||
2202 | ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0); | ||
2203 | |||
2204 | out: | 2210 | out: |
2205 | mutex_unlock(&priv->conf_mutex); | 2211 | mutex_unlock(&priv->conf_mutex); |
2206 | return ret; | 2212 | return ret; |
@@ -2419,6 +2425,96 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | |||
2419 | return 0; | 2425 | return 0; |
2420 | } | 2426 | } |
2421 | 2427 | ||
2428 | #ifdef CONFIG_MAC80211_LEDS | ||
2429 | static void p54_led_brightness_set(struct led_classdev *led_dev, | ||
2430 | enum led_brightness brightness) | ||
2431 | { | ||
2432 | struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev, | ||
2433 | led_dev); | ||
2434 | struct ieee80211_hw *dev = led->hw_dev; | ||
2435 | struct p54_common *priv = dev->priv; | ||
2436 | int err; | ||
2437 | |||
2438 | /* Don't toggle the LED, when the device is down. */ | ||
2439 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
2440 | return ; | ||
2441 | |||
2442 | if (brightness != LED_OFF) | ||
2443 | priv->softled_state |= BIT(led->index); | ||
2444 | else | ||
2445 | priv->softled_state &= ~BIT(led->index); | ||
2446 | |||
2447 | err = p54_set_leds(dev); | ||
2448 | if (err && net_ratelimit()) | ||
2449 | printk(KERN_ERR "%s: failed to update %s LED.\n", | ||
2450 | wiphy_name(dev->wiphy), led_dev->name); | ||
2451 | } | ||
2452 | |||
2453 | static int p54_register_led(struct ieee80211_hw *dev, | ||
2454 | struct p54_led_dev *led, | ||
2455 | unsigned int led_index, | ||
2456 | char *name, char *trigger) | ||
2457 | { | ||
2458 | int err; | ||
2459 | |||
2460 | if (led->registered) | ||
2461 | return -EEXIST; | ||
2462 | |||
2463 | snprintf(led->name, sizeof(led->name), "p54-%s::%s", | ||
2464 | wiphy_name(dev->wiphy), name); | ||
2465 | led->hw_dev = dev; | ||
2466 | led->index = led_index; | ||
2467 | led->led_dev.name = led->name; | ||
2468 | led->led_dev.default_trigger = trigger; | ||
2469 | led->led_dev.brightness_set = p54_led_brightness_set; | ||
2470 | |||
2471 | err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev); | ||
2472 | if (err) | ||
2473 | printk(KERN_ERR "%s: Failed to register %s LED.\n", | ||
2474 | wiphy_name(dev->wiphy), name); | ||
2475 | else | ||
2476 | led->registered = 1; | ||
2477 | |||
2478 | return err; | ||
2479 | } | ||
2480 | |||
2481 | static int p54_init_leds(struct ieee80211_hw *dev) | ||
2482 | { | ||
2483 | struct p54_common *priv = dev->priv; | ||
2484 | int err; | ||
2485 | |||
2486 | /* | ||
2487 | * TODO: | ||
2488 | * Figure out if the EEPROM contains some hints about the number | ||
2489 | * of available/programmable LEDs of the device. | ||
2490 | * But for now, we can assume that we have two programmable LEDs. | ||
2491 | */ | ||
2492 | |||
2493 | err = p54_register_led(dev, &priv->assoc_led, 0, "assoc", | ||
2494 | ieee80211_get_assoc_led_name(dev)); | ||
2495 | if (err) | ||
2496 | return err; | ||
2497 | |||
2498 | err = p54_register_led(dev, &priv->tx_led, 1, "tx", | ||
2499 | ieee80211_get_tx_led_name(dev)); | ||
2500 | if (err) | ||
2501 | return err; | ||
2502 | |||
2503 | err = p54_set_leds(dev); | ||
2504 | return err; | ||
2505 | } | ||
2506 | |||
2507 | static void p54_unregister_leds(struct ieee80211_hw *dev) | ||
2508 | { | ||
2509 | struct p54_common *priv = dev->priv; | ||
2510 | |||
2511 | if (priv->tx_led.registered) | ||
2512 | led_classdev_unregister(&priv->tx_led.led_dev); | ||
2513 | if (priv->assoc_led.registered) | ||
2514 | led_classdev_unregister(&priv->assoc_led.led_dev); | ||
2515 | } | ||
2516 | #endif /* CONFIG_MAC80211_LEDS */ | ||
2517 | |||
2422 | static const struct ieee80211_ops p54_ops = { | 2518 | static const struct ieee80211_ops p54_ops = { |
2423 | .tx = p54_tx, | 2519 | .tx = p54_tx, |
2424 | .start = p54_start, | 2520 | .start = p54_start, |
@@ -2499,6 +2595,12 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) | |||
2499 | return err; | 2595 | return err; |
2500 | } | 2596 | } |
2501 | 2597 | ||
2598 | #ifdef CONFIG_MAC80211_LEDS | ||
2599 | err = p54_init_leds(dev); | ||
2600 | if (err) | ||
2601 | return err; | ||
2602 | #endif /* CONFIG_MAC80211_LEDS */ | ||
2603 | |||
2502 | dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); | 2604 | dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); |
2503 | return 0; | 2605 | return 0; |
2504 | } | 2606 | } |
@@ -2510,6 +2612,10 @@ void p54_free_common(struct ieee80211_hw *dev) | |||
2510 | kfree(priv->iq_autocal); | 2612 | kfree(priv->iq_autocal); |
2511 | kfree(priv->output_limit); | 2613 | kfree(priv->output_limit); |
2512 | kfree(priv->curve_data); | 2614 | kfree(priv->curve_data); |
2615 | |||
2616 | #ifdef CONFIG_MAC80211_LEDS | ||
2617 | p54_unregister_leds(dev); | ||
2618 | #endif /* CONFIG_MAC80211_LEDS */ | ||
2513 | } | 2619 | } |
2514 | EXPORT_SYMBOL_GPL(p54_free_common); | 2620 | EXPORT_SYMBOL_GPL(p54_free_common); |
2515 | 2621 | ||
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index def23b1f49ec..75ead7a150fc 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h | |||
@@ -515,10 +515,9 @@ struct p54_scan_tail_rate { | |||
515 | } __attribute__ ((packed)); | 515 | } __attribute__ ((packed)); |
516 | 516 | ||
517 | struct p54_led { | 517 | struct p54_led { |
518 | __le16 mode; | 518 | __le16 flags; |
519 | __le16 led_temporary; | 519 | __le16 mask[2]; |
520 | __le16 led_permanent; | 520 | __le16 delay[2]; |
521 | __le16 duration; | ||
522 | } __attribute__ ((packed)); | 521 | } __attribute__ ((packed)); |
523 | 522 | ||
524 | struct p54_edcf { | 523 | struct p54_edcf { |