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