Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: add tx/rx LED trigger support

This patch implements the functions to add two LED triggers, named
<ifname>-tx and <ifname>-rx, to a canbus device driver.

Triggers are called from specific handlers by each CAN device driver and
can be disabled altogether with a Kconfig option.

The implementation keeps the LED on when the interface is UP and blinks
the LED on network activity at a configurable rate.

This only supports can-dev based drivers, as it uses some support field
in the can_priv structure.

Supported drivers should call devm_can_led_init() and can_led_event() as
needed.

Cleanup is handled automatically by devres, so no *_exit function is
needed.

Supported events are:
- CAN_LED_EVENT_OPEN: turn on tx/rx LEDs
- CAN_LED_EVENT_STOP: turn off tx/rx LEDs
- CAN_LED_EVENT_TX: trigger tx LED blink
- CAN_LED_EVENT_RX: trigger tx LED blink

Cc: Wolfgang Grandegger <wg@grandegger.com>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Fabio Baltieri and committed by
Marc Kleine-Budde
996a953d 0024d8ad

+149
+11
drivers/net/can/Kconfig
··· 51 51 arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". 52 52 If unsure, say Y. 53 53 54 + config CAN_LEDS 55 + bool "Enable LED triggers for Netlink based drivers" 56 + depends on LEDS_CLASS 57 + select LEDS_TRIGGERS 58 + ---help--- 59 + This option adds two LED triggers for packet receive and transmit 60 + events on each supported CAN device. 61 + 62 + Say Y here if you are working on a system with led-class supported 63 + LEDs and you want to use them as canbus activity indicators. 64 + 54 65 config CAN_AT91 55 66 tristate "Atmel AT91 onchip CAN controller" 56 67 depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
+2
drivers/net/can/Makefile
··· 8 8 obj-$(CONFIG_CAN_DEV) += can-dev.o 9 9 can-dev-y := dev.o 10 10 11 + can-dev-$(CONFIG_CAN_LEDS) += led.o 12 + 11 13 obj-y += usb/ 12 14 obj-y += softing/ 13 15
+86
drivers/net/can/led.c
··· 1 + /* 2 + * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/device.h> 11 + #include <linux/kernel.h> 12 + #include <linux/slab.h> 13 + #include <linux/netdevice.h> 14 + #include <linux/can/dev.h> 15 + 16 + #include <linux/can/led.h> 17 + 18 + static unsigned long led_delay = 50; 19 + module_param(led_delay, ulong, 0644); 20 + MODULE_PARM_DESC(led_delay, 21 + "blink delay time for activity leds (msecs, default: 50)."); 22 + 23 + /* Trigger a LED event in response to a CAN device event */ 24 + void can_led_event(struct net_device *netdev, enum can_led_event event) 25 + { 26 + struct can_priv *priv = netdev_priv(netdev); 27 + 28 + switch (event) { 29 + case CAN_LED_EVENT_OPEN: 30 + led_trigger_event(priv->tx_led_trig, LED_FULL); 31 + led_trigger_event(priv->rx_led_trig, LED_FULL); 32 + break; 33 + case CAN_LED_EVENT_STOP: 34 + led_trigger_event(priv->tx_led_trig, LED_OFF); 35 + led_trigger_event(priv->rx_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 + break; 42 + case CAN_LED_EVENT_RX: 43 + if (led_delay) 44 + led_trigger_blink_oneshot(priv->rx_led_trig, 45 + &led_delay, &led_delay, 1); 46 + break; 47 + } 48 + } 49 + EXPORT_SYMBOL_GPL(can_led_event); 50 + 51 + static void can_led_release(struct device *gendev, void *res) 52 + { 53 + struct can_priv *priv = netdev_priv(to_net_dev(gendev)); 54 + 55 + led_trigger_unregister_simple(priv->tx_led_trig); 56 + led_trigger_unregister_simple(priv->rx_led_trig); 57 + } 58 + 59 + /* Register CAN LED triggers for a CAN device 60 + * 61 + * This is normally called from a driver's probe function 62 + */ 63 + void devm_can_led_init(struct net_device *netdev) 64 + { 65 + struct can_priv *priv = netdev_priv(netdev); 66 + void *res; 67 + 68 + res = devres_alloc(can_led_release, 0, GFP_KERNEL); 69 + if (!res) { 70 + netdev_err(netdev, "cannot register LED triggers\n"); 71 + return; 72 + } 73 + 74 + snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name), 75 + "%s-tx", netdev->name); 76 + snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name), 77 + "%s-rx", netdev->name); 78 + 79 + led_trigger_register_simple(priv->tx_led_trig_name, 80 + &priv->tx_led_trig); 81 + led_trigger_register_simple(priv->rx_led_trig_name, 82 + &priv->rx_led_trig); 83 + 84 + devres_add(&netdev->dev, res); 85 + } 86 + EXPORT_SYMBOL_GPL(devm_can_led_init);
+8
include/linux/can/dev.h
··· 16 16 #include <linux/can.h> 17 17 #include <linux/can/netlink.h> 18 18 #include <linux/can/error.h> 19 + #include <linux/can/led.h> 19 20 20 21 /* 21 22 * CAN mode ··· 53 52 54 53 unsigned int echo_skb_max; 55 54 struct sk_buff **echo_skb; 55 + 56 + #ifdef CONFIG_CAN_LEDS 57 + struct led_trigger *tx_led_trig; 58 + char tx_led_trig_name[CAN_LED_NAME_SZ]; 59 + struct led_trigger *rx_led_trig; 60 + char rx_led_trig_name[CAN_LED_NAME_SZ]; 61 + #endif 56 62 }; 57 63 58 64 /*
+42
include/linux/can/led.h
··· 1 + /* 2 + * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef CAN_LED_H 10 + #define CAN_LED_H 11 + 12 + #include <linux/if.h> 13 + #include <linux/leds.h> 14 + 15 + enum can_led_event { 16 + CAN_LED_EVENT_OPEN, 17 + CAN_LED_EVENT_STOP, 18 + CAN_LED_EVENT_TX, 19 + CAN_LED_EVENT_RX, 20 + }; 21 + 22 + #ifdef CONFIG_CAN_LEDS 23 + 24 + /* keep space for interface name + "-tx"/"-rx" suffix and null terminator */ 25 + #define CAN_LED_NAME_SZ (IFNAMSIZ + 4) 26 + 27 + void can_led_event(struct net_device *netdev, enum can_led_event event); 28 + void devm_can_led_init(struct net_device *netdev); 29 + 30 + #else 31 + 32 + static inline void can_led_event(struct net_device *netdev, 33 + enum can_led_event event) 34 + { 35 + } 36 + static inline void devm_can_led_init(struct net_device *netdev) 37 + { 38 + } 39 + 40 + #endif 41 + 42 + #endif