Commit 61550022 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-davem' of git://gitorious.org/linux-can/linux-can-next

Marc Kleine-Budde says:

====================
this is a pull-request for net-next/master. There is are 9 patches by
Fabio Baltieri and Kurt Van Dijck which add LED infrastructure and
support for CAN devices. Bernd Krumboeck adds a driver for the USB CAN
adapter from 8 devices. Oliver Hartkopp improves the CAN gateway
functionality. There are 4 patches by me, which clean up the CAN's
Kconfig.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0e36cbb3 e6afa00a
menu "CAN Device Drivers" menu "CAN Device Drivers"
depends on CAN
config CAN_VCAN config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)" tristate "Virtual Local CAN Interface (vcan)"
depends on CAN
---help--- ---help---
Similar to the network loopback devices, vcan offers a Similar to the network loopback devices, vcan offers a
virtual local CAN interface. virtual local CAN interface.
...@@ -13,7 +11,6 @@ config CAN_VCAN ...@@ -13,7 +11,6 @@ config CAN_VCAN
config CAN_SLCAN config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)" tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on CAN
---help--- ---help---
CAN driver for several 'low cost' CAN interfaces that are attached CAN driver for several 'low cost' CAN interfaces that are attached
via serial lines or via USB-to-serial adapters using the LAWICEL via serial lines or via USB-to-serial adapters using the LAWICEL
...@@ -33,16 +30,16 @@ config CAN_SLCAN ...@@ -33,16 +30,16 @@ config CAN_SLCAN
config CAN_DEV config CAN_DEV
tristate "Platform CAN drivers with Netlink support" tristate "Platform CAN drivers with Netlink support"
depends on CAN
default y default y
---help--- ---help---
Enables the common framework for platform CAN drivers with Netlink Enables the common framework for platform CAN drivers with Netlink
support. This is the standard library for CAN drivers. support. This is the standard library for CAN drivers.
If unsure, say Y. If unsure, say Y.
if CAN_DEV
config CAN_CALC_BITTIMING config CAN_CALC_BITTIMING
bool "CAN bit-timing calculation" bool "CAN bit-timing calculation"
depends on CAN_DEV
default y default y
---help--- ---help---
If enabled, CAN bit-timing parameters will be calculated for the If enabled, CAN bit-timing parameters will be calculated for the
...@@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING ...@@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
If unsure, say Y. If unsure, say Y.
config CAN_LEDS
bool "Enable LED triggers for Netlink based drivers"
depends on LEDS_CLASS
select LEDS_TRIGGERS
---help---
This option adds two LED triggers for packet receive and transmit
events on each supported CAN device.
Say Y here if you are working on a system with led-class supported
LEDs and you want to use them as canbus activity indicators.
config CAN_AT91 config CAN_AT91
tristate "Atmel AT91 onchip CAN controller" tristate "Atmel AT91 onchip CAN controller"
depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5) depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
---help--- ---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors. and AT91SAM9X5 processors.
config CAN_TI_HECC config CAN_TI_HECC
depends on CAN_DEV && ARCH_OMAP3 depends on ARCH_OMAP3
tristate "TI High End CAN Controller" tristate "TI High End CAN Controller"
---help--- ---help---
Driver for TI HECC (High End CAN Controller) module found on many Driver for TI HECC (High End CAN Controller) module found on many
...@@ -70,12 +78,12 @@ config CAN_TI_HECC ...@@ -70,12 +78,12 @@ config CAN_TI_HECC
config CAN_MCP251X config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers" tristate "Microchip MCP251x SPI CAN controllers"
depends on CAN_DEV && SPI && HAS_DMA depends on SPI && HAS_DMA
---help--- ---help---
Driver for the Microchip MCP251x SPI CAN controllers. Driver for the Microchip MCP251x SPI CAN controllers.
config CAN_BFIN config CAN_BFIN
depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x) depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
tristate "Analog Devices Blackfin on-chip CAN" tristate "Analog Devices Blackfin on-chip CAN"
---help--- ---help---
Driver for the Analog Devices Blackfin on-chip CAN controllers Driver for the Analog Devices Blackfin on-chip CAN controllers
...@@ -85,7 +93,7 @@ config CAN_BFIN ...@@ -85,7 +93,7 @@ config CAN_BFIN
config CAN_JANZ_ICAN3 config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller" tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
depends on CAN_DEV && MFD_JANZ_CMODIO depends on MFD_JANZ_CMODIO
---help--- ---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board. connects to a MODULbus carrier board.
...@@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN ...@@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN
config CAN_FLEXCAN config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips" tristate "Support for Freescale FLEXCAN based chips"
depends on CAN_DEV && HAVE_CAN_FLEXCAN depends on HAVE_CAN_FLEXCAN
---help--- ---help---
Say Y here if you want to support for Freescale FlexCAN. Say Y here if you want to support for Freescale FlexCAN.
config PCH_CAN config PCH_CAN
tristate "Intel EG20T PCH CAN controller" tristate "Intel EG20T PCH CAN controller"
depends on CAN_DEV && PCI depends on PCI
---help--- ---help---
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
is an IOH for x86 embedded processor (Intel Atom E6xx series). is an IOH for x86 embedded processor (Intel Atom E6xx series).
...@@ -112,7 +120,7 @@ config PCH_CAN ...@@ -112,7 +120,7 @@ config PCH_CAN
config CAN_GRCAN config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices" tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on CAN_DEV && OF depends on OF
---help--- ---help---
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN. Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little Note that the driver supports little endian, even though little
...@@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig" ...@@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig" source "drivers/net/can/softing/Kconfig"
endif
config CAN_DEBUG_DEVICES config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages" bool "CAN devices debugging messages"
depends on CAN
---help--- ---help---
Say Y here if you want the CAN device drivers to produce a bunch of Say Y here if you want the CAN device drivers to produce a bunch of
debug messages to the system log. Select this if you are having debug messages to the system log. Select this if you are having
......
...@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o ...@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += usb/ obj-y += usb/
obj-y += softing/ obj-y += softing/
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#define AT91_MB_MASK(i) ((1 << (i)) - 1) #define AT91_MB_MASK(i) ((1 << (i)) - 1)
...@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) ...@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
} }
/** /**
...@@ -875,6 +878,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) ...@@ -875,6 +878,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
can_get_echo_skb(dev, mb - get_mb_tx_first(priv)); can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
dev->stats.tx_packets++; dev->stats.tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
} }
} }
...@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev) ...@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev)
goto out_close; goto out_close;
} }
can_led_event(dev, CAN_LED_EVENT_OPEN);
/* start chip and queuing */ /* start chip and queuing */
at91_chip_start(dev); at91_chip_start(dev);
napi_enable(&priv->napi); napi_enable(&priv->napi);
...@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev) ...@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev)
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev) ...@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev)
goto exit_free; goto exit_free;
} }
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->reg_base, dev->irq); priv->reg_base, dev->irq);
......
menuconfig CAN_C_CAN menuconfig CAN_C_CAN
tristate "Bosch C_CAN/D_CAN devices" tristate "Bosch C_CAN/D_CAN devices"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
if CAN_C_CAN if CAN_C_CAN
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#include "c_can.h" #include "c_can.h"
...@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) ...@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += frame->can_dlc; stats->rx_bytes += frame->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
return 0; return 0;
} }
...@@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev) ...@@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev)
C_CAN_IFACE(MSGCTRL_REG, 0)) C_CAN_IFACE(MSGCTRL_REG, 0))
& IF_MCONT_DLC_MASK; & IF_MCONT_DLC_MASK;
stats->tx_packets++; stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
c_can_inval_msg_object(dev, 0, msg_obj_no); c_can_inval_msg_object(dev, 0, msg_obj_no);
} else { } else {
break; break;
...@@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev) ...@@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev)
napi_enable(&priv->napi); napi_enable(&priv->napi);
can_led_event(dev, CAN_LED_EVENT_OPEN);
/* start the c_can controller */ /* start the c_can controller */
c_can_start(dev); c_can_start(dev);
...@@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev) ...@@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev)
c_can_reset_ram(priv, false); c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv); c_can_pm_runtime_put_sync(priv);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev) ...@@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev)
err = register_candev(dev); err = register_candev(dev);
if (err) if (err)
c_can_pm_runtime_disable(priv); c_can_pm_runtime_disable(priv);
else
devm_can_led_init(dev);
return err; return err;
} }
......
menuconfig CAN_CC770 menuconfig CAN_CC770
tristate "Bosch CC770 and Intel AN82527 devices" tristate "Bosch CC770 and Intel AN82527 devices"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
if CAN_CC770 if CAN_CC770
......
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/can/netlink.h> #include <linux/can/netlink.h>
#include <linux/can/led.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#define MOD_DESC "CAN device driver interface" #define MOD_DESC "CAN device driver interface"
...@@ -501,13 +503,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) ...@@ -501,13 +503,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{ {
struct sk_buff *skb; struct sk_buff *skb;
skb = netdev_alloc_skb(dev, sizeof(struct can_frame)); skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
sizeof(struct can_frame));
if (unlikely(!skb)) if (unlikely(!skb))
return NULL; return NULL;
skb->protocol = htons(ETH_P_CAN); skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_reserve(skb, sizeof(struct can_skb_priv));
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
*cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(*cf, 0, sizeof(struct can_frame)); memset(*cf, 0, sizeof(struct can_frame));
...@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev) ...@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev)
} }
EXPORT_SYMBOL_GPL(unregister_candev); EXPORT_SYMBOL_GPL(unregister_candev);
/*
* Test if a network device is a candev based device
* and return the can_priv* if so.
*/
struct can_priv *safe_candev_priv(struct net_device *dev)
{
if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops))
return NULL;
return netdev_priv(dev);
}
EXPORT_SYMBOL_GPL(safe_candev_priv);
static __init int can_dev_init(void) static __init int can_dev_init(void)
{ {
int err; int err;
can_led_notifier_init();
err = rtnl_link_register(&can_link_ops); err = rtnl_link_register(&can_link_ops);
if (!err) if (!err)
printk(KERN_INFO MOD_DESC "\n"); printk(KERN_INFO MOD_DESC "\n");
...@@ -809,6 +831,8 @@ module_init(can_dev_init); ...@@ -809,6 +831,8 @@ module_init(can_dev_init);
static __exit void can_dev_exit(void) static __exit void can_dev_exit(void)
{ {
rtnl_link_unregister(&can_link_ops); rtnl_link_unregister(&can_link_ops);
can_led_notifier_exit();
} }
module_exit(can_dev_exit); module_exit(can_dev_exit);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/platform/flexcan.h> #include <linux/can/platform/flexcan.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev) ...@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
return 1; return 1;
} }
...@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) ...@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) { if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
stats->tx_bytes += can_get_echo_skb(dev, 0); stats->tx_bytes += can_get_echo_skb(dev, 0);
stats->tx_packets++; stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1); flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev) ...@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev)
err = flexcan_chip_start(dev); err = flexcan_chip_start(dev);
if (err) if (err)
goto out_close; goto out_close;
can_led_event(dev, CAN_LED_EVENT_OPEN);
napi_enable(&priv->napi); napi_enable(&priv->napi);
netif_start_queue(dev); netif_start_queue(dev);
...@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev) ...@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev)
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev) ...@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev)
goto failed_register; goto failed_register;
} }
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->base, dev->irq); priv->base, dev->irq);
......
/*
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
* Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/can/dev.h>
#include <linux/can/led.h>
static unsigned long led_delay = 50;
module_param(led_delay, ulong, 0644);
MODULE_PARM_DESC(led_delay,
"blink delay time for activity leds (msecs, default: 50).");
/* Trigger a LED event in response to a CAN device event */
void can_led_event(struct net_device *netdev, enum can_led_event event)
{
struct can_priv *priv = netdev_priv(netdev);
switch (event) {
case CAN_LED_EVENT_OPEN:
led_trigger_event(priv->tx_led_trig, LED_FULL);
led_trigger_event(priv->rx_led_trig, LED_FULL);
break;
case CAN_LED_EVENT_STOP:
led_trigger_event(priv->tx_led_trig, LED_OFF);
led_trigger_event(priv->rx_led_trig, LED_OFF);
break;
case CAN_LED_EVENT_TX:
if (led_delay)
led_trigger_blink_oneshot(priv->tx_led_trig,
&led_delay, &led_delay, 1);
break;
case CAN_LED_EVENT_RX:
if (led_delay)
led_trigger_blink_oneshot(priv->rx_led_trig,
&led_delay, &led_delay, 1);
break;
}
}
EXPORT_SYMBOL_GPL(can_led_event);
static void can_led_release(struct device *gendev, void *res)
{
struct can_priv *priv = netdev_priv(to_net_dev(gendev));
led_trigger_unregister_simple(priv->tx_led_trig);
led_trigger_unregister_simple(priv->rx_led_trig);
}
/* Register CAN LED triggers for a CAN device
*
* This is normally called from a driver's probe function
*/
void devm_can_led_init(struct net_device *netdev)
{
struct can_priv *priv = netdev_priv(netdev);
void *res;
res = devres_alloc(can_led_release, 0, GFP_KERNEL);
if (!res) {
netdev_err(netdev, "cannot register LED triggers\n");
return;
}
snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
"%s-tx", netdev->name);
snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
"%s-rx", netdev->name);
led_trigger_register_simple(priv->tx_led_trig_name,
&priv->tx_led_trig);
led_trigger_register_simple(priv->rx_led_trig_name,
&priv->rx_led_trig);
devres_add(&netdev->dev, res);
}
EXPORT_SYMBOL_GPL(devm_can_led_init);
/* NETDEV rename notifier to rename the associated led triggers too */
static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
void *data)
{
struct net_device *netdev = data;
struct can_priv *priv = safe_candev_priv(netdev);
char name[CAN_LED_NAME_SZ];
if (!priv)
return NOTIFY_DONE;
if (msg == NETDEV_CHANGENAME) {
snprintf(name, sizeof(name), "%s-tx", netdev->name);
led_trigger_rename_static(name, priv->tx_led_trig);
snprintf(name, sizeof(name), "%s-rx", netdev->name);
led_trigger_rename_static(name, priv->rx_led_trig);
}
return NOTIFY_DONE;
}
/* notifier block for netdevice event */
static struct notifier_block can_netdev_notifier __read_mostly = {
.notifier_call = can_led_notifier,
};
int __init can_led_notifier_init(void)
{
return register_netdevice_notifier(&can_netdev_notifier);
}
void __exit can_led_notifier_exit(void)
{
unregister_netdevice_notifier(&can_netdev_notifier);
}
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/led.h>
#include <linux/can/platform/mcp251x.h> #include <linux/can/platform/mcp251x.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -494,6 +495,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx) ...@@ -494,6 +495,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
priv->net->stats.rx_packets++; priv->net->stats.rx_packets++;
priv->net->stats.rx_bytes += frame->can_dlc; priv->net->stats.rx_bytes += frame->can_dlc;
can_led_event(priv->net, CAN_LED_EVENT_RX);
netif_rx_ni(skb); netif_rx_ni(skb);
} }
...@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net) ...@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net)
mutex_unlock(&priv->mcp_lock); mutex_unlock(&priv->mcp_lock);
can_led_event(net, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) ...@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf & CANINTF_TX) { if (intf & CANINTF_TX) {
net->stats.tx_packets++; net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1; net->stats.tx_bytes += priv->tx_len - 1;
can_led_event(net, CAN_LED_EVENT_TX);
if (priv->tx_len) { if (priv->tx_len) {
can_get_echo_skb(net, 0); can_get_echo_skb(net, 0);
priv->tx_len = 0; priv->tx_len = 0;
...@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net) ...@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net)
mcp251x_open_clean(net); mcp251x_open_clean(net);
goto open_unlock; goto open_unlock;
} }
can_led_event(net, CAN_LED_EVENT_OPEN);
netif_wake_queue(net); netif_wake_queue(net);
open_unlock: open_unlock:
...@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
pdata->transceiver_enable(0); pdata->transceiver_enable(0);
ret = register_candev(net); ret = register_candev(net);
if (!ret) { if (ret)
dev_info(&spi->dev, "probed\n"); goto error_probe;
return ret;
} devm_can_led_init(net);
dev_info(&spi->dev, "probed\n");
return ret;
error_probe: error_probe:
if (!mcp251x_enable_dma) if (!mcp251x_enable_dma)
kfree(priv->spi_rx_buf); kfree(priv->spi_rx_buf);
......
config CAN_MSCAN config CAN_MSCAN
depends on CAN_DEV && (PPC || M68K) depends on PPC || M68K
tristate "Support for Freescale MSCAN based chips" tristate "Support for Freescale MSCAN based chips"
---help--- ---help---
The Motorola Scalable Controller Area Network (MSCAN) definition The Motorola Scalable Controller Area Network (MSCAN) definition
......
menuconfig CAN_SJA1000 menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices" tristate "Philips/NXP SJA1000 devices"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
if CAN_SJA1000 if CAN_SJA1000
...@@ -99,11 +99,11 @@ config CAN_TSCAN1 ...@@ -99,11 +99,11 @@ config CAN_TSCAN1
tristate "TS-CAN1 PC104 boards" tristate "TS-CAN1 PC104 boards"
depends on ISA depends on ISA
help help
This driver is for Technologic Systems' TSCAN-1 PC104 boards. This driver is for Technologic Systems' TSCAN-1 PC104 boards.
http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1 http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
The driver supports multiple boards and automatically configures them: The driver supports multiple boards and automatically configures them:
PLD IO base addresses are read from jumpers JP1 and JP2, PLD IO base addresses are read from jumpers JP1 and JP2,
IRQ numbers are read from jumpers JP4 and JP5, IRQ numbers are read from jumpers JP4 and JP5,
SJA1000 IO base addresses are chosen heuristically (first that works). SJA1000 IO base addresses are chosen heuristically (first that works).
endif endif
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#include "sja1000.h" #include "sja1000.h"
...@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev) ...@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
} }
static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
...@@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) ...@@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
can_get_echo_skb(dev, 0); can_get_echo_skb(dev, 0);
} }
netif_wake_queue(dev); netif_wake_queue(dev);
can_led_event(dev, CAN_LED_EVENT_TX);
} }
if (isrc & IRQ_RI) { if (isrc & IRQ_RI) {
/* receive interrupt */ /* receive interrupt */
...@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev) ...@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev)
/* init and start chi */ /* init and start chi */
sja1000_start(dev); sja1000_start(dev);
can_led_event(dev, CAN_LED_EVENT_OPEN);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
...@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev) ...@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev)
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = { ...@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = {
int register_sja1000dev(struct net_device *dev) int register_sja1000dev(struct net_device *dev)
{ {
int ret;
if (!sja1000_probe_chip(dev)) if (!sja1000_probe_chip(dev))
return -ENODEV; return -ENODEV;
...@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev) ...@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev)
set_reset_mode(dev); set_reset_mode(dev);
chipset_init(dev); chipset_init(dev);
return register_candev(dev); ret = register_candev(dev);
if (!ret)
devm_can_led_init(dev);
return ret;
} }
EXPORT_SYMBOL_GPL(register_sja1000dev); EXPORT_SYMBOL_GPL(register_sja1000dev);
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/skb.h>
static __initconst const char banner[] = static __initconst const char banner[] =
KERN_INFO "slcan: serial line CAN interface driver\n"; KERN_INFO "slcan: serial line CAN interface driver\n";
...@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl) ...@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl)
cf.data[i] |= tmp; cf.data[i] |= tmp;
} }
skb = dev_alloc_skb(sizeof(struct can_frame)); skb = dev_alloc_skb(sizeof(struct can_frame) +
sizeof(struct can_skb_priv));
if (!skb) if (!skb)
return; return;
...@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl) ...@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl)
skb->protocol = htons(ETH_P_CAN); skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_reserve(skb, sizeof(struct can_skb_priv));
((struct can_skb_priv *)(skb->head))->ifindex = sl->dev->ifindex;
memcpy(skb_put(skb, sizeof(struct can_frame)), memcpy(skb_put(skb, sizeof(struct can_frame)),
&cf, sizeof(struct can_frame)); &cf, sizeof(struct can_frame));
netif_rx_ni(skb); netif_rx_ni(skb);
......
config CAN_SOFTING config CAN_SOFTING
tristate "Softing Gmbh CAN generic support" tristate "Softing Gmbh CAN generic support"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
---help--- ---help---
Support for CAN cards from Softing Gmbh & some cards Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh. from Vector Gmbh.
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/platform/ti_hecc.h> #include <linux/can/platform/ti_hecc.h>
#define DRV_NAME "ti_hecc" #define DRV_NAME "ti_hecc"
...@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno) ...@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
spin_unlock_irqrestore(&priv->mbx_lock, flags); spin_unlock_irqrestore(&priv->mbx_lock, flags);
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
netif_receive_skb(skb); netif_receive_skb(skb);
stats->rx_packets++; stats->rx_packets++;
...@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id) ...@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
stats->tx_bytes += hecc_read_mbx(priv, mbxno, stats->tx_bytes += hecc_read_mbx(priv, mbxno,
HECC_CANMCF) & 0xF; HECC_CANMCF) & 0xF;
stats->tx_packets++; stats->tx_packets++;
can_led_event(ndev, CAN_LED_EVENT_TX);
can_get_echo_skb(ndev, mbxno); can_get_echo_skb(ndev, mbxno);
--priv->tx_tail; --priv->tx_tail;
} }
...@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev) ...@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev)
return err; return err;
} }
can_led_event(ndev, CAN_LED_EVENT_OPEN);
ti_hecc_start(ndev); ti_hecc_start(ndev);
napi_enable(&priv->napi); napi_enable(&priv->napi);
netif_start_queue(ndev); netif_start_queue(ndev);
...@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev) ...@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev)
close_candev(ndev); close_candev(ndev);
ti_hecc_transceiver_switch(priv, 0); ti_hecc_transceiver_switch(priv, 0);
can_led_event(ndev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register_candev() failed\n"); dev_err(&pdev->dev, "register_candev() failed\n");
goto probe_exit_clk; goto probe_exit_clk;
} }
devm_can_led_init(ndev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->base, (u32) ndev->irq); priv->base, (u32) ndev->irq);
......
menu "CAN USB interfaces" menu "CAN USB interfaces"
depends on USB && CAN_DEV depends on USB
config CAN_EMS_USB config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface" tristate "EMS CPC-USB/ARM7 CAN/USB interface"
...@@ -48,4 +48,10 @@ config CAN_PEAK_USB ...@@ -48,4 +48,10 @@ config CAN_PEAK_USB
This driver supports the PCAN-USB and PCAN-USB Pro adapters This driver supports the PCAN-USB and PCAN-USB Pro adapters
from PEAK-System Technik (http://www.peak-system.com). from PEAK-System Technik (http://www.peak-system.com).
config CAN_8DEV_USB
tristate "8 devices USB2CAN interface"
---help---
This driver supports the USB2CAN interface
from 8 devices (http://www.8devices.com).
endmenu endmenu
...@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o ...@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/ obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
/*
* CAN driver for "8 devices" USB2CAN converter
*
* Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program.
*
* This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c
* and drivers/net/can/usb/esd_usb2.c
*
* Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de)
* for testing and fixing this driver. Also many thanks to "8 devices",
* who were very cooperative and answered my questions.
*/
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
/* driver constants */
#define MAX_RX_URBS 20
#define MAX_TX_URBS 20
#define RX_BUFFER_SIZE 64
/* vendor and product id */
#define USB_8DEV_VENDOR_ID 0x0483
#define USB_8DEV_PRODUCT_ID 0x1234
/* endpoints */
enum usb_8dev_endpoint {
USB_8DEV_ENDP_DATA_RX = 1,
USB_8DEV_ENDP_DATA_TX,
USB_8DEV_ENDP_CMD_RX,
USB_8DEV_ENDP_CMD_TX
};
/* device CAN clock */
#define USB_8DEV_ABP_CLOCK 32000000
/* setup flags */
#define USB_8DEV_SILENT 0x01
#define USB_8DEV_LOOPBACK 0x02
#define USB_8DEV_DISABLE_AUTO_RESTRANS 0x04
#define USB_8DEV_STATUS_FRAME 0x08
/* commands */
enum usb_8dev_cmd {
USB_8DEV_RESET = 1,
USB_8DEV_OPEN,
USB_8DEV_CLOSE,
USB_8DEV_SET_SPEED,
USB_8DEV_SET_MASK_FILTER,
USB_8DEV_GET_STATUS,
USB_8DEV_GET_STATISTICS,
USB_8DEV_GET_SERIAL,
USB_8DEV_GET_SOFTW_VER,
USB_8DEV_GET_HARDW_VER,
USB_8DEV_RESET_TIMESTAMP,
USB_8DEV_GET_SOFTW_HARDW_VER
};
/* command options */
#define USB_8DEV_BAUD_MANUAL 0x09
#define USB_8DEV_CMD_START 0x11
#define USB_8DEV_CMD_END 0x22
#define USB_8DEV_CMD_SUCCESS 0
#define USB_8DEV_CMD_ERROR 255
#define USB_8DEV_CMD_TIMEOUT 1000
/* frames */
#define USB_8DEV_DATA_START 0x55
#define USB_8DEV_DATA_END 0xAA
#define USB_8DEV_TYPE_CAN_FRAME 0
#define USB_8DEV_TYPE_ERROR_FRAME 3
#define USB_8DEV_EXTID 0x01
#define USB_8DEV_RTR 0x02
#define USB_8DEV_ERR_FLAG 0x04
/* status */
#define USB_8DEV_STATUSMSG_OK 0x00 /* Normal condition. */
#define USB_8DEV_STATUSMSG_OVERRUN 0x01 /* Overrun occured when sending */
#define USB_8DEV_STATUSMSG_BUSLIGHT 0x02 /* Error counter has reached 96 */
#define USB_8DEV_STATUSMSG_BUSHEAVY 0x03 /* Error count. has reached 128 */
#define USB_8DEV_STATUSMSG_BUSOFF 0x04 /* Device is in BUSOFF */
#define USB_8DEV_STATUSMSG_STUFF 0x20 /* Stuff Error */
#define USB_8DEV_STATUSMSG_FORM 0x21 /* Form Error */
#define USB_8DEV_STATUSMSG_ACK 0x23 /* Ack Error */
#define USB_8DEV_STATUSMSG_BIT0 0x24 /* Bit1 Error */
#define USB_8DEV_STATUSMSG_BIT1 0x25 /* Bit0 Error */
#define USB_8DEV_STATUSMSG_CRC 0x27 /* CRC Error */
#define USB_8DEV_RP_MASK 0x7F /* Mask for Receive Error Bit */
/* table of devices that work with this driver */
static const struct usb_device_id usb_8dev_table[] = {
{ USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, usb_8dev_table);
struct usb_8dev_tx_urb_context {
struct usb_8dev_priv *priv;
u32 echo_index;
u8 dlc;
};
/* Structure to hold all of our device specific stuff */
struct usb_8dev_priv {
struct can_priv can; /* must be the first member */
struct sk_buff *echo_skb[MAX_TX_URBS];
struct usb_device *udev;
struct net_device *netdev;
atomic_t active_tx_urbs;
struct usb_anchor tx_submitted;
struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
struct usb_anchor rx_submitted;
struct can_berr_counter bec;
u8 *cmd_msg_buffer;
struct mutex usb_8dev_cmd_lock;
};
/* tx frame */
struct __packed usb_8dev_tx_msg {
u8 begin;
u8 flags; /* RTR and EXT_ID flag */
__be32 id; /* upper 3 bits not used */
u8 dlc; /* data length code 0-8 bytes */
u8 data[8]; /* 64-bit data */
u8 end;
};
/* rx frame */
struct __packed usb_8dev_rx_msg {
u8 begin;
u8 type; /* frame type */
u8 flags; /* RTR and EXT_ID flag */
__be32 id; /* upper 3 bits not used */
u8 dlc; /* data length code 0-8 bytes */
u8 data[8]; /* 64-bit data */
__be32 timestamp; /* 32-bit timestamp */
u8 end;
};
/* command frame */
struct __packed usb_8dev_cmd_msg {
u8 begin;
u8 channel; /* unkown - always 0 */
u8 command; /* command to execute */
u8 opt1; /* optional parameter / return value */
u8 opt2; /* optional parameter 2 */
u8 data[10]; /* optional parameter and data */
u8 end;
};
static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size)
{
int actual_length;
return usb_bulk_msg(priv->udev,
usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX),
msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT);
}
static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size,
int *actual_length)
{
return usb_bulk_msg(priv->udev,
usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX),
msg, size, actual_length, USB_8DEV_CMD_TIMEOUT);
}
/* Send command to device and receive result.
* Command was successful when opt1 = 0.
*/
static int usb_8dev_send_cmd(struct usb_8dev_priv *priv,
struct usb_8dev_cmd_msg *out,
struct usb_8dev_cmd_msg *in)
{
int err;
int num_bytes_read;
struct net_device *netdev;
netdev = priv->netdev;
out->begin = USB_8DEV_CMD_START;
out->end = USB_8DEV_CMD_END;
mutex_lock(&priv->usb_8dev_cmd_lock);
memcpy(priv->cmd_msg_buffer, out,
sizeof(struct usb_8dev_cmd_msg));
err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer,
sizeof(struct usb_8dev_cmd_msg));
if (err < 0) {
netdev_err(netdev, "sending command message failed\n");
goto failed;
}
err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer,
sizeof(struct usb_8dev_cmd_msg),
&num_bytes_read);
if (err < 0) {
netdev_err(netdev, "no command message answer\n");
goto failed;
}
memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg));
if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END ||
num_bytes_read != 16 || in->opt1 != 0)
err = -EPROTO;
failed:
mutex_unlock(&priv->usb_8dev_cmd_lock);
return err;
}
/* Send open command to device */
static int usb_8dev_cmd_open(struct usb_8dev_priv *priv)
{
struct can_bittiming *bt = &priv->can.bittiming;
struct usb_8dev_cmd_msg outmsg;
struct usb_8dev_cmd_msg inmsg;
u32 ctrlmode = priv->can.ctrlmode;
u32 flags = USB_8DEV_STATUS_FRAME;
__be32 beflags;
__be16 bebrp;
memset(&outmsg, 0, sizeof(outmsg));
outmsg.command = USB_8DEV_OPEN;
outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
outmsg.data[0] = bt->prop_seg + bt->phase_seg1;
outmsg.data[1] = bt->phase_seg2;
outmsg.data[2] = bt->sjw;
/* BRP */
bebrp = cpu_to_be16((u16)bt->brp);
memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
/* flags */
if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
flags |= USB_8DEV_LOOPBACK;
if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
flags |= USB_8DEV_SILENT;
if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
beflags = cpu_to_be32(flags);
memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
}
/* Send close command to device */
static int usb_8dev_cmd_close(struct usb_8dev_priv *priv)
{
struct usb_8dev_cmd_msg inmsg;
struct usb_8dev_cmd_msg outmsg = {
.channel = 0,
.command = USB_8DEV_CLOSE,
.opt1 = 0,
.opt2 = 0
};
return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
}
/* Get firmware and hardware version */
static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res)
{
struct usb_8dev_cmd_msg inmsg;
struct usb_8dev_cmd_msg outmsg = {
.channel = 0,
.command = USB_8DEV_GET_SOFTW_HARDW_VER,
.opt1 = 0,
.opt2 = 0
};
int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg);
if (err)
return err;
*res = be32_to_cpup((__be32 *)inmsg.data);
return err;
}
/* Set network device mode
*
* Maybe we should leave this function empty, because the device
* set mode variable with open command.
*/
static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode)
{
struct usb_8dev_priv *priv = netdev_priv(netdev);
int err = 0;
switch (mode) {
case CAN_MODE_START:
err = usb_8dev_cmd_open(priv);
if (err)
netdev_warn(netdev, "couldn't start device");
break;
default:
return -EOPNOTSUPP;
}
return err;
}
/* Read error/status frames */
static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
struct usb_8dev_rx_msg *msg)
{
struct can_frame *cf;
struct sk_buff *skb;
struct net_device_stats *stats = &priv->netdev->stats;
/* Error message:
* byte 0: Status
* byte 1: bit 7: Receive Passive
* byte 1: bit 0-6: Receive Error Counter
* byte 2: Transmit Error Counter
* byte 3: Always 0 (maybe reserved for future use)
*/
u8 state = msg->data[0];
u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
u8 txerr = msg->data[2];
int rx_errors = 0;
int tx_errors = 0;
skb = alloc_can_err_skb(priv->netdev, &cf);
if (!skb)
return;
switch (state) {
case USB_8DEV_STATUSMSG_OK:
priv->can.state = CAN_STATE_ERROR_ACTIVE;
cf->can_id |= CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_ACTIVE;
break;
case USB_8DEV_STATUSMSG_BUSOFF:
priv->can.state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
can_bus_off(priv->netdev);
break;
case USB_8DEV_STATUSMSG_OVERRUN:
case USB_8DEV_STATUSMSG_BUSLIGHT:
case USB_8DEV_STATUSMSG_BUSHEAVY:
cf->can_id |= CAN_ERR_CRTL;
break;
default:
priv->can.state = CAN_STATE_ERROR_WARNING;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
priv->can.can_stats.bus_error++;
break;
}
switch (state) {
case USB_8DEV_STATUSMSG_OK:
case USB_8DEV_STATUSMSG_BUSOFF:
break;
case USB_8DEV_STATUSMSG_ACK:
cf->can_id |= CAN_ERR_ACK;
tx_errors = 1;
break;
case USB_8DEV_STATUSMSG_CRC:
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
CAN_ERR_PROT_LOC_CRC_DEL;
rx_errors = 1;
break;
case USB_8DEV_STATUSMSG_BIT0:
cf->data[2] |= CAN_ERR_PROT_BIT0;
tx_errors = 1;
break;
case USB_8DEV_STATUSMSG_BIT1:
cf->data[2] |= CAN_ERR_PROT_BIT1;
tx_errors = 1;
break;
case USB_8DEV_STATUSMSG_FORM:
cf->data[2] |= CAN_ERR_PROT_FORM;
rx_errors = 1;
break;
case USB_8DEV_STATUSMSG_STUFF:
cf->data[2] |= CAN_ERR_PROT_STUFF;
rx_errors = 1;
break;
case USB_8DEV_STATUSMSG_OVERRUN:
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
rx_errors = 1;
break;
case USB_8DEV_STATUSMSG_BUSLIGHT:
priv->can.state = CAN_STATE_ERROR_WARNING;
cf->data[1] = (txerr > rxerr) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
priv->can.can_stats.error_warning++;
break;
case USB_8DEV_STATUSMSG_BUSHEAVY:
priv->can.state = CAN_STATE_ERROR_PASSIVE;
cf->data[1] = (txerr > rxerr) ?
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
priv->can.can_stats.error_passive++;
break;
default:
netdev_warn(priv->netdev,
"Unknown status/error message (%d)\n", state);
break;
}
if (tx_errors) {
cf->data[2] |= CAN_ERR_PROT_TX;
stats->tx_errors++;
}
if (rx_errors)
stats->rx_errors++;
cf->data[6] = txerr;
cf->data[7] = rxerr;
priv->bec.txerr = txerr;
priv->bec.rxerr = rxerr;
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
}
/* Read data and status frames */
static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
struct usb_8dev_rx_msg *msg)
{
struct can_frame *cf;
struct sk_buff *skb;
struct net_device_stats *stats = &priv->netdev->stats;
if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
msg->flags == USB_8DEV_ERR_FLAG) {
usb_8dev_rx_err_msg(priv, msg);
} else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
skb = alloc_can_skb(priv->netdev, &cf);
if (!skb)
return;
cf->can_id = be32_to_cpu(msg->id);
cf->can_dlc = get_can_dlc(msg->dlc & 0xF);
if (msg->flags & USB_8DEV_EXTID)
cf->can_id |= CAN_EFF_FLAG;
if (msg->flags & USB_8DEV_RTR)
cf->can_id |= CAN_RTR_FLAG;
else
memcpy(cf->data, msg->data, cf->can_dlc);
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
can_led_event(priv->netdev, CAN_LED_EVENT_RX);
} else {
netdev_warn(priv->netdev, "frame type %d unknown",
msg->type);
}
}
/* Callback for reading data from device
*
* Check urb status, call read function and resubmit urb read operation.
*/
static void usb_8dev_read_bulk_callback(struct urb *urb)
{
struct usb_8dev_priv *priv = urb->context;
struct net_device *netdev;
int retval;
int pos = 0;
netdev = priv->netdev;
if (!netif_device_present(netdev))
return;
switch (urb->status) {
case 0: /* success */
break;
case -ENOENT:
case -ESHUTDOWN:
return;
default:
netdev_info(netdev, "Rx URB aborted (%d)\n",
urb->status);
goto resubmit_urb;
}
while (pos < urb->actual_length) {
struct usb_8dev_rx_msg *msg;
if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) {
netdev_err(priv->netdev, "format error\n");
break;
}
msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos);
usb_8dev_rx_can_msg(priv, msg);
pos += sizeof(struct usb_8dev_rx_msg);
}
resubmit_urb:
usb_fill_bulk_urb(urb, priv->udev,
usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
urb->transfer_buffer, RX_BUFFER_SIZE,
usb_8dev_read_bulk_callback, priv);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval == -ENODEV)
netif_device_detach(netdev);
else if (retval)
netdev_err(netdev,
"failed resubmitting read bulk urb: %d\n", retval);
}
/* Callback handler for write operations
*
* Free allocated buffers, check transmit status and
* calculate statistic.
*/
static void usb_8dev_write_bulk_callback(struct urb *urb)
{
struct usb_8dev_tx_urb_context *context = urb->context;
struct usb_8dev_priv *priv;
struct net_device *netdev;
BUG_ON(!context);
priv = context->priv;
netdev = priv->netdev;
/* free up our allocated buffer */
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
atomic_dec(&priv->active_tx_urbs);
if (!netif_device_present(netdev))
return;
if (urb->status)
netdev_info(netdev, "Tx URB aborted (%d)\n",
urb->status);
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += context->dlc;
can_get_echo_skb(netdev, context->echo_index);
can_led_event(netdev, CAN_LED_EVENT_TX);
/* Release context */
context->echo_index = MAX_TX_URBS;
netif_wake_queue(netdev);
}
/* Send data to device */
static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct usb_8dev_priv *priv = netdev_priv(netdev);
struct net_device_stats *stats = &netdev->stats;
struct can_frame *cf = (struct can_frame *) skb->data;
struct usb_8dev_tx_msg *msg;
struct urb *urb;
struct usb_8dev_tx_urb_context *context = NULL;
u8 *buf;
int i, err;
size_t size = sizeof(struct usb_8dev_tx_msg);
if (can_dropped_invalid_skb(netdev, skb))
return NETDEV_TX_OK;
/* create a URB, and a buffer for it, and copy the data to the URB */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
netdev_err(netdev, "No memory left for URBs\n");
goto nomem;
}
buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC,
&urb->transfer_dma);
if (!buf) {
netdev_err(netdev, "No memory left for USB buffer\n");
goto nomembuf;
}
memset(buf, 0, size);
msg = (struct usb_8dev_tx_msg *)buf;
msg->begin = USB_8DEV_DATA_START;
msg->flags = 0x00;
if (cf->can_id & CAN_RTR_FLAG)
msg->flags |= USB_8DEV_RTR;
if (cf->can_id & CAN_EFF_FLAG)
msg->flags |= USB_8DEV_EXTID;
msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK);
msg->dlc = cf->can_dlc;
memcpy(msg->data, cf->data, cf->can_dlc);
msg->end = USB_8DEV_DATA_END;
for (i = 0; i < MAX_TX_URBS; i++) {
if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
context = &priv->tx_contexts[i];
break;
}
}
/* May never happen! When this happens we'd more URBs in flight as
* allowed (MAX_TX_URBS).
*/
if (!context)
goto nofreecontext;
context->priv = priv;
context->echo_index = i;
context->dlc = cf->can_dlc;
usb_fill_bulk_urb(urb, priv->udev,
usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX),
buf, size, usb_8dev_write_bulk_callback, context);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &priv->tx_submitted);
can_put_echo_skb(skb, netdev, context->echo_index);
atomic_inc(&priv->active_tx_urbs);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err))
goto failed;
else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
/* Slow down tx path */
netif_stop_queue(netdev);
/* Release our reference to this URB, the USB core will eventually free
* it entirely.
*/
usb_free_urb(urb);
return NETDEV_TX_OK;
nofreecontext:
usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
netdev_warn(netdev, "couldn't find free context");
return NETDEV_TX_BUSY;
failed:
can_free_echo_skb(netdev, context->echo_index);
usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
atomic_dec(&priv->active_tx_urbs);
if (err == -ENODEV)
netif_device_detach(netdev);
else
netdev_warn(netdev, "failed tx_urb %d\n", err);
nomembuf:
usb_free_urb(urb);
nomem:
dev_kfree_skb(skb);
stats->tx_dropped++;
return NETDEV_TX_OK;
}
static int usb_8dev_get_berr_counter(const struct net_device *netdev,
struct can_berr_counter *bec)
{
struct usb_8dev_priv *priv = netdev_priv(netdev);
bec->txerr = priv->bec.txerr;
bec->rxerr = priv->bec.rxerr;
return 0;
}
/* Start USB device */
static int usb_8dev_start(struct usb_8dev_priv *priv)
{
struct net_device *netdev = priv->netdev;
int err, i;
for (i = 0; i < MAX_RX_URBS; i++) {
struct urb *urb = NULL;
u8 *buf;
/* create a URB, and a buffer for it */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
netdev_err(netdev, "No memory left for URBs\n");
err = -ENOMEM;
break;
}
buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
&urb->transfer_dma);
if (!buf) {
netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
err = -ENOMEM;
break;
}
usb_fill_bulk_urb(urb, priv->udev,
usb_rcvbulkpipe(priv->udev,
USB_8DEV_ENDP_DATA_RX),
buf, RX_BUFFER_SIZE,
usb_8dev_read_bulk_callback, priv);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &priv->rx_submitted);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
urb->transfer_dma);
break;
}
/* Drop reference, USB core will take care of freeing it */
usb_free_urb(urb);
}
/* Did we submit any URBs */
if (i == 0) {
netdev_warn(netdev, "couldn't setup read URBs\n");
return err;
}
/* Warn if we've couldn't transmit all the URBs */
if (i < MAX_RX_URBS)
netdev_warn(netdev, "rx performance may be slow\n");
err = usb_8dev_cmd_open(priv);
if (err)
goto failed;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
failed:
if (err == -ENODEV)
netif_device_detach(priv->netdev);
netdev_warn(netdev, "couldn't submit control: %d\n", err);
return err;
}
/* Open USB device */
static int usb_8dev_open(struct net_device *netdev)
{
struct usb_8dev_priv *priv = netdev_priv(netdev);
int err;
/* common open */
err = open_candev(netdev);
if (err)
return err;
can_led_event(netdev, CAN_LED_EVENT_OPEN);
/* finally start device */
err = usb_8dev_start(priv);
if (err) {
if (err == -ENODEV)
netif_device_detach(priv->netdev);
netdev_warn(netdev, "couldn't start device: %d\n",
err);
close_candev(netdev);
return err;
}
netif_start_queue(netdev);
return 0;
}
static void unlink_all_urbs(struct usb_8dev_priv *priv)
{
int i;
usb_kill_anchored_urbs(&priv->rx_submitted);
usb_kill_anchored_urbs(&priv->tx_submitted);
atomic_set(&priv->active_tx_urbs, 0);
for (i = 0; i < MAX_TX_URBS; i++)
priv->tx_contexts[i].echo_index = MAX_TX_URBS;
}
/* Close USB device */
static int usb_8dev_close(struct net_device *netdev)
{
struct usb_8dev_priv *priv = netdev_priv(netdev);
int err = 0;
/* Send CLOSE command to CAN controller */
err = usb_8dev_cmd_close(priv);
if (err)
netdev_warn(netdev, "couldn't stop device");
priv->can.state = CAN_STATE_STOPPED;
netif_stop_queue(netdev);
/* Stop polling */
unlink_all_urbs(priv);
close_candev(netdev);
can_led_event(netdev, CAN_LED_EVENT_STOP);
return err;
}
static const struct net_device_ops usb_8dev_netdev_ops = {
.ndo_open = usb_8dev_open,
.ndo_stop = usb_8dev_close,
.ndo_start_xmit = usb_8dev_start_xmit,
};
static const struct can_bittiming_const usb_8dev_bittiming_const = {
.name = "usb_8dev",
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 1024,
.brp_inc = 1,
};
/* Probe USB device
*
* Check device and firmware.
* Set supported modes and bittiming constants.
* Allocate some memory.
*/
static int usb_8dev_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct net_device *netdev;
struct usb_8dev_priv *priv;
int i, err = -ENOMEM;
u32 version;
char buf[18];
struct usb_device *usbdev = interface_to_usbdev(intf);
/* product id looks strange, better we also check iProduct string */
if (usb_string(usbdev, usbdev->descriptor.iProduct, buf,
sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) {
dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n");
return -ENODEV;
}
netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS);
if (!netdev) {
dev_err(&intf->dev, "Couldn't alloc candev\n");
return -ENOMEM;
}
priv = netdev_priv(netdev);
priv->udev = usbdev;
priv->netdev = netdev;
priv->can.state = CAN_STATE_STOPPED;
priv->can.clock.freq = USB_8DEV_ABP_CLOCK;
priv->can.bittiming_const = &usb_8dev_bittiming_const;
priv->can.do_set_mode = usb_8dev_set_mode;
priv->can.do_get_berr_counter = usb_8dev_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_ONE_SHOT;
netdev->netdev_ops = &usb_8dev_netdev_ops;
netdev->flags |= IFF_ECHO; /* we support local echo */
init_usb_anchor(&priv->rx_submitted);
init_usb_anchor(&priv->tx_submitted);
atomic_set(&priv->active_tx_urbs, 0);
for (i = 0; i < MAX_TX_URBS; i++)
priv->tx_contexts[i].echo_index = MAX_TX_URBS;
priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
GFP_KERNEL);
if (!priv->cmd_msg_buffer) {
netdev_err(netdev, "Couldn't alloc Tx buffer\n");
goto cleanup_candev;
}
usb_set_intfdata(intf, priv);
SET_NETDEV_DEV(netdev, &intf->dev);
mutex_init(&priv->usb_8dev_cmd_lock);
err = register_candev(netdev);
if (err) {
netdev_err(netdev,
"couldn't register CAN device: %d\n", err);
goto cleanup_cmd_msg_buffer;
}
err = usb_8dev_cmd_version(priv, &version);
if (err) {
netdev_err(netdev, "can't get firmware version\n");
goto cleanup_cmd_msg_buffer;
} else {
netdev_info(netdev,
"firmware: %d.%d, hardware: %d.%d\n",
(version>>24) & 0xff, (version>>16) & 0xff,
(version>>8) & 0xff, version & 0xff);
}
devm_can_led_init(netdev);
return 0;
cleanup_cmd_msg_buffer:
kfree(priv->cmd_msg_buffer);
cleanup_candev:
free_candev(netdev);
return err;
}
/* Called by the usb core when driver is unloaded or device is removed */
static void usb_8dev_disconnect(struct usb_interface *intf)
{
struct usb_8dev_priv *priv = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (priv) {
netdev_info(priv->netdev, "device disconnected\n");
unregister_netdev(priv->netdev);
free_candev(priv->netdev);
unlink_all_urbs(priv);
}
}
static struct usb_driver usb_8dev_driver = {
.name = "usb_8dev",
.probe = usb_8dev_probe,
.disconnect = usb_8dev_disconnect,
.id_table = usb_8dev_table,
};
module_usb_driver(usb_8dev_driver);
MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>");
MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces");
MODULE_LICENSE("GPL v2");
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/netlink.h> #include <linux/can/netlink.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
/* /*
* CAN mode * CAN mode
...@@ -52,6 +53,13 @@ struct can_priv { ...@@ -52,6 +53,13 @@ struct can_priv {
unsigned int echo_skb_max; unsigned int echo_skb_max;
struct sk_buff **echo_skb; struct sk_buff **echo_skb;
#ifdef CONFIG_CAN_LEDS
struct led_trigger *tx_led_trig;
char tx_led_trig_name[CAN_LED_NAME_SZ];
struct led_trigger *rx_led_trig;
char rx_led_trig_name[CAN_LED_NAME_SZ];
#endif
}; };
/* /*
...@@ -98,6 +106,9 @@ u8 can_len2dlc(u8 len); ...@@ -98,6 +106,9 @@ u8 can_len2dlc(u8 len);
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max); struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
void free_candev(struct net_device *dev); void free_candev(struct net_device *dev);
/* a candev safe wrapper around netdev_priv */
struct can_priv *safe_candev_priv(struct net_device *dev);
int open_candev(struct net_device *dev); int open_candev(struct net_device *dev);
void close_candev(struct net_device *dev); void close_candev(struct net_device *dev);
......
/*
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef CAN_LED_H
#define CAN_LED_H
#include <linux/if.h>
#include <linux/leds.h>
enum can_led_event {
CAN_LED_EVENT_OPEN,
CAN_LED_EVENT_STOP,
CAN_LED_EVENT_TX,
CAN_LED_EVENT_RX,
};
#ifdef CONFIG_CAN_LEDS
/* keep space for interface name + "-tx"/"-rx" suffix and null terminator */
#define CAN_LED_NAME_SZ (IFNAMSIZ + 4)
void can_led_event(struct net_device *netdev, enum can_led_event event);
void devm_can_led_init(struct net_device *netdev);
int __init can_led_notifier_init(void);
void __exit can_led_notifier_exit(void);
#else
static inline void can_led_event(struct net_device *netdev,
enum can_led_event event)
{
}
static inline void devm_can_led_init(struct net_device *netdev)
{
}
static inline int can_led_notifier_init(void)
{
return 0;
}
static inline void can_led_notifier_exit(void)
{
}
#endif
#endif
/*
* linux/can/skb.h
*
* Definitions for the CAN network socket buffer
*
* Copyright (C) 2012 Oliver Hartkopp <socketcan@hartkopp.net>
*
*/
#ifndef CAN_SKB_H
#define CAN_SKB_H
#include <linux/types.h>
#include <linux/can.h>
/*
* The struct can_skb_priv is used to transport additional information along
* with the stored struct can(fd)_frame that can not be contained in existing
* struct sk_buff elements.
* N.B. that this information must not be modified in cloned CAN sk_buffs.
* To modify the CAN frame content or the struct can_skb_priv content
* skb_copy() needs to be used instead of skb_clone().
*/
/**
* struct can_skb_priv - private additional data inside CAN sk_buffs
* @ifindex: ifindex of the first interface the CAN frame appeared on
* @cf: align to the following CAN frame at skb->data
*/
struct can_skb_priv {
int ifindex;
struct can_frame cf[0];
};
#endif /* CAN_SKB_H */
...@@ -44,6 +44,7 @@ enum { ...@@ -44,6 +44,7 @@ enum {
CGW_SRC_IF, /* ifindex of source network interface */ CGW_SRC_IF, /* ifindex of source network interface */
CGW_DST_IF, /* ifindex of destination network interface */ CGW_DST_IF, /* ifindex of destination network interface */
CGW_FILTER, /* specify struct can_filter on source CAN device */ CGW_FILTER, /* specify struct can_filter on source CAN device */
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
__CGW_MAX __CGW_MAX
}; };
...@@ -51,6 +52,7 @@ enum { ...@@ -51,6 +52,7 @@ enum {
#define CGW_FLAGS_CAN_ECHO 0x01 #define CGW_FLAGS_CAN_ECHO 0x01
#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02 #define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */ #define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
......
...@@ -16,10 +16,11 @@ menuconfig CAN ...@@ -16,10 +16,11 @@ menuconfig CAN
If you want CAN support you should say Y here and also to the If you want CAN support you should say Y here and also to the
specific driver for your controller(s) below. specific driver for your controller(s) below.
if CAN
config CAN_RAW config CAN_RAW
tristate "Raw CAN Protocol (raw access with CAN-ID filtering)" tristate "Raw CAN Protocol (raw access with CAN-ID filtering)"
depends on CAN default y
default N
---help--- ---help---
The raw CAN protocol option offers access to the CAN bus via The raw CAN protocol option offers access to the CAN bus via
the BSD socket API. You probably want to use the raw socket in the BSD socket API. You probably want to use the raw socket in
...@@ -29,8 +30,7 @@ config CAN_RAW ...@@ -29,8 +30,7 @@ config CAN_RAW
config CAN_BCM config CAN_BCM
tristate "Broadcast Manager CAN Protocol (with content filtering)" tristate "Broadcast Manager CAN Protocol (with content filtering)"
depends on CAN default y
default N
---help--- ---help---
The Broadcast Manager offers content filtering, timeout monitoring, The Broadcast Manager offers content filtering, timeout monitoring,
sending of RTR frames, and cyclic CAN messages without permanent user sending of RTR frames, and cyclic CAN messages without permanent user
...@@ -42,8 +42,7 @@ config CAN_BCM ...@@ -42,8 +42,7 @@ config CAN_BCM
config CAN_GW config CAN_GW
tristate "CAN Gateway/Router (with netlink configuration)" tristate "CAN Gateway/Router (with netlink configuration)"
depends on CAN default y
default N
---help--- ---help---
The CAN Gateway/Router is used to route (and modify) CAN frames. The CAN Gateway/Router is used to route (and modify) CAN frames.
It is based on the PF_CAN core infrastructure for msg filtering and It is based on the PF_CAN core infrastructure for msg filtering and
...@@ -53,3 +52,5 @@ config CAN_GW ...@@ -53,3 +52,5 @@ config CAN_GW
by the netlink configuration interface known e.g. from iptables. by the netlink configuration interface known e.g. from iptables.
source "drivers/net/can/Kconfig" source "drivers/net/can/Kconfig"
endif
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/bcm.h> #include <linux/can/bcm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op) ...@@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op)
return; return;
} }
skb = alloc_skb(CFSIZ, gfp_any()); skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), gfp_any());
if (!skb) if (!skb)
goto out; goto out;
skb_reserve(skb, sizeof(struct can_skb_priv));
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
memcpy(skb_put(skb, CFSIZ), cf, CFSIZ); memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);
/* send with loopback */ /* send with loopback */
...@@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) ...@@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
if (!ifindex) if (!ifindex)
return -ENODEV; return -ENODEV;
skb = alloc_skb(CFSIZ, GFP_KERNEL); skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), GFP_KERNEL);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
skb_reserve(skb, sizeof(struct can_skb_priv));
err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ); err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
...@@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) ...@@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
return -ENODEV; return -ENODEV;
} }
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
skb->dev = dev; skb->dev = dev;
skb->sk = sk; skb->sk = sk;
err = can_send(skb, 1); /* send with loopback */ err = can_send(skb, 1); /* send with loopback */
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
...@@ -52,19 +53,31 @@ ...@@ -52,19 +53,31 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/gw.h> #include <linux/can/gw.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
#define CAN_GW_VERSION "20101209" #define CAN_GW_VERSION "20130117"
static __initconst const char banner[] = #define CAN_GW_NAME "can-gw"
KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
MODULE_DESCRIPTION("PF_CAN netlink gateway"); MODULE_DESCRIPTION("PF_CAN netlink gateway");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
MODULE_ALIAS("can-gw"); MODULE_ALIAS(CAN_GW_NAME);
#define CGW_MIN_HOPS 1
#define CGW_MAX_HOPS 6
#define CGW_DEFAULT_HOPS 1
static unsigned int max_hops __read_mostly = CGW_DEFAULT_HOPS;
module_param(max_hops, uint, S_IRUGO);
MODULE_PARM_DESC(max_hops,
"maximum " CAN_GW_NAME " routing hops for CAN frames "
"(valid values: " __stringify(CGW_MIN_HOPS) "-"
__stringify(CGW_MAX_HOPS) " hops, "
"default: " __stringify(CGW_DEFAULT_HOPS) ")");
static HLIST_HEAD(cgw_list); static HLIST_HEAD(cgw_list);
static struct notifier_block notifier; static struct notifier_block notifier;
...@@ -118,6 +131,7 @@ struct cgw_job { ...@@ -118,6 +131,7 @@ struct cgw_job {
struct rcu_head rcu; struct rcu_head rcu;
u32 handled_frames; u32 handled_frames;
u32 dropped_frames; u32 dropped_frames;
u32 deleted_frames;
struct cf_mod mod; struct cf_mod mod;
union { union {
/* CAN frame data source */ /* CAN frame data source */
...@@ -338,15 +352,40 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) ...@@ -338,15 +352,40 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
struct sk_buff *nskb; struct sk_buff *nskb;
int modidx = 0; int modidx = 0;
/* do not handle already routed frames - see comment below */ /*
if (skb_mac_header_was_set(skb)) * Do not handle CAN frames routed more than 'max_hops' times.
* In general we should never catch this delimiter which is intended
* to cover a misconfiguration protection (e.g. circular CAN routes).
*
* The Controller Area Network controllers only accept CAN frames with
* correct CRCs - which are not visible in the controller registers.
* According to skbuff.h documentation the csum_start element for IP
* checksums is undefined/unsued when ip_summed == CHECKSUM_UNNECESSARY.
* Only CAN skbs can be processed here which already have this property.
*/
#define cgw_hops(skb) ((skb)->csum_start)
BUG_ON(skb->ip_summed != CHECKSUM_UNNECESSARY);
if (cgw_hops(skb) >= max_hops) {
/* indicate deleted frames due to misconfiguration */
gwj->deleted_frames++;
return; return;
}
if (!(gwj->dst.dev->flags & IFF_UP)) { if (!(gwj->dst.dev->flags & IFF_UP)) {
gwj->dropped_frames++; gwj->dropped_frames++;
return; return;
} }
/* is sending the skb back to the incoming interface not allowed? */
if (!(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK) &&
skb_headroom(skb) == sizeof(struct can_skb_priv) &&
(((struct can_skb_priv *)(skb->head))->ifindex ==
gwj->dst.dev->ifindex))
return;
/* /*
* clone the given skb, which has not been done in can_rcv() * clone the given skb, which has not been done in can_rcv()
* *
...@@ -363,15 +402,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) ...@@ -363,15 +402,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
return; return;
} }
/* /* put the incremented hop counter in the cloned skb */
* Mark routed frames by setting some mac header length which is cgw_hops(nskb) = cgw_hops(skb) + 1;
* not relevant for the CAN frames located in the skb->data section.
*
* As dev->header_ops is not set in CAN netdevices no one is ever
* accessing the various header offsets in the CAN skbuffs anyway.
* E.g. using the packet socket to read CAN frames is still working.
*/
skb_set_mac_header(nskb, 8);
nskb->dev = gwj->dst.dev; nskb->dev = gwj->dst.dev;
/* pointer to modifiable CAN frame */ /* pointer to modifiable CAN frame */
...@@ -472,6 +504,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, ...@@ -472,6 +504,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
goto cancel; goto cancel;
} }
if (gwj->deleted_frames) {
if (nla_put_u32(skb, CGW_DELETED, gwj->deleted_frames) < 0)
goto cancel;
}
/* check non default settings of attributes */ /* check non default settings of attributes */
if (gwj->mod.modtype.and) { if (gwj->mod.modtype.and) {
...@@ -771,6 +808,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -771,6 +808,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
gwj->handled_frames = 0; gwj->handled_frames = 0;
gwj->dropped_frames = 0; gwj->dropped_frames = 0;
gwj->deleted_frames = 0;
gwj->flags = r->flags; gwj->flags = r->flags;
gwj->gwtype = r->gwtype; gwj->gwtype = r->gwtype;
...@@ -895,7 +933,11 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -895,7 +933,11 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
static __init int cgw_module_init(void) static __init int cgw_module_init(void)
{ {
printk(banner); /* sanitize given module parameter */
max_hops = clamp_t(unsigned int, max_hops, CGW_MIN_HOPS, CGW_MAX_HOPS);
pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
max_hops);
cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
0, 0, NULL); 0, 0, NULL);
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/raw.h> #include <linux/can/raw.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
...@@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
if (!dev) if (!dev)
return -ENXIO; return -ENXIO;
skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
&err); msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) if (!skb)
goto put_dev; goto put_dev;
skb_reserve(skb, sizeof(struct can_skb_priv));
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0) if (err < 0)
goto free_skb; goto free_skb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment