linux-can.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Marc Kleine-Budde <mkl@pengutronix.de>
To: Alexander Stein <alexander.stein@systec-electronic.com>,
	Wolfgang Grandegger <wg@grandegger.com>
Cc: linux-can@vger.kernel.org
Subject: Re: [PATCH 2/5] can: slcan: Convert to can_dev interface
Date: Thu, 17 Apr 2014 21:10:35 +0200	[thread overview]
Message-ID: <5350272B.70703@pengutronix.de> (raw)
In-Reply-To: <1397573468-7619-3-git-send-email-alexander.stein@systec-electronic.com>

[-- Attachment #1: Type: text/plain, Size: 10981 bytes --]

On 04/15/2014 04:51 PM, Alexander Stein wrote:
> No actual feature change despite the interface name. This is just a
> preparation for additional CAN related features.
> 
> Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
> ---
>  drivers/net/can/Kconfig |  40 +++++++++----------
>  drivers/net/can/slcan.c | 104 +++++++++++++++++++++---------------------------
>  2 files changed, 65 insertions(+), 79 deletions(-)
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index 9e7d95d..daea043 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -9,26 +9,6 @@ config CAN_VCAN
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called vcan.
>  
> -config CAN_SLCAN
> -	tristate "Serial / USB serial CAN Adaptors (slcan)"
> -	depends on TTY
> -	---help---
> -	  CAN driver for several 'low cost' CAN interfaces that are attached
> -	  via serial lines or via USB-to-serial adapters using the LAWICEL
> -	  ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
> -
> -	  As only the sending and receiving of CAN frames is implemented, this
> -	  driver should work with the (serial/USB) CAN hardware from:
> -	  www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
> -
> -	  Userspace tools to attach the SLCAN line discipline (slcan_attach,
> -	  slcand) can be found in the can-utils at the SocketCAN SVN, see
> -	  http://developer.berlios.de/projects/socketcan for details.
> -
> -	  The slcan driver supports up to 10 CAN netdevices by default which
> -	  can be changed by the 'maxdev=xx' module option. This driver can
> -	  also be built as a module. If so, the module will be called slcan.
> -
>  config CAN_DEV
>  	tristate "Platform CAN drivers with Netlink support"
>  	default y
> @@ -125,6 +105,26 @@ config CAN_GRCAN
>  	  endian syntheses of the cores would need some modifications on
>  	  the hardware level to work.
>  
> +config CAN_SLCAN
> +	tristate "Serial / USB serial CAN Adaptors (slcan)"
> +	depends on TTY
> +	---help---
> +	  CAN driver for several 'low cost' CAN interfaces that are attached
> +	  via serial lines or via USB-to-serial adapters using the LAWICEL
> +	  ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
> +
> +	  As only the sending and receiving of CAN frames is implemented, this
> +	  driver should work with the (serial/USB) CAN hardware from:
> +	  www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
> +
> +	  Userspace tools to attach the SLCAN line discipline (slcan_attach,
> +	  slcand) can be found in the can-utils at the SocketCAN SVN, see
> +	  http://developer.berlios.de/projects/socketcan for details.
> +
> +	  The slcan driver supports up to 10 CAN netdevices by default which
> +	  can be changed by the 'maxdev=xx' module option. This driver can
> +	  also be built as a module. If so, the module will be called slcan.
> +
>  source "drivers/net/can/mscan/Kconfig"
>  
>  source "drivers/net/can/sja1000/Kconfig"
> diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
> index 2577c1e..337e6e3 100644
> --- a/drivers/net/can/slcan.c
> +++ b/drivers/net/can/slcan.c
> @@ -53,6 +53,7 @@
>  #include <linux/init.h>
>  #include <linux/kernel.h>
>  #include <linux/can.h>
> +#include <linux/can/dev.h>
>  #include <linux/can/skb.h>
>  
>  static __initconst const char banner[] =
> @@ -79,6 +80,7 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
>  #define SLC_EFF_ID_LEN 8
>  
>  struct slcan {
> +	struct can_priv		can;	/* must be the first member */
>  	int			magic;
>  
>  	/* Various fields. */
> @@ -99,6 +101,7 @@ struct slcan {
>  };
>  
>  static struct net_device **slcan_devs;
> +static DEFINE_MUTEX(slcan_mutex);
>  
>   /************************************************************************
>    *			SLCAN ENCAPSULATION FORMAT			 *
> @@ -143,31 +146,33 @@ static struct net_device **slcan_devs;
>  static void slc_bump(struct slcan *sl)
>  {
>  	struct sk_buff *skb;
> -	struct can_frame cf;
> +	struct can_frame *cf;
> +	canid_t can_id;
> +	u8 can_dlc;
>  	int i, tmp;
>  	u32 tmpid;
>  	char *cmd = sl->rbuff;
>  
> -	cf.can_id = 0;
> +	can_id = 0;
>  
>  	switch (*cmd) {
>  	case 'r':
> -		cf.can_id = CAN_RTR_FLAG;
> +		can_id = CAN_RTR_FLAG;
>  		/* fallthrough */
>  	case 't':
>  		/* store dlc ASCII value and terminate SFF CAN ID string */
> -		cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
> +		can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
>  		sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0;
>  		/* point to payload data behind the dlc */
>  		cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1;
>  		break;
>  	case 'R':
> -		cf.can_id = CAN_RTR_FLAG;
> +		can_id = CAN_RTR_FLAG;
>  		/* fallthrough */
>  	case 'T':
> -		cf.can_id |= CAN_EFF_FLAG;
> +		can_id |= CAN_EFF_FLAG;
>  		/* store dlc ASCII value and terminate EFF CAN ID string */
> -		cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
> +		can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
>  		sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0;
>  		/* point to payload data behind the dlc */
>  		cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1;
> @@ -179,49 +184,39 @@ static void slc_bump(struct slcan *sl)
>  	if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
>  		return;
>  
> -	cf.can_id |= tmpid;
> +	can_id |= tmpid;
>  
>  	/* get can_dlc from sanitized ASCII value */
> -	if (cf.can_dlc >= '0' && cf.can_dlc < '9')
> -		cf.can_dlc -= '0';
> +	if (can_dlc >= '0' && can_dlc < '9')
> +		can_dlc -= '0';
>  	else
>  		return;
>  
> -	*(u64 *) (&cf.data) = 0; /* clear payload */
> +	skb = alloc_can_skb(sl->dev, &cf);
> +	if (!skb)
> +		return;
> +	cf->can_id = can_id;
> +	cf->can_dlc = can_dlc;
>  
>  	/* RTR frames may have a dlc > 0 but they never have any data bytes */
> -	if (!(cf.can_id & CAN_RTR_FLAG)) {
> -		for (i = 0; i < cf.can_dlc; i++) {
> +	if (!(cf->can_id & CAN_RTR_FLAG)) {
> +		for (i = 0; i < cf->can_dlc; i++) {
>  			tmp = hex_to_bin(*cmd++);
>  			if (tmp < 0)
>  				return;
> -			cf.data[i] = (tmp << 4);
> +			cf->data[i] = (tmp << 4);
>  			tmp = hex_to_bin(*cmd++);
>  			if (tmp < 0)
>  				return;
> -			cf.data[i] |= tmp;
> +			cf->data[i] |= tmp;
>  		}
>  	}
> -
> -	skb = dev_alloc_skb(sizeof(struct can_frame) +
> -			    sizeof(struct can_skb_priv));
> -	if (!skb)
> -		return;
> -
>  	skb->dev = sl->dev;

I think this is not needed anymore, as alloc_can_skb() sets this already.

> -	skb->protocol = htons(ETH_P_CAN);
> -	skb->pkt_type = PACKET_BROADCAST;
> -	skb->ip_summed = CHECKSUM_UNNECESSARY;
> -
> -	can_skb_reserve(skb);
> -	can_skb_prv(skb)->ifindex = sl->dev->ifindex;
>  
> -	memcpy(skb_put(skb, sizeof(struct can_frame)),
> -	       &cf, sizeof(struct can_frame));
>  	netif_rx_ni(skb);
>  
>  	sl->dev->stats.rx_packets++;
> -	sl->dev->stats.rx_bytes += cf.can_dlc;
> +	sl->dev->stats.rx_bytes += cf->can_dlc;

Please don't touch the skb (and this cf) after netif_rx_ni

>  }
>  
>  /* parse tty input stream */
> @@ -385,6 +380,10 @@ static int slc_close(struct net_device *dev)
>  	netif_stop_queue(dev);
>  	sl->rcount   = 0;
>  	sl->xleft    = 0;
> +	sl->can.state = CAN_STATE_STOPPED;
> +
> +	close_candev(dev);
> +
>  	spin_unlock_bh(&sl->lock);
>  
>  	return 0;
> @@ -394,12 +393,19 @@ static int slc_close(struct net_device *dev)
>  static int slc_open(struct net_device *dev)
>  {
>  	struct slcan *sl = netdev_priv(dev);
> +	int err;
>  
>  	if (sl->tty == NULL)
>  		return -ENODEV;
>  
> +	err = open_candev(dev);
> +	if (err)
> +		return err;
> +
> +	sl->can.state = CAN_STATE_ERROR_ACTIVE;
>  	sl->flags &= (1 << SLF_INUSE);
>  	netif_start_queue(dev);
> +
>  	return 0;
>  }
>  
> @@ -407,7 +413,7 @@ static int slc_open(struct net_device *dev)
>  static void slc_free_netdev(struct net_device *dev)
>  {
>  	int i = dev->base_addr;
> -	free_netdev(dev);
> +	free_candev(dev);
>  	slcan_devs[i] = NULL;
>  }
>  
> @@ -417,23 +423,6 @@ static const struct net_device_ops slc_netdev_ops = {
>  	.ndo_start_xmit         = slc_xmit,
>  };
>  
> -static void slc_setup(struct net_device *dev)
> -{
> -	dev->netdev_ops		= &slc_netdev_ops;
> -	dev->destructor		= slc_free_netdev;
> -
> -	dev->hard_header_len	= 0;
> -	dev->addr_len		= 0;
> -	dev->tx_queue_len	= 10;
> -
> -	dev->mtu		= sizeof(struct can_frame);
> -	dev->type		= ARPHRD_CAN;
> -
> -	/* New-style flags. */
> -	dev->flags		= IFF_NOARP;
> -	dev->features           = NETIF_F_HW_CSUM;
> -}
> -
>  /******************************************
>    Routines looking at TTY side.
>   ******************************************/
> @@ -495,7 +484,6 @@ static void slc_sync(void)
>  static struct slcan *slc_alloc(dev_t line)
>  {
>  	int i;
> -	char name[IFNAMSIZ];
>  	struct net_device *dev = NULL;
>  	struct slcan       *sl;
>  
> @@ -510,12 +498,13 @@ static struct slcan *slc_alloc(dev_t line)
>  	if (i >= maxdev)
>  		return NULL;
>  
> -	sprintf(name, "slcan%d", i);
> -	dev = alloc_netdev(sizeof(*sl), name, slc_setup);
> +	dev = alloc_candev(sizeof(*sl), 1);
>  	if (!dev)
>  		return NULL;
>  
>  	dev->base_addr  = i;
> +	dev->netdev_ops = &slc_netdev_ops;
> +	dev->destructor = slc_free_netdev;
>  	sl = netdev_priv(dev);
>  
>  	/* Initialize channel control data */
> @@ -548,11 +537,8 @@ static int slcan_open(struct tty_struct *tty)
>  	if (tty->ops->write == NULL)
>  		return -EOPNOTSUPP;
>  
> -	/* RTnetlink lock is misused here to serialize concurrent
> -	   opens of slcan channels. There are better ways, but it is
> -	   the simplest one.
> -	 */
> -	rtnl_lock();
> +	/* Serialize concurrent opens of slcan channels. */
> +	mutex_lock(&slcan_mutex);
>  
>  	/* Collect hanged up channels. */
>  	slc_sync();
> @@ -580,13 +566,13 @@ static int slcan_open(struct tty_struct *tty)
>  
>  		set_bit(SLF_INUSE, &sl->flags);
>  
> -		err = register_netdevice(sl->dev);
> +		err = register_candev(sl->dev);
>  		if (err)
>  			goto err_free_chan;
>  	}
>  
>  	/* Done.  We have linked the TTY line to a channel. */
> -	rtnl_unlock();
> +	mutex_unlock(&slcan_mutex);
>  	tty->receive_room = 65536;	/* We don't flow control */
>  
>  	/* TTY layer expects 0 on success */
> @@ -598,7 +584,7 @@ err_free_chan:
>  	clear_bit(SLF_INUSE, &sl->flags);
>  
>  err_exit:
> -	rtnl_unlock();
> +	mutex_unlock(&slcan_mutex);
>  
>  	/* Count references from TTY module */
>  	return err;
> 

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 242 bytes --]

  reply	other threads:[~2014-04-17 19:10 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-15 14:51 Bitrate and CAN status support for slcan Alexander Stein
2014-04-15 14:51 ` [PATCH 1/5] can: slcan: Fix spinlock variant Alexander Stein
2014-04-22 19:58   ` Oliver Hartkopp
2014-04-24 20:32   ` Marc Kleine-Budde
2014-04-15 14:51 ` [PATCH 2/5] can: slcan: Convert to can_dev interface Alexander Stein
2014-04-17 19:10   ` Marc Kleine-Budde [this message]
2014-04-15 14:51 ` [PATCH 3/5] can: slcan: Send open/close command upon interface up/down Alexander Stein
2014-04-15 14:51 ` [PATCH 4/5] can: slcan: Add bitrate change support Alexander Stein
2014-04-17 19:13   ` Marc Kleine-Budde
2014-04-15 14:51 ` [PATCH 5/5] can: slcan: Add CAN status flag support Alexander Stein
2014-04-17 19:22   ` Marc Kleine-Budde
2014-04-19 20:38   ` Oliver Hartkopp
2014-04-19 19:24 ` Bitrate and CAN status support for slcan Oliver Hartkopp
2014-04-22  7:08   ` Alexander Stein
2014-04-22 19:50     ` Oliver Hartkopp

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5350272B.70703@pengutronix.de \
    --to=mkl@pengutronix.de \
    --cc=alexander.stein@systec-electronic.com \
    --cc=linux-can@vger.kernel.org \
    --cc=wg@grandegger.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).