linux/drivers/net/can/led.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
   4 * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
   5 */
   6
   7#include <linux/module.h>
   8#include <linux/device.h>
   9#include <linux/kernel.h>
  10#include <linux/slab.h>
  11#include <linux/netdevice.h>
  12#include <linux/can/dev.h>
  13
  14#include <linux/can/led.h>
  15
  16static unsigned long led_delay = 50;
  17module_param(led_delay, ulong, 0644);
  18MODULE_PARM_DESC(led_delay,
  19                "blink delay time for activity leds (msecs, default: 50).");
  20
  21/* Trigger a LED event in response to a CAN device event */
  22void can_led_event(struct net_device *netdev, enum can_led_event event)
  23{
  24        struct can_priv *priv = netdev_priv(netdev);
  25
  26        switch (event) {
  27        case CAN_LED_EVENT_OPEN:
  28                led_trigger_event(priv->tx_led_trig, LED_FULL);
  29                led_trigger_event(priv->rx_led_trig, LED_FULL);
  30                led_trigger_event(priv->rxtx_led_trig, LED_FULL);
  31                break;
  32        case CAN_LED_EVENT_STOP:
  33                led_trigger_event(priv->tx_led_trig, LED_OFF);
  34                led_trigger_event(priv->rx_led_trig, LED_OFF);
  35                led_trigger_event(priv->rxtx_led_trig, LED_OFF);
  36                break;
  37        case CAN_LED_EVENT_TX:
  38                if (led_delay) {
  39                        led_trigger_blink_oneshot(priv->tx_led_trig,
  40                                                  &led_delay, &led_delay, 1);
  41                        led_trigger_blink_oneshot(priv->rxtx_led_trig,
  42                                                  &led_delay, &led_delay, 1);
  43                }
  44                break;
  45        case CAN_LED_EVENT_RX:
  46                if (led_delay) {
  47                        led_trigger_blink_oneshot(priv->rx_led_trig,
  48                                                  &led_delay, &led_delay, 1);
  49                        led_trigger_blink_oneshot(priv->rxtx_led_trig,
  50                                                  &led_delay, &led_delay, 1);
  51                }
  52                break;
  53        }
  54}
  55EXPORT_SYMBOL_GPL(can_led_event);
  56
  57static void can_led_release(struct device *gendev, void *res)
  58{
  59        struct can_priv *priv = netdev_priv(to_net_dev(gendev));
  60
  61        led_trigger_unregister_simple(priv->tx_led_trig);
  62        led_trigger_unregister_simple(priv->rx_led_trig);
  63        led_trigger_unregister_simple(priv->rxtx_led_trig);
  64}
  65
  66/* Register CAN LED triggers for a CAN device
  67 *
  68 * This is normally called from a driver's probe function
  69 */
  70void devm_can_led_init(struct net_device *netdev)
  71{
  72        struct can_priv *priv = netdev_priv(netdev);
  73        void *res;
  74
  75        res = devres_alloc(can_led_release, 0, GFP_KERNEL);
  76        if (!res) {
  77                netdev_err(netdev, "cannot register LED triggers\n");
  78                return;
  79        }
  80
  81        snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
  82                 "%s-tx", netdev->name);
  83        snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
  84                 "%s-rx", netdev->name);
  85        snprintf(priv->rxtx_led_trig_name, sizeof(priv->rxtx_led_trig_name),
  86                 "%s-rxtx", netdev->name);
  87
  88        led_trigger_register_simple(priv->tx_led_trig_name,
  89                                    &priv->tx_led_trig);
  90        led_trigger_register_simple(priv->rx_led_trig_name,
  91                                    &priv->rx_led_trig);
  92        led_trigger_register_simple(priv->rxtx_led_trig_name,
  93                                    &priv->rxtx_led_trig);
  94
  95        devres_add(&netdev->dev, res);
  96}
  97EXPORT_SYMBOL_GPL(devm_can_led_init);
  98
  99/* NETDEV rename notifier to rename the associated led triggers too */
 100static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
 101                            void *ptr)
 102{
 103        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
 104        struct can_priv *priv = safe_candev_priv(netdev);
 105        char name[CAN_LED_NAME_SZ];
 106
 107        if (!priv)
 108                return NOTIFY_DONE;
 109
 110        if (!priv->tx_led_trig || !priv->rx_led_trig || !priv->rxtx_led_trig)
 111                return NOTIFY_DONE;
 112
 113        if (msg == NETDEV_CHANGENAME) {
 114                snprintf(name, sizeof(name), "%s-tx", netdev->name);
 115                led_trigger_rename_static(name, priv->tx_led_trig);
 116
 117                snprintf(name, sizeof(name), "%s-rx", netdev->name);
 118                led_trigger_rename_static(name, priv->rx_led_trig);
 119
 120                snprintf(name, sizeof(name), "%s-rxtx", netdev->name);
 121                led_trigger_rename_static(name, priv->rxtx_led_trig);
 122        }
 123
 124        return NOTIFY_DONE;
 125}
 126
 127/* notifier block for netdevice event */
 128static struct notifier_block can_netdev_notifier __read_mostly = {
 129        .notifier_call = can_led_notifier,
 130};
 131
 132int __init can_led_notifier_init(void)
 133{
 134        return register_netdevice_notifier(&can_netdev_notifier);
 135}
 136
 137void __exit can_led_notifier_exit(void)
 138{
 139        unregister_netdevice_notifier(&can_netdev_notifier);
 140}
 141