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"
depends on CAN
config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)"
depends on CAN
---help---
Similar to the network loopback devices, vcan offers a
virtual local CAN interface.
......@@ -13,7 +11,6 @@ config CAN_VCAN
config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on CAN
---help---
CAN driver for several 'low cost' CAN interfaces that are attached
via serial lines or via USB-to-serial adapters using the LAWICEL
......@@ -33,16 +30,16 @@ config CAN_SLCAN
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
depends on CAN
default y
---help---
Enables the common framework for platform CAN drivers with Netlink
support. This is the standard library for CAN drivers.
If unsure, say Y.
if CAN_DEV
config CAN_CALC_BITTIMING
bool "CAN bit-timing calculation"
depends on CAN_DEV
default y
---help---
If enabled, CAN bit-timing parameters will be calculated for the
......@@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
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
tristate "Atmel AT91 onchip CAN controller"
depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors.
config CAN_TI_HECC
depends on CAN_DEV && ARCH_OMAP3
depends on ARCH_OMAP3
tristate "TI High End CAN Controller"
---help---
Driver for TI HECC (High End CAN Controller) module found on many
......@@ -70,12 +78,12 @@ config CAN_TI_HECC
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on CAN_DEV && SPI && HAS_DMA
depends on SPI && HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
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"
---help---
Driver for the Analog Devices Blackfin on-chip CAN controllers
......@@ -85,7 +93,7 @@ config CAN_BFIN
config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
depends on CAN_DEV && MFD_JANZ_CMODIO
depends on MFD_JANZ_CMODIO
---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board.
......@@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
depends on CAN_DEV && HAVE_CAN_FLEXCAN
depends on HAVE_CAN_FLEXCAN
---help---
Say Y here if you want to support for Freescale FlexCAN.
config PCH_CAN
tristate "Intel EG20T PCH CAN controller"
depends on CAN_DEV && PCI
depends on PCI
---help---
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
is an IOH for x86 embedded processor (Intel Atom E6xx series).
......@@ -112,7 +120,7 @@ config PCH_CAN
config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on CAN_DEV && OF
depends on OF
---help---
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little
......@@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"
endif
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
depends on CAN
---help---
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
......
......@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += usb/
obj-y += softing/
......
......@@ -37,6 +37,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#define AT91_MB_MASK(i) ((1 << (i)) - 1)
......@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
stats->rx_packets++;
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)
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
dev->stats.tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
}
}
......@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev)
goto out_close;
}
can_led_event(dev, CAN_LED_EVENT_OPEN);
/* start chip and queuing */
at91_chip_start(dev);
napi_enable(&priv->napi);
......@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev)
close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
......@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev)
goto exit_free;
}
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->reg_base, dev->irq);
......
menuconfig CAN_C_CAN
tristate "Bosch C_CAN/D_CAN devices"
depends on CAN_DEV && HAS_IOMEM
depends on HAS_IOMEM
if CAN_C_CAN
......
......@@ -39,6 +39,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include "c_can.h"
......@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
return 0;
}
......@@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev)
C_CAN_IFACE(MSGCTRL_REG, 0))
& IF_MCONT_DLC_MASK;
stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
c_can_inval_msg_object(dev, 0, msg_obj_no);
} else {
break;
......@@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev)
napi_enable(&priv->napi);
can_led_event(dev, CAN_LED_EVENT_OPEN);
/* start the c_can controller */
c_can_start(dev);
......@@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev)
c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
......@@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev)
err = register_candev(dev);
if (err)
c_can_pm_runtime_disable(priv);
else
devm_can_led_init(dev);
return err;
}
......
menuconfig CAN_CC770
tristate "Bosch CC770 and Intel AN82527 devices"
depends on CAN_DEV && HAS_IOMEM
depends on HAS_IOMEM
if CAN_CC770
......
......@@ -24,7 +24,9 @@
#include <linux/if_arp.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/can/netlink.h>
#include <linux/can/led.h>
#include <net/rtnetlink.h>
#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)
{
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))
return NULL;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
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));
memset(*cf, 0, sizeof(struct can_frame));
......@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev)
}
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)
{
int err;
can_led_notifier_init();
err = rtnl_link_register(&can_link_ops);
if (!err)
printk(KERN_INFO MOD_DESC "\n");
......@@ -809,6 +831,8 @@ module_init(can_dev_init);
static __exit void can_dev_exit(void)
{
rtnl_link_unregister(&can_link_ops);
can_led_notifier_exit();
}
module_exit(can_dev_exit);
......
......@@ -23,6 +23,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/platform/flexcan.h>
#include <linux/clk.h>
#include <linux/delay.h>
......@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
return 1;
}
......@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
stats->tx_bytes += can_get_echo_skb(dev, 0);
stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev);
}
......@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev)
err = flexcan_chip_start(dev);
if (err)
goto out_close;
can_led_event(dev, CAN_LED_EVENT_OPEN);
napi_enable(&priv->napi);
netif_start_queue(dev);
......@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev)
close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
......@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev)
goto failed_register;
}
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
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 @@
#include <linux/can/core.h>
#include <linux/can/dev.h>
#include <linux/can/led.h>
#include <linux/can/platform/mcp251x.h>
#include <linux/completion.h>
#include <linux/delay.h>
......@@ -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_bytes += frame->can_dlc;
can_led_event(priv->net, CAN_LED_EVENT_RX);
netif_rx_ni(skb);
}
......@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net)
mutex_unlock(&priv->mcp_lock);
can_led_event(net, CAN_LED_EVENT_STOP);
return 0;
}
......@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf & CANINTF_TX) {
net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1;
can_led_event(net, CAN_LED_EVENT_TX);
if (priv->tx_len) {
can_get_echo_skb(net, 0);
priv->tx_len = 0;
......@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net)
mcp251x_open_clean(net);
goto open_unlock;
}
can_led_event(net, CAN_LED_EVENT_OPEN);
netif_wake_queue(net);
open_unlock:
......@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
pdata->transceiver_enable(0);
ret = register_candev(net);
if (!ret) {
if (ret)
goto error_probe;
devm_can_led_init(net);
dev_info(&spi->dev, "probed\n");
return ret;
}
error_probe:
if (!mcp251x_enable_dma)
kfree(priv->spi_rx_buf);
......
config CAN_MSCAN
depends on CAN_DEV && (PPC || M68K)
depends on PPC || M68K
tristate "Support for Freescale MSCAN based chips"
---help---
The Motorola Scalable Controller Area Network (MSCAN) definition
......
menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices"
depends on CAN_DEV && HAS_IOMEM
depends on HAS_IOMEM
if CAN_SJA1000
......
......@@ -60,6 +60,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include "sja1000.h"
......@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
stats->rx_packets++;
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)
......@@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
can_get_echo_skb(dev, 0);
}
netif_wake_queue(dev);
can_led_event(dev, CAN_LED_EVENT_TX);
}
if (isrc & IRQ_RI) {
/* receive interrupt */
......@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev)
/* init and start chi */
sja1000_start(dev);
can_led_event(dev, CAN_LED_EVENT_OPEN);
netif_start_queue(dev);
return 0;
......@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev)
close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
......@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = {
int register_sja1000dev(struct net_device *dev)
{
int ret;
if (!sja1000_probe_chip(dev))
return -ENODEV;
......@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev)
set_reset_mode(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);
......
......@@ -55,6 +55,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/can.h>
#include <linux/can/skb.h>
static __initconst const char banner[] =
KERN_INFO "slcan: serial line CAN interface driver\n";
......@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl)
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)
return;
......@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl)
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
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)),
&cf, sizeof(struct can_frame));
netif_rx_ni(skb);
......
config CAN_SOFTING
tristate "Softing Gmbh CAN generic support"
depends on CAN_DEV && HAS_IOMEM
depends on HAS_IOMEM
---help---
Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh.
......
......@@ -50,6 +50,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/platform/ti_hecc.h>
#define DRV_NAME "ti_hecc"
......@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
stats->rx_bytes += cf->can_dlc;
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
netif_receive_skb(skb);
stats->rx_packets++;
......@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
stats->tx_bytes += hecc_read_mbx(priv, mbxno,
HECC_CANMCF) & 0xF;
stats->tx_packets++;
can_led_event(ndev, CAN_LED_EVENT_TX);
can_get_echo_skb(ndev, mbxno);
--priv->tx_tail;
}
......@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev)
return err;
}
can_led_event(ndev, CAN_LED_EVENT_OPEN);
ti_hecc_start(ndev);
napi_enable(&priv->napi);
netif_start_queue(ndev);
......@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev)
close_candev(ndev);
ti_hecc_transceiver_switch(priv, 0);
can_led_event(ndev, CAN_LED_EVENT_STOP);
return 0;
}
......@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register_candev() failed\n");
goto probe_exit_clk;
}
devm_can_led_init(ndev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->base, (u32) ndev->irq);
......
menu "CAN USB interfaces"
depends on USB && CAN_DEV
depends on USB
config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
......@@ -48,4 +48,10 @@ config CAN_PEAK_USB
This driver supports the PCAN-USB and PCAN-USB Pro adapters
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
......@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
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 @@
#include <linux/can.h>
#include <linux/can/netlink.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
/*
* CAN mode
......@@ -52,6 +53,13 @@ struct can_priv {
unsigned int echo_skb_max;
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);
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
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);
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 {
CGW_SRC_IF, /* ifindex of source network interface */
CGW_DST_IF, /* ifindex of destination network interface */
CGW_FILTER, /* specify struct can_filter on source CAN device */
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
__CGW_MAX
};
......@@ -51,6 +52,7 @@ enum {
#define CGW_FLAGS_CAN_ECHO 0x01
#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
......
......@@ -16,10 +16,11 @@ menuconfig CAN
If you want CAN support you should say Y here and also to the
specific driver for your controller(s) below.
if CAN
config CAN_RAW
tristate "Raw CAN Protocol (raw access with CAN-ID filtering)"
depends on CAN
default N
default y
---help---
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
......@@ -29,8 +30,7 @@ config CAN_RAW
config CAN_BCM
tristate "Broadcast Manager CAN Protocol (with content filtering)"
depends on CAN
default N
default y
---help---
The Broadcast Manager offers content filtering, timeout monitoring,
sending of RTR frames, and cyclic CAN messages without permanent user
......@@ -42,8 +42,7 @@ config CAN_BCM
config CAN_GW
tristate "CAN Gateway/Router (with netlink configuration)"
depends on CAN
default N
default y
---help---
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
......@@ -53,3 +52,5 @@ config CAN_GW
by the netlink configuration interface known e.g. from iptables.
source "drivers/net/can/Kconfig"
endif
......@@ -54,6 +54,7 @@
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/bcm.h>
#include <linux/slab.h>
#include <net/sock.h>
......@@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op)
return;
}
skb = alloc_skb(CFSIZ, gfp_any());
skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), gfp_any());
if (!skb)
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);
/* send with loopback */
......@@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
if (!ifindex)
return -ENODEV;
skb = alloc_skb(CFSIZ, GFP_KERNEL);
skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, sizeof(struct can_skb_priv));
err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ);
if (err < 0) {
kfree_skb(skb);
......@@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
return -ENODEV;
}
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
skb->dev = dev;
skb->sk = sk;
err = can_send(skb, 1); /* send with loopback */
......
......@@ -42,6 +42,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
......@@ -52,19 +53,31 @@
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/gw.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#define CAN_GW_VERSION "20101209"
static __initconst const char banner[] =
KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
#define CAN_GW_VERSION "20130117"
#define CAN_GW_NAME "can-gw"
MODULE_DESCRIPTION("PF_CAN netlink gateway");
MODULE_LICENSE("Dual BSD/GPL");
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 struct notifier_block notifier;
......@@ -118,6 +131,7 @@ struct cgw_job {
struct rcu_head rcu;
u32 handled_frames;
u32 dropped_frames;
u32 deleted_frames;
struct cf_mod mod;
union {
/* CAN frame data source */
......@@ -338,15 +352,40 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
struct sk_buff *nskb;
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;
}
if (!(gwj->dst.dev->flags & IFF_UP)) {
gwj->dropped_frames++;
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()
*
......@@ -363,15 +402,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
return;
}
/*
* Mark routed frames by setting some mac header length which is
* 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);
/* put the incremented hop counter in the cloned skb */
cgw_hops(nskb) = cgw_hops(skb) + 1;
nskb->dev = gwj->dst.dev;
/* pointer to modifiable CAN frame */
......@@ -472,6 +504,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
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 */
if (gwj->mod.modtype.and) {
......@@ -771,6 +808,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
gwj->handled_frames = 0;
gwj->dropped_frames = 0;
gwj->deleted_frames = 0;
gwj->flags = r->flags;
gwj->gwtype = r->gwtype;
......@@ -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)
{
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),
0, 0, NULL);
......
......@@ -50,6 +50,7 @@
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/raw.h>
#include <net/sock.h>
#include <net/net_namespace.h>
......@@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
if (!dev)
return -ENXIO;
skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
&err);
skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
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);
if (err < 0)
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