Skip to content

Commit c4e54b0

Browse files
passgatmarckleinebudde
authored andcommitted
can: slcan: use CAN network device driver API
As suggested by commit [1], now the driver uses the functions and the data structures provided by the CAN network device driver interface. Currently the driver doesn't implement a way to set bitrate for SLCAN based devices via ip tool, so you'll have to do this by slcand or slcan_attach invocation through the -sX parameter: - slcan_attach -f -s6 -o /dev/ttyACM0 - slcand -f -s8 -o /dev/ttyUSB0 where -s6 in will set adapter's bitrate to 500 Kbit/s and -s8 to 1Mbit/s. See the table below for further CAN bitrates: - s0 -> 10 Kbit/s - s1 -> 20 Kbit/s - s2 -> 50 Kbit/s - s3 -> 100 Kbit/s - s4 -> 125 Kbit/s - s5 -> 250 Kbit/s - s6 -> 500 Kbit/s - s7 -> 800 Kbit/s - s8 -> 1000 Kbit/s In doing so, the struct can_priv::bittiming.bitrate of the driver is not set and since the open_candev() checks that the bitrate has been set, it must be a non-zero value, the bitrate is set to a fake value (-1U) before it is called. Using the rtnl_lock()/rtnl_unlock() functions has become a bit more tricky as the register_candev() function indirectly calls rtnl_lock() via register_netdev(). To avoid a deadlock it is therefore necessary to call rtnl_unlock() before calling register_candev(). The same goes for the unregister_candev() function. [1] commit 39549ee ("can: CAN Network device driver and Netlink interface") Link: https://lore.kernel.org/all/[email protected] Signed-off-by: Dario Binacchi <[email protected]> Tested-by: Jeroen Hofstee <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 036bff2 commit c4e54b0

File tree

2 files changed

+60
-62
lines changed

2 files changed

+60
-62
lines changed

drivers/net/can/Kconfig

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,6 @@ config CAN_VXCAN
4949
This driver can also be built as a module. If so, the module
5050
will be called vxcan.
5151

52-
config CAN_SLCAN
53-
tristate "Serial / USB serial CAN Adaptors (slcan)"
54-
depends on TTY
55-
help
56-
CAN driver for several 'low cost' CAN interfaces that are attached
57-
via serial lines or via USB-to-serial adapters using the LAWICEL
58-
ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
59-
60-
As only the sending and receiving of CAN frames is implemented, this
61-
driver should work with the (serial/USB) CAN hardware from:
62-
www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
63-
64-
Userspace tools to attach the SLCAN line discipline (slcan_attach,
65-
slcand) can be found in the can-utils at the linux-can project, see
66-
https://github.com/linux-can/can-utils for details.
67-
68-
The slcan driver supports up to 10 CAN netdevices by default which
69-
can be changed by the 'maxdev=xx' module option. This driver can
70-
also be built as a module. If so, the module will be called slcan.
71-
7252
config CAN_NETLINK
7353
bool "CAN device drivers with Netlink support"
7454
default y
@@ -172,6 +152,26 @@ config CAN_KVASER_PCIEFD
172152
Kvaser Mini PCI Express HS v2
173153
Kvaser Mini PCI Express 2xHS v2
174154

155+
config CAN_SLCAN
156+
tristate "Serial / USB serial CAN Adaptors (slcan)"
157+
depends on TTY
158+
help
159+
CAN driver for several 'low cost' CAN interfaces that are attached
160+
via serial lines or via USB-to-serial adapters using the LAWICEL
161+
ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
162+
163+
As only the sending and receiving of CAN frames is implemented, this
164+
driver should work with the (serial/USB) CAN hardware from:
165+
www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
166+
167+
Userspace tools to attach the SLCAN line discipline (slcan_attach,
168+
slcand) can be found in the can-utils at the linux-can project, see
169+
https://github.com/linux-can/can-utils for details.
170+
171+
The slcan driver supports up to 10 CAN netdevices by default which
172+
can be changed by the 'maxdev=xx' module option. This driver can
173+
also be built as a module. If so, the module will be called slcan.
174+
175175
config CAN_SUN4I
176176
tristate "Allwinner A10 CAN controller"
177177
depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST

drivers/net/can/slcan.c

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
#include <linux/can.h>
5757
#include <linux/can/dev.h>
5858
#include <linux/can/skb.h>
59-
#include <linux/can/can-ml.h>
6059

6160
MODULE_ALIAS_LDISC(N_SLCAN);
6261
MODULE_DESCRIPTION("serial line CAN interface");
@@ -79,6 +78,7 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
7978
#define SLC_EFF_ID_LEN 8
8079

8180
struct slcan {
81+
struct can_priv can;
8282
int magic;
8383

8484
/* Various fields. */
@@ -394,6 +394,8 @@ static int slc_close(struct net_device *dev)
394394
clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
395395
}
396396
netif_stop_queue(dev);
397+
close_candev(dev);
398+
sl->can.state = CAN_STATE_STOPPED;
397399
sl->rcount = 0;
398400
sl->xleft = 0;
399401
spin_unlock_bh(&sl->lock);
@@ -405,20 +407,34 @@ static int slc_close(struct net_device *dev)
405407
static int slc_open(struct net_device *dev)
406408
{
407409
struct slcan *sl = netdev_priv(dev);
410+
int err;
408411

409412
if (sl->tty == NULL)
410413
return -ENODEV;
411414

415+
/* The baud rate is not set with the command
416+
* `ip link set <iface> type can bitrate <baud>' and therefore
417+
* can.bittiming.bitrate is CAN_BITRATE_UNSET (0), causing
418+
* open_candev() to fail. So let's set to a fake value.
419+
*/
420+
sl->can.bittiming.bitrate = CAN_BITRATE_UNKNOWN;
421+
err = open_candev(dev);
422+
if (err) {
423+
netdev_err(dev, "failed to open can device\n");
424+
return err;
425+
}
426+
427+
sl->can.state = CAN_STATE_ERROR_ACTIVE;
412428
sl->flags &= BIT(SLF_INUSE);
413429
netif_start_queue(dev);
414430
return 0;
415431
}
416432

