diff options
author | Fabio Baltieri <fabio.baltieri@gmail.com> | 2012-12-18 12:50:55 -0500 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2013-01-26 10:58:59 -0500 |
commit | 996a953de02ffb852c9ac736f4e892008ed68884 (patch) | |
tree | dcf301c575ee47331f34c961c36f5658ce32da32 | |
parent | 0024d8ad1639e32d717445c69ca813fd19c2a91c (diff) |
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>
-rw-r--r-- | drivers/net/can/Kconfig | 11 | ||||
-rw-r--r-- | drivers/net/can/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/can/led.c | 86 | ||||
-rw-r--r-- | include/linux/can/dev.h | 8 | ||||
-rw-r--r-- | include/linux/can/led.h | 42 |
5 files changed, 149 insertions, 0 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 0c5a65682d01..1cca19f1c490 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig | |||
@@ -51,6 +51,17 @@ config CAN_CALC_BITTIMING | |||
51 | arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". | 51 | arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". |
52 | If unsure, say Y. | 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 | config CAN_AT91 | 65 | config CAN_AT91 |
55 | tristate "Atmel AT91 onchip CAN controller" | 66 | tristate "Atmel AT91 onchip CAN controller" |
56 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5 | 67 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5 |
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 7de59862bbe9..c7440392adbb 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile | |||
@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o | |||
8 | obj-$(CONFIG_CAN_DEV) += can-dev.o | 8 | obj-$(CONFIG_CAN_DEV) += can-dev.o |
9 | can-dev-y := dev.o | 9 | can-dev-y := dev.o |
10 | 10 | ||
11 | can-dev-$(CONFIG_CAN_LEDS) += led.o | ||
12 | |||
11 | obj-y += usb/ | 13 | obj-y += usb/ |
12 | obj-y += softing/ | 14 | obj-y += softing/ |
13 | 15 | ||
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c new file mode 100644 index 000000000000..c50a0d741c57 --- /dev/null +++ b/drivers/net/can/led.c | |||
@@ -0,0 +1,86 @@ | |||
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); | ||
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 2b2fc345afca..7747d9bcdc84 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/can.h> | 16 | #include <linux/can.h> |
17 | #include <linux/can/netlink.h> | 17 | #include <linux/can/netlink.h> |
18 | #include <linux/can/error.h> | 18 | #include <linux/can/error.h> |
19 | #include <linux/can/led.h> | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * CAN mode | 22 | * CAN mode |
@@ -52,6 +53,13 @@ struct can_priv { | |||
52 | 53 | ||
53 | unsigned int echo_skb_max; | 54 | unsigned int echo_skb_max; |
54 | struct sk_buff **echo_skb; | 55 | struct sk_buff **echo_skb; |
56 | |||
57 | #ifdef CONFIG_CAN_LEDS | ||
58 | struct led_trigger *tx_led_trig; | ||
59 | char tx_led_trig_name[CAN_LED_NAME_SZ]; | ||
60 | struct led_trigger *rx_led_trig; | ||
61 | char rx_led_trig_name[CAN_LED_NAME_SZ]; | ||
62 | #endif | ||
55 | }; | 63 | }; |
56 | 64 | ||
57 | /* | 65 | /* |
diff --git a/include/linux/can/led.h b/include/linux/can/led.h new file mode 100644 index 000000000000..12d5549abb95 --- /dev/null +++ b/include/linux/can/led.h | |||
@@ -0,0 +1,42 @@ | |||
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 | ||