linux/drivers/net/wireless/rtl818x/rtl8187/leds.c
<<
>>
Prefs
   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 "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->vif || priv->vif->type == 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->GPIO0, 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->vif || priv->vif->type == 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->GPIO0, 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;
 109        static bool radio_on;
 110
 111        if (!hw)
 112                return;
 113        priv = hw->priv;
 114        if (led->is_radio) {
 115                if (brightness == LED_FULL) {
 116                        ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
 117                        radio_on = true;
 118                } else if (radio_on) {
 119                        radio_on = false;
 120                        cancel_delayed_work(&priv->led_on);
 121                        ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
 122                }
 123        } else if (radio_on) {
 124                if (brightness == LED_OFF) {
 125                        ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
 126                        /* The LED is off for 1/20 sec - it just blinks. */
 127                        ieee80211_queue_delayed_work(hw, &priv->led_on,
 128                                                     HZ / 20);
 129                } else
 130                        ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
 131        }
 132}
 133
 134static int rtl8187_register_led(struct ieee80211_hw *dev,
 135                                struct rtl8187_led *led, const char *name,
 136                                const char *default_trigger, u8 ledpin,
 137                                bool is_radio)
 138{
 139        int err;
 140        struct rtl8187_priv *priv = dev->priv;
 141
 142        if (led->dev)
 143                return -EEXIST;
 144        if (!default_trigger)
 145                return -EINVAL;
 146        led->dev = dev;
 147        led->ledpin = ledpin;
 148        led->is_radio = is_radio;
 149        strncpy(led->name, name, sizeof(led->name));
 150
 151        led->led_dev.name = led->name;
 152        led->led_dev.default_trigger = default_trigger;
 153        led->led_dev.brightness_set = rtl8187_led_brightness_set;
 154
 155        err = led_classdev_register(&priv->udev->dev, &led->led_dev);
 156        if (err) {
 157                printk(KERN_INFO "LEDs: Failed to register %s\n", name);
 158                led->dev = NULL;
 159                return err;
 160        }
 161        return 0;
 162}
 163
 164static void rtl8187_unregister_led(struct rtl8187_led *led)
 165{
 166        struct ieee80211_hw *hw = led->dev;
 167        struct rtl8187_priv *priv = hw->priv;
 168
 169        led_classdev_unregister(&led->led_dev);
 170        flush_delayed_work(&priv->led_off);
 171        led->dev = NULL;
 172}
 173
 174void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
 175{
 176        struct rtl8187_priv *priv = dev->priv;
 177        char name[RTL8187_LED_MAX_NAME_LEN + 1];
 178        u8 ledpin;
 179        int err;
 180
 181        /* According to the vendor driver, the LED operation depends on the
 182         * customer ID encoded in the EEPROM
 183         */
 184        printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid);
 185        switch (custid) {
 186        case EEPROM_CID_RSVD0:
 187        case EEPROM_CID_RSVD1:
 188        case EEPROM_CID_SERCOMM_PS:
 189        case EEPROM_CID_QMI:
 190        case EEPROM_CID_DELL:
 191        case EEPROM_CID_TOSHIBA:
 192                ledpin = LED_PIN_GPIO0;
 193                break;
 194        case EEPROM_CID_ALPHA0:
 195                ledpin = LED_PIN_LED0;
 196                break;
 197        case EEPROM_CID_HW:
 198                ledpin = LED_PIN_HW;
 199                break;
 200        default:
 201                ledpin = LED_PIN_GPIO0;
 202        }
 203
 204        INIT_DELAYED_WORK(&priv->led_on, led_turn_on);
 205        INIT_DELAYED_WORK(&priv->led_off, led_turn_off);
 206
 207        snprintf(name, sizeof(name),
 208                 "rtl8187-%s::radio", wiphy_name(dev->wiphy));
 209        err = rtl8187_register_led(dev, &priv->led_radio, name,
 210                         ieee80211_get_radio_led_name(dev), ledpin, true);
 211        if (err)
 212                return;
 213
 214        snprintf(name, sizeof(name),
 215                 "rtl8187-%s::tx", wiphy_name(dev->wiphy));
 216        err = rtl8187_register_led(dev, &priv->led_tx, name,
 217                         ieee80211_get_tx_led_name(dev), ledpin, false);
 218        if (err)
 219                goto err_tx;
 220
 221        snprintf(name, sizeof(name),
 222                 "rtl8187-%s::rx", wiphy_name(dev->wiphy));
 223        err = rtl8187_register_led(dev, &priv->led_rx, name,
 224                         ieee80211_get_rx_led_name(dev), ledpin, false);
 225        if (!err)
 226                return;
 227
 228        /* registration of RX LED failed - unregister */
 229        rtl8187_unregister_led(&priv->led_tx);
 230err_tx:
 231        rtl8187_unregister_led(&priv->led_radio);
 232}
 233
 234void rtl8187_leds_exit(struct ieee80211_hw *dev)
 235{
 236        struct rtl8187_priv *priv = dev->priv;
 237
 238        rtl8187_unregister_led(&priv->led_radio);
 239        rtl8187_unregister_led(&priv->led_rx);
 240        rtl8187_unregister_led(&priv->led_tx);
 241        cancel_delayed_work_sync(&priv->led_off);
 242        cancel_delayed_work_sync(&priv->led_on);
 243}
 244#endif /* def CONFIG_RTL8187_LEDS */
 245
 246