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