aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2009-04-16 20:56:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:57:16 -0400
commita027087a6b4c7d985b872cac3e19ce023670792e (patch)
tree7c2b85a9e417f1ed432332967efb95287d39c458
parent357303e2b61272b191f2e5d782d94fdd8f50fd71 (diff)
rtl8187: Implement TX/RX blink for LED
The following patch implements some control over the LED on RTL8187B and RTL8187L devices. Triggers are registered for TX and RX. Whenever the trigger event occurs, the LED is turned off for 1/20 second, then turned back on. Note: For those RTL8187X devices that are built into the computer and have a LED that is expected to be controlled with a radio switch, this patch will not operate that LED. That will take a separate patch to be prepared later. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Tested-by: Hin-Tak Leung <htl10@users.sourceforge.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/Kconfig7
-rw-r--r--drivers/net/wireless/rtl818x/Makefile2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h7
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c18
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c218
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.h57
6 files changed, 305 insertions, 4 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ad99470ae92d..11c248180982 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -433,6 +433,13 @@ config RTL8187
433 433
434 Thanks to Realtek for their support! 434 Thanks to Realtek for their support!
435 435
436# If possible, automatically enable LEDs for RTL8187.
437
438config RTL8187_LEDS
439 bool
440 depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
441 default y
442
436config ADM8211 443config ADM8211
437 tristate "ADMtek ADM8211 support" 444 tristate "ADMtek ADM8211 support"
438 depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL 445 depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
index c113b3e69046..37e3d4db0c40 100644
--- a/drivers/net/wireless/rtl818x/Makefile
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -1,5 +1,5 @@
1rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o 1rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
2rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o 2rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o
3 3
4obj-$(CONFIG_RTL8180) += rtl8180.o 4obj-$(CONFIG_RTL8180) += rtl8180.o
5obj-$(CONFIG_RTL8187) += rtl8187.o 5obj-$(CONFIG_RTL8187) += rtl8187.o
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 9718f61809cf..622196dc078e 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -16,6 +16,7 @@
16#define RTL8187_H 16#define RTL8187_H
17 17
18#include "rtl818x.h" 18#include "rtl818x.h"
19#include "rtl8187_leds.h"
19 20
20#define RTL8187_EEPROM_TXPWR_BASE 0x05 21#define RTL8187_EEPROM_TXPWR_BASE 0x05
21#define RTL8187_EEPROM_MAC_ADDR 0x07 22#define RTL8187_EEPROM_MAC_ADDR 0x07
@@ -102,6 +103,12 @@ struct rtl8187_priv {
102 struct usb_anchor anchored; 103 struct usb_anchor anchored;
103 struct delayed_work work; 104 struct delayed_work work;
104 struct ieee80211_hw *dev; 105 struct ieee80211_hw *dev;
106#ifdef CONFIG_RTL8187_LEDS
107 struct rtl8187_led led_tx;
108 struct rtl8187_led led_rx;
109 struct delayed_work led_on;
110 struct delayed_work led_off;
111#endif
105 u16 txpwr_base; 112 u16 txpwr_base;
106 u8 asic_rev; 113 u8 asic_rev;
107 u8 is_rtl8187b; 114 u8 is_rtl8187b;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index d6d4001812a7..ac558da92aac 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -29,6 +29,9 @@
29 29
30#include "rtl8187.h" 30#include "rtl8187.h"
31#include "rtl8187_rtl8225.h" 31#include "rtl8187_rtl8225.h"
32#ifdef CONFIG_RTL8187_LEDS
33#include "rtl8187_leds.h"
34#endif
32 35
33MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); 36MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
34MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>"); 37MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@@ -734,10 +737,10 @@ static const u8 rtl8187b_reg_table[][3] = {
734 {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, 737 {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0},
735 {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, 738 {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0},
736 {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, 739 {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0},
737 {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, 740 {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x4C, 0x00, 2},
738 741
739 {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, 742 {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, {0x8E, 0x08, 0},
740 {0x8E, 0x08, 0}, {0x8F, 0x00, 0} 743 {0x8F, 0x00, 0}
741}; 744};
742 745
743static int rtl8187b_init_hw(struct ieee80211_hw *dev) 746static int rtl8187b_init_hw(struct ieee80211_hw *dev)
@@ -1501,6 +1504,12 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
1501 wiphy_name(dev->wiphy), dev->wiphy->perm_addr, 1504 wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
1502 chip_name, priv->asic_rev, priv->rf->name); 1505 chip_name, priv->asic_rev, priv->rf->name);
1503 1506
1507#ifdef CONFIG_RTL8187_LEDS
1508 eeprom_93cx6_read(&eeprom, 0x3F, &reg);
1509 reg &= 0xFF;
1510 rtl8187_leds_init(dev, reg);
1511#endif
1512
1504 return 0; 1513 return 0;
1505 1514
1506 err_free_dev: 1515 err_free_dev:
@@ -1518,6 +1527,9 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
1518 if (!dev) 1527 if (!dev)
1519 return; 1528 return;
1520 1529
1530#ifdef CONFIG_RTL8187_LEDS
1531 rtl8187_leds_exit(dev);
1532#endif
1521 ieee80211_unregister_hw(dev); 1533 ieee80211_unregister_hw(dev);
1522 1534
1523 priv = dev->priv; 1535 priv = dev->priv;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
new file mode 100644
index 000000000000..b44253592243
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -0,0 +1,218 @@
1/*
2 * Linux LED driver for RTL8187
3 *
4 * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
5 *
6 * Based on the LED handling in the r8187 driver, which is:
7 * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
8 *
9 * Thanks to Realtek for their support!
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#ifdef CONFIG_RTL8187_LEDS
17
18#include <net/mac80211.h>
19#include <linux/usb.h>
20#include <linux/eeprom_93cx6.h>
21
22#include "rtl8187.h"
23#include "rtl8187_leds.h"
24
25static void led_turn_on(struct work_struct *work)
26{
27 /* As this routine does read/write operations on the hardware, it must
28 * be run from a work queue.
29 */
30 u8 reg;
31 struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
32 led_on.work);
33 struct rtl8187_led *led = &priv->led_tx;
34
35 /* Don't change the LED, when the device is down. */
36 if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
37 return ;
38
39 /* Skip if the LED is not registered. */
40 if (!led->dev)
41 return;
42 mutex_lock(&priv->conf_mutex);
43 switch (led->ledpin) {
44 case LED_PIN_GPIO0:
45 rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
46 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
47 break;
48 case LED_PIN_LED0:
49 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4);
50 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
51 break;
52 case LED_PIN_LED1:
53 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5);
54 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
55 break;
56 case LED_PIN_HW:
57 default:
58 break;
59 }
60 mutex_unlock(&priv->conf_mutex);
61}
62
63static void led_turn_off(struct work_struct *work)
64{
65 /* As this routine does read/write operations on the hardware, it must
66 * be run from a work queue.
67 */
68 u8 reg;
69 struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
70 led_off.work);
71 struct rtl8187_led *led = &priv->led_tx;
72
73 /* Don't change the LED, when the device is down. */
74 if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
75 return ;
76
77 /* Skip if the LED is not registered. */
78 if (!led->dev)
79 return;
80 mutex_lock(&priv->conf_mutex);
81 switch (led->ledpin) {
82 case LED_PIN_GPIO0:
83 rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
84 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
85 break;
86 case LED_PIN_LED0:
87 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4);
88 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
89 break;
90 case LED_PIN_LED1:
91 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5);
92 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
93 break;
94 case LED_PIN_HW:
95 default:
96 break;
97 }
98 mutex_unlock(&priv->conf_mutex);
99}
100
101/* Callback from the LED subsystem. */
102static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
103 enum led_brightness brightness)
104{
105 struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led,
106 led_dev);
107 struct ieee80211_hw *hw = led->dev;
108 struct rtl8187_priv *priv = hw->priv;
109
110 if (brightness == LED_OFF) {
111 queue_delayed_work(hw->workqueue, &priv->led_off, 0);
112 /* The LED is off for 1/20 sec so that it just blinks. */
113 queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20);
114 } else
115 queue_delayed_work(hw->workqueue, &priv->led_on, 0);
116}
117
118static int rtl8187_register_led(struct ieee80211_hw *dev,
119 struct rtl8187_led *led, const char *name,
120 const char *default_trigger, u8 ledpin)
121{
122 int err;
123 struct rtl8187_priv *priv = dev->priv;
124
125 if (led->dev)
126 return -EEXIST;
127 if (!default_trigger)
128 return -EINVAL;
129 led->dev = dev;
130 led->ledpin = ledpin;
131 strncpy(led->name, name, sizeof(led->name));
132
133 led->led_dev.name = led->name;
134 led->led_dev.default_trigger = default_trigger;
135 led->led_dev.brightness_set = rtl8187_led_brightness_set;
136
137 err = led_classdev_register(&priv->udev->dev, &led->led_dev);
138 if (err) {
139 printk(KERN_INFO "LEDs: Failed to register %s\n", name);
140 led->dev = NULL;
141 return err;
142 }
143 return 0;
144}
145
146static void rtl8187_unregister_led(struct rtl8187_led *led)
147{
148 led_classdev_unregister(&led->led_dev);
149 led->dev = NULL;
150}
151
152void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
153{
154 struct rtl8187_priv *priv = dev->priv;
155 char name[RTL8187_LED_MAX_NAME_LEN + 1];
156 u8 ledpin;
157 int err;
158
159 /* According to the vendor driver, the LED operation depends on the
160 * customer ID encoded in the EEPROM
161 */
162 printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid);
163 switch (custid) {
164 case EEPROM_CID_RSVD0:
165 case EEPROM_CID_RSVD1:
166 case EEPROM_CID_SERCOMM_PS:
167 case EEPROM_CID_QMI:
168 case EEPROM_CID_DELL:
169 case EEPROM_CID_TOSHIBA:
170 ledpin = LED_PIN_GPIO0;
171 break;
172 case EEPROM_CID_ALPHA0:
173 ledpin = LED_PIN_LED0;
174 break;
175 case EEPROM_CID_HW:
176 ledpin = LED_PIN_HW;
177 break;
178 default:
179 ledpin = LED_PIN_GPIO0;
180 }
181
182 INIT_DELAYED_WORK(&priv->led_on, led_turn_on);
183 INIT_DELAYED_WORK(&priv->led_off, led_turn_off);
184
185 snprintf(name, sizeof(name),
186 "rtl8187-%s::tx", wiphy_name(dev->wiphy));
187 err = rtl8187_register_led(dev, &priv->led_tx, name,
188 ieee80211_get_tx_led_name(dev), ledpin);
189 if (err)
190 goto error;
191 snprintf(name, sizeof(name),
192 "rtl8187-%s::rx", wiphy_name(dev->wiphy));
193 err = rtl8187_register_led(dev, &priv->led_rx, name,
194 ieee80211_get_rx_led_name(dev), ledpin);
195 if (!err) {
196 queue_delayed_work(dev->workqueue, &priv->led_on, 0);
197 return;
198 }
199 /* registration of RX LED failed - unregister TX */
200 rtl8187_unregister_led(&priv->led_tx);
201error:
202 /* If registration of either failed, cancel delayed work */
203 cancel_delayed_work_sync(&priv->led_off);
204 cancel_delayed_work_sync(&priv->led_on);
205}
206
207void rtl8187_leds_exit(struct ieee80211_hw *dev)
208{
209 struct rtl8187_priv *priv = dev->priv;
210
211 rtl8187_unregister_led(&priv->led_tx);
212 /* turn the LED off before exiting */
213 queue_delayed_work(dev->workqueue, &priv->led_off, 0);
214 cancel_delayed_work_sync(&priv->led_off);
215 rtl8187_unregister_led(&priv->led_rx);
216}
217#endif /* def CONFIG_RTL8187_LED */
218
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187_leds.h
new file mode 100644
index 000000000000..a0332027aead
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.h
@@ -0,0 +1,57 @@
1/*
2 * Definitions for RTL8187 leds
3 *
4 * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
5 *
6 * Based on the LED handling in the r8187 driver, which is:
7 * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#ifndef RTL8187_LED_H
15#define RTL8187_LED_H
16
17#ifdef CONFIG_RTL8187_LEDS
18
19#define RTL8187_LED_MAX_NAME_LEN 21
20
21#include <linux/leds.h>
22#include <linux/types.h>
23
24enum {
25 LED_PIN_LED0,
26 LED_PIN_LED1,
27 LED_PIN_GPIO0,
28 LED_PIN_HW
29};
30
31enum {
32 EEPROM_CID_RSVD0 = 0x00,
33 EEPROM_CID_RSVD1 = 0xFF,
34 EEPROM_CID_ALPHA0 = 0x01,
35 EEPROM_CID_SERCOMM_PS = 0x02,
36 EEPROM_CID_HW = 0x03,
37 EEPROM_CID_TOSHIBA = 0x04,
38 EEPROM_CID_QMI = 0x07,
39 EEPROM_CID_DELL = 0x08
40};
41
42struct rtl8187_led {
43 struct ieee80211_hw *dev;
44 /* The LED class device */
45 struct led_classdev led_dev;
46 /* The pin/method used to control the led */
47 u8 ledpin;
48 /* The unique name string for this LED device. */
49 char name[RTL8187_LED_MAX_NAME_LEN + 1];
50};
51
52void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code);
53void rtl8187_leds_exit(struct ieee80211_hw *dev);
54
55#endif /* def CONFIG_RTL8187_LED */
56
57#endif /* RTL8187_LED_H */