417-
/* Hook the destructor so we can free slcan devs at the right point in time */
418-
static void slc_free_netdev(struct net_device *dev)
433+
static void slc_dealloc(struct slcan *sl)
419434
{
420-
int i = dev->base_addr;
435+
int i = sl->dev->base_addr;
421436

437+
free_candev(sl->dev);
422438
slcan_devs[i] = NULL;
423439
}
424440

@@ -434,24 +450,6 @@ static const struct net_device_ops slc_netdev_ops = {
434450
.ndo_change_mtu = slcan_change_mtu,
435451
};
436452

437-
static void slc_setup(struct net_device *dev)
438-
{
439-
dev->netdev_ops = &slc_netdev_ops;
440-
dev->needs_free_netdev = true;
441-
dev->priv_destructor = slc_free_netdev;
442-
443-
dev->hard_header_len = 0;
444-
dev->addr_len = 0;
445-
dev->tx_queue_len = 10;
446-
447-
dev->mtu = CAN_MTU;
448-
dev->type = ARPHRD_CAN;
449-
450-
/* New-style flags. */
451-
dev->flags = IFF_NOARP;
452-
dev->features = NETIF_F_HW_CSUM;
453-
}
454-
455453
/******************************************
456454
Routines looking at TTY side.
457455
******************************************/
@@ -514,11 +512,8 @@ static void slc_sync(void)
514512
static struct slcan *slc_alloc(void)
515513
{
516514
int i;
517-
char name[IFNAMSIZ];
518515
struct net_device *dev = NULL;
519-
struct can_ml_priv *can_ml;
520516
struct slcan *sl;
521-
int size;
522517

523518
for (i = 0; i < maxdev; i++) {
524519
dev = slcan_devs[i];
@@ -531,16 +526,14 @@ static struct slcan *slc_alloc(void)
531526
if (i >= maxdev)
532527
return NULL;
533528

534-
sprintf(name, "slcan%d", i);
535-
size = ALIGN(sizeof(*sl), NETDEV_ALIGN) + sizeof(struct can_ml_priv);
536-
dev = alloc_netdev(size, name, NET_NAME_UNKNOWN, slc_setup);
529+
dev = alloc_candev(sizeof(*sl), 1);
537530
if (!dev)
538531
return NULL;
539532

533+
snprintf(dev->name, sizeof(dev->name), "slcan%d", i);
534+
dev->netdev_ops = &slc_netdev_ops;
540535
dev->base_addr = i;
541536
sl = netdev_priv(dev);
542-
can_ml = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
543-
can_set_ml_priv(dev, can_ml);
544537

545538
/* Initialize channel control data */
546539
sl->magic = SLCAN_MAGIC;
@@ -605,26 +598,28 @@ static int slcan_open(struct tty_struct *tty)
605598

606599
set_bit(SLF_INUSE, &sl->flags);
607600

608-
err = register_netdevice(sl->dev);
609-
if (err)
601+
rtnl_unlock();
602+
err = register_candev(sl->dev);
603+
if (err) {
604+
pr_err("slcan: can't register candev\n");
610605
goto err_free_chan;
606+
}
607+
} else {
608+
rtnl_unlock();
611609
}
612610

613-
/* Done. We have linked the TTY line to a channel. */
614-
rtnl_unlock();
615611
tty->receive_room = 65536; /* We don't flow control */
616612

617613
/* TTY layer expects 0 on success */
618614
return 0;
619615

620616
err_free_chan:
617+
rtnl_lock();
621618
sl->tty = NULL;
622619
tty->disc_data = NULL;
623620
clear_bit(SLF_INUSE, &sl->flags);
624-
slc_free_netdev(sl->dev);
625-
/* do not call free_netdev before rtnl_unlock */
621+
slc_dealloc(sl);
626622
rtnl_unlock();
627-
free_netdev(sl->dev);
628623
return err;
629624

630625
err_exit:
@@ -658,9 +653,11 @@ static void slcan_close(struct tty_struct *tty)
658653
synchronize_rcu();
659654
flush_work(&sl->tx_work);
660655

661-
/* Flush network side */
662-
unregister_netdev(sl->dev);
663-
/* This will complete via sl_free_netdev */
656+
slc_close(sl->dev);
657+
unregister_candev(sl->dev);
658+
rtnl_lock();
659+
slc_dealloc(sl);
660+
rtnl_unlock();
664661
}
665662

666663
static void slcan_hangup(struct tty_struct *tty)
@@ -768,14 +765,15 @@ static void __exit slcan_exit(void)
768765
dev = slcan_devs[i];
769766
if (!dev)
770767
continue;
771-
slcan_devs[i] = NULL;
772768

773769
sl = netdev_priv(dev);
774770
if (sl->tty) {
775771
netdev_err(dev, "tty discipline still running\n");
776772
}
777773

778-
unregister_netdev(dev);
774+
slc_close(dev);
775+
unregister_candev(dev);
776+
slc_dealloc(sl);
779777
}
780778

781779
kfree(slcan_devs);

0 commit comments

Comments
 (0)