cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

leds.c (6419B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Linux LED driver for RTL8187
      4 *
      5 * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
      6 *
      7 * Based on the LED handling in the r8187 driver, which is:
      8 * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
      9 *
     10 * Thanks to Realtek for their support!
     11 */
     12
     13#ifdef CONFIG_RTL8187_LEDS
     14
     15#include <net/mac80211.h>
     16#include <linux/usb.h>
     17#include <linux/eeprom_93cx6.h>
     18
     19#include "rtl8187.h"
     20#include "leds.h"
     21
     22static void led_turn_on(struct work_struct *work)
     23{
     24	/* As this routine does read/write operations on the hardware, it must
     25	 * be run from a work queue.
     26	 */
     27	u8 reg;
     28	struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
     29				    led_on.work);
     30	struct rtl8187_led *led = &priv->led_tx;
     31
     32	/* Don't change the LED, when the device is down. */
     33	if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
     34		return ;
     35
     36	/* Skip if the LED is not registered. */
     37	if (!led->dev)
     38		return;
     39	mutex_lock(&priv->conf_mutex);
     40	switch (led->ledpin) {
     41	case LED_PIN_GPIO0:
     42		rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
     43		rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
     44		break;
     45	case LED_PIN_LED0:
     46		reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4);
     47		rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
     48		break;
     49	case LED_PIN_LED1:
     50		reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5);
     51		rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
     52		break;
     53	case LED_PIN_HW:
     54	default:
     55		break;
     56	}
     57	mutex_unlock(&priv->conf_mutex);
     58}
     59
     60static void led_turn_off(struct work_struct *work)
     61{
     62	/* As this routine does read/write operations on the hardware, it must
     63	 * be run from a work queue.
     64	 */
     65	u8 reg;
     66	struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
     67				    led_off.work);
     68	struct rtl8187_led *led = &priv->led_tx;
     69
     70	/* Don't change the LED, when the device is down. */
     71	if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
     72		return ;
     73
     74	/* Skip if the LED is not registered. */
     75	if (!led->dev)
     76		return;
     77	mutex_lock(&priv->conf_mutex);
     78	switch (led->ledpin) {
     79	case LED_PIN_GPIO0:
     80		rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
     81		rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
     82		break;
     83	case LED_PIN_LED0:
     84		reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4);
     85		rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
     86		break;
     87	case LED_PIN_LED1:
     88		reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5);
     89		rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
     90		break;
     91	case LED_PIN_HW:
     92	default:
     93		break;
     94	}
     95	mutex_unlock(&priv->conf_mutex);
     96}
     97
     98/* Callback from the LED subsystem. */
     99static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
    100				   enum led_brightness brightness)
    101{
    102	struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led,
    103					       led_dev);
    104	struct ieee80211_hw *hw = led->dev;
    105	struct rtl8187_priv *priv;
    106	static bool radio_on;
    107
    108	if (!hw)
    109		return;
    110	priv = hw->priv;
    111	if (led->is_radio) {
    112		if (brightness == LED_FULL) {
    113			ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
    114			radio_on = true;
    115		} else if (radio_on) {
    116			radio_on = false;
    117			cancel_delayed_work(&priv->led_on);
    118			ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
    119		}
    120	} else if (radio_on) {
    121		if (brightness == LED_OFF) {
    122			ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
    123			/* The LED is off for 1/20 sec - it just blinks. */
    124			ieee80211_queue_delayed_work(hw, &priv->led_on,
    125						     HZ / 20);
    126		} else
    127			ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
    128	}
    129}
    130
    131static int rtl8187_register_led(struct ieee80211_hw *dev,
    132				struct rtl8187_led *led, const char *name,
    133				const char *default_trigger, u8 ledpin,
    134				bool is_radio)
    135{
    136	int err;
    137	struct rtl8187_priv *priv = dev->priv;
    138
    139	if (led->dev)
    140		return -EEXIST;
    141	if (!default_trigger)
    142		return -EINVAL;
    143	led->dev = dev;
    144	led->ledpin = ledpin;
    145	led->is_radio = is_radio;
    146	strlcpy(led->name, name, sizeof(led->name));
    147
    148	led->led_dev.name = led->name;
    149	led->led_dev.default_trigger = default_trigger;
    150	led->led_dev.brightness_set = rtl8187_led_brightness_set;
    151
    152	err = led_classdev_register(&priv->udev->dev, &led->led_dev);
    153	if (err) {
    154		printk(KERN_INFO "LEDs: Failed to register %s\n", name);
    155		led->dev = NULL;
    156		return err;
    157	}
    158	return 0;
    159}
    160
    161static void rtl8187_unregister_led(struct rtl8187_led *led)
    162{
    163	struct ieee80211_hw *hw = led->dev;
    164	struct rtl8187_priv *priv = hw->priv;
    165
    166	led_classdev_unregister(&led->led_dev);
    167	flush_delayed_work(&priv->led_off);
    168	led->dev = NULL;
    169}
    170
    171void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
    172{
    173	struct rtl8187_priv *priv = dev->priv;
    174	char name[RTL8187_LED_MAX_NAME_LEN + 1];
    175	u8 ledpin;
    176	int err;
    177
    178	/* According to the vendor driver, the LED operation depends on the
    179	 * customer ID encoded in the EEPROM
    180	 */
    181	printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid);
    182	switch (custid) {
    183	case EEPROM_CID_RSVD0:
    184	case EEPROM_CID_RSVD1:
    185	case EEPROM_CID_SERCOMM_PS:
    186	case EEPROM_CID_QMI:
    187	case EEPROM_CID_DELL:
    188	case EEPROM_CID_TOSHIBA:
    189		ledpin = LED_PIN_GPIO0;
    190		break;
    191	case EEPROM_CID_ALPHA0:
    192		ledpin = LED_PIN_LED0;
    193		break;
    194	case EEPROM_CID_HW:
    195		ledpin = LED_PIN_HW;
    196		break;
    197	default:
    198		ledpin = LED_PIN_GPIO0;
    199	}
    200
    201	INIT_DELAYED_WORK(&priv->led_on, led_turn_on);
    202	INIT_DELAYED_WORK(&priv->led_off, led_turn_off);
    203
    204	snprintf(name, sizeof(name),
    205		 "rtl8187-%s::radio", wiphy_name(dev->wiphy));
    206	err = rtl8187_register_led(dev, &priv->led_radio, name,
    207			 ieee80211_get_radio_led_name(dev), ledpin, true);
    208	if (err)
    209		return;
    210
    211	snprintf(name, sizeof(name),
    212		 "rtl8187-%s::tx", wiphy_name(dev->wiphy));
    213	err = rtl8187_register_led(dev, &priv->led_tx, name,
    214			 ieee80211_get_tx_led_name(dev), ledpin, false);
    215	if (err)
    216		goto err_tx;
    217
    218	snprintf(name, sizeof(name),
    219		 "rtl8187-%s::rx", wiphy_name(dev->wiphy));
    220	err = rtl8187_register_led(dev, &priv->led_rx, name,
    221			 ieee80211_get_rx_led_name(dev), ledpin, false);
    222	if (!err)
    223		return;
    224
    225	/* registration of RX LED failed - unregister */
    226	rtl8187_unregister_led(&priv->led_tx);
    227err_tx:
    228	rtl8187_unregister_led(&priv->led_radio);
    229}
    230
    231void rtl8187_leds_exit(struct ieee80211_hw *dev)
    232{
    233	struct rtl8187_priv *priv = dev->priv;
    234
    235	rtl8187_unregister_led(&priv->led_radio);
    236	rtl8187_unregister_led(&priv->led_rx);
    237	rtl8187_unregister_led(&priv->led_tx);
    238	cancel_delayed_work_sync(&priv->led_off);
    239	cancel_delayed_work_sync(&priv->led_on);
    240}
    241#endif /* def CONFIG_RTL8187_LEDS */
    242