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