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 break; 34 case CAN_LED_EVENT_STOP: 35 led_trigger_event(priv->tx_led_trig, LED_OFF); 36 led_trigger_event(priv->rx_led_trig, LED_OFF); 37 break; 38 case CAN_LED_EVENT_TX: 39 if (led_delay) 40 led_trigger_blink_oneshot(priv->tx_led_trig, 41 &led_delay, &led_delay, 1); 42 break; 43 case CAN_LED_EVENT_RX: 44 if (led_delay) 45 led_trigger_blink_oneshot(priv->rx_led_trig, 46 &led_delay, &led_delay, 1); 47 break; 48 } 49} 50EXPORT_SYMBOL_GPL(can_led_event); 51 52static void can_led_release(struct device *gendev, void *res) 53{ 54 struct can_priv *priv = netdev_priv(to_net_dev(gendev)); 55 56 led_trigger_unregister_simple(priv->tx_led_trig); 57 led_trigger_unregister_simple(priv->rx_led_trig); 58} 59 60/* Register CAN LED triggers for a CAN device 61 * 62 * This is normally called from a driver's probe function 63 */ 64void devm_can_led_init(struct net_device *netdev) 65{ 66 struct can_priv *priv = netdev_priv(netdev); 67 void *res; 68 69 res = devres_alloc(can_led_release, 0, GFP_KERNEL); 70 if (!res) { 71 netdev_err(netdev, "cannot register LED triggers\n"); 72 return; 73 } 74 75 snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name), 76 "%s-tx", netdev->name); 77 snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name), 78 "%s-rx", netdev->name); 79 80 led_trigger_register_simple(priv->tx_led_trig_name, 81 &priv->tx_led_trig); 82 led_trigger_register_simple(priv->rx_led_trig_name, 83 &priv->rx_led_trig); 84 85 devres_add(&netdev->dev, res); 86} 87EXPORT_SYMBOL_GPL(devm_can_led_init); 88 89/* NETDEV rename notifier to rename the associated led triggers too */ 90static int can_led_notifier(struct notifier_block *nb, unsigned long msg, 91 void *ptr) 92{ 93 struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 94 struct can_priv *priv = safe_candev_priv(netdev); 95 char name[CAN_LED_NAME_SZ]; 96 97 if (!priv) 98 return NOTIFY_DONE; 99 100 if (!priv->tx_led_trig || !priv->rx_led_trig) 101 return NOTIFY_DONE; 102 103 if (msg == NETDEV_CHANGENAME) { 104 snprintf(name, sizeof(name), "%s-tx", netdev->name); 105 led_trigger_rename_static(name, priv->tx_led_trig); 106 107 snprintf(name, sizeof(name), "%s-rx", netdev->name); 108 led_trigger_rename_static(name, priv->rx_led_trig); 109 } 110 111 return NOTIFY_DONE; 112} 113 114/* notifier block for netdevice event */ 115static struct notifier_block can_netdev_notifier __read_mostly = { 116 .notifier_call = can_led_notifier, 117}; 118 119int __init can_led_notifier_init(void) 120{ 121 return register_netdevice_notifier(&can_netdev_notifier); 122} 123 124void __exit can_led_notifier_exit(void) 125{ 126 unregister_netdevice_notifier(&can_netdev_notifier); 127} 128