]> git.baikalelectronics.ru Git - kernel.git/commitdiff
can: slcan: set bitrate by CAN device driver API
authorDario Binacchi <dario.binacchi@amarulasolutions.com>
Tue, 28 Jun 2022 16:31:31 +0000 (18:31 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Sun, 3 Jul 2022 09:34:38 +0000 (11:34 +0200)
It allows to set the bitrate via ip tool, as it happens for the other
CAN device drivers. It still remains possible to set the bitrate via
slcand or slcan_attach utilities. In case the ip tool is used, the
driver will send the serial command to the adapter.

Link: https://lore.kernel.org/all/20220628163137.413025-8-dario.binacchi@amarulasolutions.com
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Tested-by: Jeroen Hofstee <jhofstee@victronenergy.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/slcan.c

index dfccf8d6c9a559cfe19674075c929d9662ca6be8..74033e2d7097ec8583b47ac59d9d879fe5602f6d 100644 (file)
@@ -104,6 +104,11 @@ struct slcan {
 
 static struct net_device **slcan_devs;
 
+static const u32 slcan_bitrate_const[] = {
+       10000, 20000, 50000, 100000, 125000,
+       250000, 500000, 800000, 1000000
+};
+
  /************************************************************************
   *                    SLCAN ENCAPSULATION FORMAT                       *
   ************************************************************************/
@@ -439,6 +444,9 @@ static int slc_close(struct net_device *dev)
        netif_stop_queue(dev);
        close_candev(dev);
        sl->can.state = CAN_STATE_STOPPED;
+       if (sl->can.bittiming.bitrate == CAN_BITRATE_UNKNOWN)
+               sl->can.bittiming.bitrate = CAN_BITRATE_UNSET;
+
        sl->rcount   = 0;
        sl->xleft    = 0;
        spin_unlock_bh(&sl->lock);
@@ -450,7 +458,8 @@ static int slc_close(struct net_device *dev)
 static int slc_open(struct net_device *dev)
 {
        struct slcan *sl = netdev_priv(dev);
-       int err;
+       unsigned char cmd[SLC_MTU];
+       int err, s;
 
        if (sl->tty == NULL)
                return -ENODEV;
@@ -460,15 +469,39 @@ static int slc_open(struct net_device *dev)
         * can.bittiming.bitrate is CAN_BITRATE_UNSET (0), causing
         * open_candev() to fail. So let's set to a fake value.
         */
-       sl->can.bittiming.bitrate = CAN_BITRATE_UNKNOWN;
+       if (sl->can.bittiming.bitrate == CAN_BITRATE_UNSET)
+               sl->can.bittiming.bitrate = CAN_BITRATE_UNKNOWN;
+
        err = open_candev(dev);
        if (err) {
                netdev_err(dev, "failed to open can device\n");
                return err;
        }
 
-       sl->can.state = CAN_STATE_ERROR_ACTIVE;
        sl->flags &= BIT(SLF_INUSE);
+
+       if (sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) {
+               for (s = 0; s < ARRAY_SIZE(slcan_bitrate_const); s++) {
+                       if (sl->can.bittiming.bitrate == slcan_bitrate_const[s])
+                               break;
+               }
+
+               /* The CAN framework has already validate the bitrate value,
+                * so we can avoid to check if `s' has been properly set.
+                */
+
+               snprintf(cmd, sizeof(cmd), "C\rS%d\r", s);
+               err = slcan_transmit_cmd(sl, cmd);
+               if (err) {
+                       netdev_err(dev,
+                                  "failed to send bitrate command 'C\\rS%d\\r'\n",
+                                  s);
+                       close_candev(dev);
+                       return err;
+               }
+       }
+
+       sl->can.state = CAN_STATE_ERROR_ACTIVE;
        netif_start_queue(dev);
        return 0;
 }
@@ -581,6 +614,8 @@ static struct slcan *slc_alloc(void)
        /* Initialize channel control data */
        sl->magic = SLCAN_MAGIC;
        sl->dev = dev;
+       sl->can.bitrate_const = slcan_bitrate_const;
+       sl->can.bitrate_const_cnt = ARRAY_SIZE(slcan_bitrate_const);
        spin_lock_init(&sl->lock);
        INIT_WORK(&sl->tx_work, slcan_transmit);
        init_waitqueue_head(&sl->xcmd_wait);