http://lxr.free-electrons.com/source/include/linux/gpio_keys.h?v=3.2;a=arm
https://www.kernel.org/doc/Documentation/leds/leds-class.txt
这是无线网卡的LED功能的实现思路,最终还是会回到kernel里面的LED处理routine。
/********************************/
/* LED functions */
/********************************/
#ifdef CPTCFG_MAC80211_LEDS
static void ath_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
struct ath_softc *sc = led->sc;
ath9k_ps_wakeup(sc);
ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
(brightness != LED_OFF) ^ led->gpio->active_low);
ath9k_ps_restore(sc);
}
static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
{
const struct gpio_led *gpio = led->gpio;
int ret;
led->cdev.name = gpio->name;
led->cdev.default_trigger = gpio->default_trigger;
led->cdev.brightness_set = ath_led_brightness;
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
if (ret < 0)
return ret;
led->sc = sc;
list_add(&led->list, &sc->leds);
/* Configure gpio for output */
ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off */
ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
return 0;
}
int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
const char *trigger, bool active_low)
{
struct ath_led *led;
struct gpio_led *gpio;
char *_name;
int ret;
led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
GFP_KERNEL);
if (!led)
return -ENOMEM;
led->gpio = gpio = (struct gpio_led *) (led + 1);
_name = (char *) (led->gpio + 1);
strcpy(_name, name);
gpio->name = _name;
gpio->gpio = gpio_num;
gpio->active_low = active_low;
gpio->default_trigger = trigger;
ret = ath_add_led(sc, led);
if (unlikely(ret < 0))
kfree(led);
return ret;
}
static int ath_create_platform_led(struct ath_softc *sc,
const struct gpio_led *gpio)
{
struct ath_led *led;
int ret;
led = kzalloc(sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
led->gpio = gpio;
ret = ath_add_led(sc, led);
if (ret < 0)
kfree(led);
return ret;
}
void ath_deinit_leds(struct ath_softc *sc)
{
struct ath_led *led;
while (!list_empty(&sc->leds)) {
led = list_first_entry(&sc->leds, struct ath_led, list);
list_del(&led->list);
ath_led_brightness(&led->cdev, LED_OFF);
led_classdev_unregister(&led->cdev);
kfree(led);
}
}
void ath_init_leds(struct ath_softc *sc)
{
struct ath9k_platform_data *pdata = sc->dev->platform_data;
char led_name[32];
const char *trigger;
int i;
INIT_LIST_HEAD(&sc->leds);
if (AR_SREV_9100(sc->sc_ah))
return;
snprintf(led_name, sizeof(led_name), "ath9k-%s",
wiphy_name(sc->hw->wiphy));
if (led_blink)
trigger = sc->led_default_trigger;
else
trigger = ieee80211_get_radio_led_name(sc->hw);
ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
if (!pdata)
return;
for (i = 0; i < pdata->num_leds; i++)
ath_create_platform_led(sc, &pdata->leds[i]);
}
void ath_fill_led_pin(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
if (AR_SREV_9100(ah) || (ah->led_pin >= 0))
return;
if (AR_SREV_9287(ah))
ah->led_pin = ATH_LED_PIN_9287;
else if (AR_SREV_9485(sc->sc_ah))
ah->led_pin = ATH_LED_PIN_9485;
else if (AR_SREV_9300(sc->sc_ah))
ah->led_pin = ATH_LED_PIN_9300;
else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
ah->led_pin = ATH_LED_PIN_9462;
else
ah->led_pin = ATH_LED_PIN_DEF;
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
}
#endif