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