]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
Added new interface for setting bit-timing parameters.
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Sat, 4 Oct 2008 17:15:39 +0000 (17:15 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Sat, 4 Oct 2008 17:15:39 +0000 (17:15 +0000)
See details at
https://lists.berlios.de/pipermail/socketcan-core/2008-September/001850.html

git-svn-id: svn://svn.berlios.de//socketcan/trunk@823 030b6a49-0b11-0410-94ab-b0dab22257f2

kernel/2.6/drivers/net/can/dev.c
kernel/2.6/drivers/net/can/sysfs.c
kernel/2.6/include/linux/can/dev.h

index ca9e6bc25a8a0fbe6fd74a773db1e75981b3fd6b..1f90fc5fd2b5191e201e98a0a1bd6b8a07b7341e 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
  * Copyright (C) 2006 Andrey Volkov, Varma Electronics
+ * Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
 
 MODULE_DESCRIPTION(MOD_DESC);
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Marc Kleine-Budde <mkl@pengutronix.de>, "
-             "Andrey Volkov <avolkov@varma-el.com>");
-
-static int restart_ms;
-
-module_param(restart_ms, int, S_IRUGO | S_IWUSR);
-
-MODULE_PARM_DESC(restart_ms, "Restart time after bus-off in ms (default 0)");
-
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 
 /*
- * Abstract:
- *   Bit rate calculated with next formula:
- *   bitrate = frq/(brp*(1 + prop_seg+ phase_seg1 + phase_seg2))
- *
- *   This calc function based on work of Florian Hartwich and Armin Bassemi
- *   "The Configuration of the CAN Bit Timing"
- *   (http://www.semiconductors.bosch.de/pdf/CiA99Paper.pdf)
+ * Bit-timing calculation derived from:
  *
- *  Parameters:
- *  [in]
- *    bittime_nsec - expected bit time in nanosecs
- *
- *  [out]
- *    bittime      - calculated time segments, for meaning of
- *                  each field read CAN standard.
+ * Code based on LinCAN sources and H8S2638 project
+ * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
+ * Copyright 2005      Stanislav Marek
+ * email: pisa@cmp.felk.cvut.cz
  */
+static int can_update_spt(const struct can_bittiming_const *btc,
+                         int sampl_pt, int tseg, int *tseg1, int *tseg2)
+{
+       *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
+       if (*tseg2 < btc->tseg2_min)
+               *tseg2 = btc->tseg2_min;
+       if (*tseg2 > btc->tseg2_max)
+               *tseg2 = btc->tseg2_max;
+       *tseg1 = tseg - *tseg2;
+       if (*tseg1 > btc->tseg1_max) {
+               *tseg1 = btc->tseg1_max;
+               *tseg2 = tseg - *tseg1;
+       }
+       return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
+}
+
+static int can_calc_bittiming(struct net_device *dev)
+{
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_bittiming *bt = &priv->bittiming;
+       const struct can_bittiming_const *btc = priv->bittiming_const;
+       long rate, best_rate = 0;
+       long best_error = 1000000000, error = 0;
+       int best_tseg = 0, best_brp = 0, brp = 0;
+       int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
+       int spt_error = 1000, spt = 0, sampl_pt;
+       uint64_t v64;
+
+       if (!priv->bittiming_const)
+               return -ENOTSUPP;
+
+       /* Use CIA recommended sample points */
+       if (bt->sample_point) {
+               sampl_pt = bt->sample_point;
+       } else {
+               if (bt->bitrate > 800000)
+                       sampl_pt = 750;
+               else if (bt->bitrate > 500000)
+                       sampl_pt = 800;
+               else
+                       sampl_pt = 875;
+       }
+
+       /* tseg even = round down, odd = round up */
+       for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
+            tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
+               tsegall = 1 + tseg / 2;
+               /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
+               brp = bt->clock / (tsegall * bt->bitrate) + tseg % 2;
+               /* chose brp step which is possible in system */
+               brp = (brp / btc->brp_inc) * btc->brp_inc;
+               if ((brp < btc->brp_min) || (brp > btc->brp_max))
+                       continue;
+               rate = bt->clock / (brp * tsegall);
+               error = bt->bitrate - rate;
+               /* tseg brp biterror */
+               if (error < 0)
+                       error = -error;
+               if (error > best_error)
+                       continue;
+               best_error = error;
+               if (error == 0) {
+                       spt = can_update_spt(btc, sampl_pt, tseg / 2,
+                                            &tseg1, &tseg2);
+                       error = sampl_pt - spt;
+                       if (error < 0)
+                               error = -error;
+                       if (error > spt_error)
+                               continue;
+                       spt_error = error;
+               }
+               best_tseg = tseg / 2;
+               best_brp = brp;
+               best_rate = rate;
+               if (error == 0)
+                       break;
+       }
 
-#define DEFAULT_MAX_BRP        64U
-#define DEFAULT_MAX_SJW        4U
+       if (!spt)
+               spt = can_update_spt(btc, sampl_pt, best_tseg, &tseg1, &tseg2);
+
+       v64 = (u64)best_brp * 1000000000UL;
+       do_div(v64, bt->clock);
+       bt->tq = (u32)v64;
+       bt->prop_seg = 0;
+       bt->phase_seg1 = tseg1;
+       bt->phase_seg2 = tseg2;
+       bt->sjw = 1;
+       bt->brp = best_brp;
+
+       if (best_error) {
+               error = best_error * 1000;
+               error /= bt->bitrate;
+               dev_warn(ND2D(dev), "bitrate error %ld.%ld%%\n",
+                        error / 10, error % 10);
+       }
 
-/* All below values in tq units */
-#define MAX_BITTIME    25U
-#define MIN_BITTIME    8U
-#define MAX_PROP_SEG   8U
-#define MAX_PHASE_SEG1 8U
-#define MAX_PHASE_SEG2 8U
+       return 0;
+}
 
-int can_calc_bittime(struct can_priv *can, u32 bitrate,
-                    struct can_bittime_std *bittime)
+int can_sample_point(struct can_bittiming *bt)
 {
-       int best_error = -1;    /* Ariphmetic error */
-       int df, best_df = -1;   /* oscillator's tolerance range,
-                                  greater is better */
-       u32 quanta;             /* in tq units */
-       u32 brp, phase_seg1, phase_seg2, sjw, prop_seg;
-       u32 brp_min, brp_max, brp_expected;
-       u64 tmp;
-
-       /* bitrate range [1baud,1MiB/s] */
-       if (bitrate == 0 || bitrate > 1000000UL)
+       return ((bt->prop_seg + bt->phase_seg1 + 1) * 1000) /
+               (bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1);
+}
+
+int can_fixup_bittiming(struct net_device *dev)
+{
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_bittiming *bt = &priv->bittiming;
+       const struct can_bittiming_const *btc = priv->bittiming_const;
+       int tseg1, alltseg;
+       u32 bitrate;
+       u64 brp64;
+
+       if (!priv->bittiming_const)
+               return -ENOTSUPP;
+
+       tseg1 = bt->prop_seg + bt->phase_seg1;
+       if (bt->sjw > btc->sjw_max ||
+           tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
+           bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
                return -EINVAL;
 
-       tmp = (u64) can->can_sys_clock * 1000;
-       do_div(tmp, bitrate);
-       brp_expected = (u32) tmp;
-
-       brp_min = brp_expected / (1000 * MAX_BITTIME);
-       if (brp_min == 0)
-               brp_min = 1;
-       if (brp_min > can->max_brp)
-               return -ERANGE;
-
-       brp_max = (brp_expected + 500 * MIN_BITTIME) / (1000 * MIN_BITTIME);
-       if (brp_max == 0)
-               brp_max = 1;
-       if (brp_max > can->max_brp)
-               brp_max = can->max_brp;
-
-       for (brp = brp_min; brp <= brp_max; brp++) {
-               quanta = brp_expected / (brp * 1000);
-               if (quanta < MAX_BITTIME
-                   && quanta * brp * 1000 != brp_expected)
-                       quanta++;
-               if (quanta < MIN_BITTIME || quanta > MAX_BITTIME)
-                       continue;
+       brp64 = (u64)bt->clock * (u64)bt->tq;
+       if (btc->brp_inc > 1)
+               do_div(brp64, btc->brp_inc);
+       brp64 += 500000000UL - 1;
+       do_div(brp64, 1000000000UL); /* the practicable BRP */
+       if (btc->brp_inc > 1)
+               brp64 *= btc->brp_inc;
+       bt->brp = (u32)brp64;
 
-               phase_seg2 = min((quanta - 3) / 2, MAX_PHASE_SEG2);
-               for (sjw = can->max_sjw; sjw > 0; sjw--) {
-                       for (; phase_seg2 > sjw; phase_seg2--) {
-                               u32 err1, err2;
-                               phase_seg1 =
-                                   phase_seg2 % 2 ? phase_seg2 -
-                                   1 : phase_seg2;
-                               prop_seg = quanta - 1 - phase_seg2 - phase_seg1;
-                               /*
-                                * FIXME: support of longer lines (i.e. bigger
-                                * prop_seg) is more prefered than support of
-                                * cheap oscillators (i.e. bigger
-                                * df/phase_seg1/phase_seg2)
-                                */
-                               if (prop_seg < phase_seg1)
-                                       continue;
-                               if (prop_seg > MAX_PROP_SEG)
-                                       goto next_brp;
-
-                               err1 = phase_seg1 * brp * 500 * 1000 /
-                                   (13 * brp_expected -
-                                    phase_seg2 * brp * 1000);
-                               err2 = sjw * brp * 50 * 1000 / brp_expected;
-
-                               df = min(err1, err2);
-                               if (df >= best_df) {
-                                       unsigned error =
-                                               abs(brp_expected * 10 /
-                                                   (brp * (1 + prop_seg +
-                                                           phase_seg1 +
-                                                           phase_seg2)) -
-                                                   10000);
-
-                                       if (error > 10 || error > best_error)
-                                               continue;
-
-                                       if (error == best_error
-                                           && prop_seg < bittime->prop_seg)
-                                               continue;
-
-                                       best_error = error;
-                                       best_df = df;
-                                       bittime->brp = brp;
-                                       bittime->prop_seg = prop_seg;
-                                       bittime->phase_seg1 = phase_seg1;
-                                       bittime->phase_seg2 = phase_seg2;
-                                       bittime->sjw = sjw;
-                                       bittime->sam =
-                                               (bittime->phase_seg1 > 3);
-                               }
-                       }
-               }
-next_brp:;
-       }
+       if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
+               return -EINVAL;
+
+       alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
+       bitrate = bt->clock / (bt->brp * alltseg);
+       bt->bitrate = bitrate;
 
-       if (best_error < 0)
-               return -EDOM;
        return 0;
 }
 
-int can_set_bitrate(struct net_device *dev, u32 bitrate)
+int can_set_bittiming(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
-       int err = -ENOTSUPP;
-
-       if (priv->state != CAN_STATE_STOPPED)
-               return -EBUSY;
-
-       if (priv->do_set_bittime) {
-               if (priv->do_set_bittime) {
-                       struct can_bittime bittime;
-                       err = can_calc_bittime(priv, bitrate, &bittime.std);
-                       if (err)
-                               goto out;
-                       bittime.type = CAN_BITTIME_STD;
-                       err = priv->do_set_bittime(dev, &bittime);
-                       if (!err) {
-                               priv->bitrate = bitrate;
-                               priv->bittime = bittime;
-                       }
-               }
+       int err;
+
+       /* Check if the CAN device needs bit-timing parameters */
+       if (priv->do_set_bittiming) {
+
+               /* Check if bit-timing parameters have already been set */
+               if (priv->bittiming.tq && priv->bittiming.bitrate)
+                       return 0;
+
+               /* Check if bit-timing parameters have been pre-defined */
+               if (!priv->bittiming.tq && !priv->bittiming.bitrate)
+                       return -EINVAL;
+
+               /* Non-expert mode? Check if the bitrate has been pre-defined */
+               if (!priv->bittiming.tq)
+                       /* Determine bit-timing parameters */
+                       err = can_calc_bittiming(dev);
+               else
+                       /* Check bit-timing params and calculate proper brp */
+                       err = can_fixup_bittiming(dev);
+               if (err)
+                       return err;
+
+               /* Finally, set the bit-timing registers */
+               err = priv->do_set_bittiming(dev);
+               if (err)
+                       return err;
        }
-out:
-       return err;
+       return 0;
 }
-EXPORT_SYMBOL(can_set_bitrate);
+EXPORT_SYMBOL(can_set_bittiming);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
 static struct net_device_stats *can_get_stats(struct net_device *dev)
@@ -235,12 +260,7 @@ struct net_device *alloc_candev(int sizeof_priv)
 
        priv = netdev_priv(dev);
 
-       /* Default values can be overwritten by the device driver */
-       priv->restart_ms = restart_ms;
-       priv->bitrate = CAN_BITRATE_UNCONFIGURED;
        priv->state = CAN_STATE_STOPPED;
-       priv->max_brp = DEFAULT_MAX_BRP;
-       priv->max_sjw = DEFAULT_MAX_SJW;
        spin_lock_init(&priv->irq_lock);
 
        init_timer(&priv->timer);
@@ -448,12 +468,6 @@ static int can_netdev_notifier_call(struct notifier_block *nb,
 
        switch (state) {
        case NETDEV_REGISTER:
-               /* set default bit timing */
-               if (priv->do_set_bittime &&
-                   priv->bitrate == CAN_BITRATE_UNCONFIGURED) {
-                       if (can_set_bitrate(dev, CAN_BITRATE_DEFAULT))
-                               dev_err(ND2D(dev), "failed to set bitrate\n");
-               }
 #ifdef CONFIG_SYSFS
                can_create_sysfs(dev);
 #endif
index 39f2b632e83e1446c2652f6eb34c765c86e12bc5..1600b96bd618e09d2e4a5232af4fd9bb3672193f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * $Id: dev.c 542 2007-11-07 13:57:16Z thuermann $
  *
- * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2007-2008 Wolfgang Grandegger <wg@grandegger.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
 #include "sysfs.h"
 
 #ifdef CONFIG_SYSFS
+
 /*
- * Functions to set/get CAN properties used by SYSFS
- *
- * FIXME: we may want to check for capabilities!
- *
- *        if (!capable(CAP_NET_ADMIN))
- *             return -EPERM;
+ * SYSFS access functions and attributes. Use same locking as
+ * net/core/net-sysfs.c does.
  */
-static int can_get_bitrate(struct net_device *dev, u32 *bitrate)
+static inline int dev_isalive(const struct net_device *dev)
 {
-       struct can_priv *priv = netdev_priv(dev);
-       *bitrate = priv->bitrate;
+       return dev->reg_state <= NETREG_REGISTERED;
+}
 
-       return 0;
+/* use same locking rules as GIF* ioctl's */
+static ssize_t can_dev_show(struct device *d,
+                           struct device_attribute *attr, char *buf,
+                           ssize_t (*fmt)(struct net_device *, char *))
+{
+       struct net_device *dev = to_net_dev(d);
+       ssize_t ret = -EINVAL;
+
+       read_lock(&dev_base_lock);
+       if (dev_isalive(dev))
+               ret = (*fmt)(dev, buf);
+       read_unlock(&dev_base_lock);
+
+       return ret;
 }
 
-static int can_set_custombittime(struct net_device *dev,
-                                struct can_bittime *bt)
+/* generate a show function for simple field */
+#define CAN_DEV_SHOW(field, fmt_string)                                        \
+static ssize_t fmt_can_##field(struct net_device *dev, char *buf)      \
+{                                                                      \
+       struct can_priv *priv = netdev_priv(dev);                       \
+       return sprintf(buf, fmt_string, priv->field);                   \
+}                                                                      \
+static ssize_t show_can_##field(struct device *d,                      \
+                               struct device_attribute *attr,          \
+                               char *buf)                              \
+{                                                                      \
+       return can_dev_show(d, attr, buf, fmt_can_##field);             \
+}
+
+/* use same locking and permission rules as SIF* ioctl's */
+static ssize_t can_dev_store(struct device *d, struct device_attribute *attr,
+                            const char *buf, size_t len,
+                            int (*set)(struct net_device *, unsigned long))
 {
-       struct can_priv *priv = netdev_priv(dev);
-       int err = -ENOTSUPP;
+       struct net_device *dev = to_net_dev(d);
+       unsigned long new;
+       int ret = -EINVAL;
 
-       if (priv->state != CAN_STATE_STOPPED)
-               return -EBUSY;
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
 
-       if (priv->do_set_bittime) {
-               err = priv->do_set_bittime(dev, bt);
-               if (err)
-                       goto out;
-               priv->bittime = *bt;
-               if (bt->type == CAN_BITTIME_STD && bt->std.brp) {
-                       priv->bitrate = priv->can_sys_clock /
-                               (bt->std.brp * (1 + bt->std.prop_seg +
-                                               bt->std.phase_seg1 +
-                                               bt->std.phase_seg2));
-               } else
-                       priv->bitrate = CAN_BITRATE_UNKNOWN;
+       ret = strict_strtoul(buf, 0, &new);
+       if (ret)
+               goto out;
+
+       rtnl_lock();
+       if (dev_isalive(dev)) {
+               ret = (*set)(dev, new);
+               if (!ret)
+                       ret = len;
        }
+       rtnl_unlock();
 out:
-       return err;
+       return ret;
 }
 
-static int can_get_custombittime(struct net_device *dev,
-                                struct can_bittime *bt)
-{
-       struct can_priv *priv = netdev_priv(dev);
+#define CAN_CREATE_FILE(_dev, _name)                                   \
+       if (device_create_file(&_dev->dev, &dev_attr_##_name))          \
+               dev_err(ND2D(_dev),                                     \
+                       "Couldn't create device file for ##_name\n")
 
-       *bt = priv->bittime;
-       return 0;
-}
+#define CAN_REMOVE_FILE(_dev, _name)                                   \
+       device_remove_file(&_dev->dev, &dev_attr_##_name)               \
+
+CAN_DEV_SHOW(ctrlmode, "0x%x\n");
 
-static int can_set_ctrlmode(struct net_device *dev, u32 ctrlmode)
+static int change_can_ctrlmode(struct net_device *dev, unsigned long ctrlmode)
 {
        struct can_priv *priv = netdev_priv(dev);
+       int err = 0;
 
-       if (!priv->do_set_ctrlmode)
-               return -ENOTSUPP;
        if (priv->state != CAN_STATE_STOPPED)
                return -EBUSY;
 
-       return priv->do_set_ctrlmode(dev, ctrlmode);
+       if (priv->do_set_ctrlmode)
+               err = priv->do_set_ctrlmode(dev, ctrlmode);
+
+       if (!err)
+               priv->ctrlmode = ctrlmode;
+
+       return err;
 }
 
-static int can_get_ctrlmode(struct net_device *dev, u32 *ctrlmode)
+static ssize_t store_can_ctrlmode(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
 {
-       struct can_priv *priv = netdev_priv(dev);
-
-       *ctrlmode = priv->ctrlmode;
-       return 0;
+       return can_dev_store(dev, attr, buf, len, change_can_ctrlmode);
 }
 
-static int can_get_state(struct net_device *dev, enum can_state *state)
+static DEVICE_ATTR(can_ctrlmode, S_IRUGO | S_IWUSR,
+                  show_can_ctrlmode, store_can_ctrlmode);
+
+static const char *can_state_names[] = {
+       "active", "bus-warn", "bus-pass" , "bus-off",
+       "stopped", "sleeping", "unkown"
+};
+
+static ssize_t printf_can_state(struct net_device *dev, char *buf)
 {
        struct can_priv *priv = netdev_priv(dev);
+       enum can_state state;
+       int err = 0;
 
        if (priv->do_get_state) {
-               int err = priv->do_get_state(dev, state);
+               int err = priv->do_get_state(dev, &state);
                if (err)
-                       return err;
-               priv->state = *state;
+                       goto out;
+               priv->state = state;
        } else
-               *state = priv->state;
-       return 0;
+               state = priv->state;
+
+       if (state >= ARRAY_SIZE(can_state_names))
+               state = ARRAY_SIZE(can_state_names) - 1;
+       err = sprintf(buf, "%s\n", can_state_names[state]);
+out:
+       return err;
 }
 
-static int can_set_clock(struct net_device *dev, u32 clock)
+static ssize_t show_can_state(struct device *d,
+                             struct device_attribute *attr, char *buf)
 {
-       struct can_priv *priv = netdev_priv(dev);
-
-       if (priv->state != CAN_STATE_STOPPED)
-               return -EBUSY;
-
-       priv->can_sys_clock = clock;
-       return 0;
+       return can_dev_show(d, attr, buf, printf_can_state);
 }
 
-static int can_get_clock(struct net_device *dev, u32 *clock)
-{
-       struct can_priv *priv = netdev_priv(dev);
+static DEVICE_ATTR(can_state, S_IRUGO, show_can_state, NULL);
 
-       *clock = priv->can_sys_clock;
-       return 0;
-}
+CAN_DEV_SHOW(restart_ms, "%d\n");
 
-static int can_set_restart_ms(struct net_device *dev, int ms)
+static int change_can_restart_ms(struct net_device *dev, unsigned long ms)
 {
        struct can_priv *priv = netdev_priv(dev);
 
@@ -144,15 +180,28 @@ static int can_set_restart_ms(struct net_device *dev, int ms)
        return 0;
 }
 
-static int can_get_restart_ms(struct net_device *dev, int *ms)
+static ssize_t store_can_restart_ms(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t len)
 {
-       struct can_priv *priv = netdev_priv(dev);
+       return can_dev_store(dev, attr, buf, len, change_can_restart_ms);
+}
 
-       *ms = priv->restart_ms;
-       return 0;
+static DEVICE_ATTR(can_restart_ms, S_IRUGO | S_IWUSR,
+                  show_can_restart_ms, store_can_restart_ms);
+
+static ssize_t printf_can_echo(struct net_device *dev, char *buf)
+{
+       return sprintf(buf, "%d\n", dev->flags & IFF_ECHO ? 1 : 0);
+}
+
+static ssize_t show_can_echo(struct device *d,
+                         struct device_attribute *attr, char *buf)
+{
+       return can_dev_show(d, attr, buf, printf_can_echo);
 }
 
-static int can_set_echo(struct net_device *dev, int on)
+static int change_can_echo(struct net_device *dev, unsigned long on)
 {
        if (on)
                dev->flags |= IFF_ECHO;
@@ -161,316 +210,243 @@ static int can_set_echo(struct net_device *dev, int on)
        return 0;
 }
 
-static int can_get_echo(struct net_device *dev, int *on)
+static ssize_t store_can_echo(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t len)
 {
-       *on = dev->flags & IFF_ECHO ? 1 : 0;
-       return 0;
+       return can_dev_store(dev, attr, buf, len, change_can_echo);
 }
 
-/*
- * SYSFS access functions and attributes.
- * Use same locking as net/core/net-sysfs.c
- */
-static inline int dev_isalive(const struct net_device *dev)
+static DEVICE_ATTR(can_echo, S_IRUGO | S_IWUSR, show_can_echo, store_can_echo);
+
+static int change_can_restart(struct net_device *dev, unsigned long on)
 {
-       return dev->reg_state <= NETREG_REGISTERED;
+       return can_restart_now(dev);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-#define CAN_ATTR(_name, _func, _type, _fmt)                            \
-static ssize_t can_show_##_func(struct device *dev,                    \
-                               struct device_attribute *attr,          \
-                               char *buf)                              \
-{                                                                      \
-       struct net_device *ndev = to_net_dev(dev);                      \
-       _type val;                                                      \
-       int ret = -EINVAL;                                              \
-       read_lock(&dev_base_lock);                                      \
-       if (dev_isalive(ndev)) {                                        \
-               can_get_##_func(ndev, &val);                            \
-               ret = snprintf(buf, PAGE_SIZE, _fmt "\n", val);         \
-       }                                                               \
-       read_unlock(&dev_base_lock);                                    \
-       return ret;                                                     \
-}                                                                      \
-static ssize_t can_store_##_func(struct device *dev,                   \
-                                struct device_attribute *attr,         \
-                                const char *buf, size_t count)         \
-{                                                                      \
-       struct net_device *ndev = to_net_dev(dev);                      \
-       char *endp;                                                     \
-       _type val;                                                      \
-       int ret = -EINVAL;                                              \
-       val = simple_strtoul(buf, &endp, 0);                            \
-       if (endp == buf)                                                \
-               return ret;                                             \
-       rtnl_lock();                                                    \
-       if (dev_isalive(ndev)) {                                        \
-               if ((ret = can_set_##_func(ndev, val)) == 0)            \
-                       ret = count;                                    \
-       }                                                               \
-       rtnl_unlock();                                                  \
-       return ret;                                                     \
-}                                                                      \
-static DEVICE_ATTR(_name, S_IRUGO | S_IWUSR,                           \
-                  can_show_##_func, can_store_##_func)
-
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) */
-#define CAN_ATTR(_name, _func, _type, _fmt)                            \
-static ssize_t can_show_##_func(struct device *dev,                    \
-                               struct device_attribute *attr,          \
-                               char *buf)                              \
-{                                                                      \
-       struct net_device *ndev = to_net_dev(dev);                      \
-       _type val;                                                      \
-       int ret = -EINVAL;                                              \
-       read_lock(&dev_base_lock);                                      \
-       if (dev_isalive(ndev)) {                                        \
-               can_get_##_func(ndev, &val);                            \
-               ret = snprintf(buf, PAGE_SIZE, _fmt "\n", val);         \
-       }                                                               \
-       read_unlock(&dev_base_lock);                                    \
-       return ret;                                                     \
-}                                                                      \
-static ssize_t can_store_##_func(struct device *dev,                   \
-                                struct device_attribute *attr,         \
-                                const char *buf, size_t count)         \
-{                                                                      \
-       struct net_device *ndev = to_net_dev(dev);                      \
-       _type val;                                                      \
-       unsigned long input;                                            \
-       int ret = -EINVAL;                                              \
-       ret = strict_strtoul(buf, 0, &input);                           \
-       if (ret)                                                        \
-               return ret;                                             \
-       val = (_type)input;                                             \
-       rtnl_lock();                                                    \
-       if (dev_isalive(ndev)) {                                        \
-               ret = can_set_##_func(ndev, val);                       \
-               if (ret == 0)                                           \
-                       ret = count;                                    \
-       }                                                               \
-       rtnl_unlock();                                                  \
-       return ret;                                                     \
-}                                                                      \
-static DEVICE_ATTR(_name, S_IRUGO | S_IWUSR,                           \
-                  can_show_##_func, can_store_##_func)
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) */
-
-CAN_ATTR(can_bitrate, bitrate, u32, "%d");
-CAN_ATTR(can_restart_ms, restart_ms, int, "%d");
-CAN_ATTR(can_clock, clock, u32, "%d");
-CAN_ATTR(can_echo, echo, int, "%d");
-
-#define CAN_STATS_ATTR(_name)                                          \
-static ssize_t can_stats_show_##_name(struct device *dev,              \
-                                     struct device_attribute *attr,    \
-                                     char *buf)                        \
-{                                                                      \
-       struct net_device *ndev = to_net_dev(dev);                      \
-       struct can_priv *priv = netdev_priv(ndev);                      \
-       int ret = -EINVAL;                                              \
-       read_lock(&dev_base_lock);                                      \
-       if (dev_isalive(ndev)) {                                        \
-               ret = snprintf(buf, PAGE_SIZE, "%d\n",                  \
-                             priv->can_stats._name);                   \
-       }                                                               \
-       read_unlock(&dev_base_lock);                                    \
-       return ret;                                                     \
-}                                                                      \
-static DEVICE_ATTR(_name, S_IRUGO, can_stats_show_##_name, NULL)
-
-#define CAN_CREATE_FILE(_dev, _name)                                   \
-       if (device_create_file(&_dev->dev, &dev_attr_##_name))          \
-               dev_err(ND2D(_dev),                                     \
-                       "Couldn't create device file for ##_name\n")
-
-#define CAN_REMOVE_FILE(_dev, _name)                                   \
-       device_remove_file(&_dev->dev, &dev_attr_##_name)               \
-
-CAN_STATS_ATTR(error_warning);
-CAN_STATS_ATTR(error_passive);
-CAN_STATS_ATTR(bus_error);
-CAN_STATS_ATTR(arbitration_lost);
-CAN_STATS_ATTR(data_overrun);
-CAN_STATS_ATTR(wakeup);
-CAN_STATS_ATTR(restarts);
-
-static ssize_t can_store_restart(struct device *dev,
+static ssize_t store_can_restart(struct device *dev,
                                 struct device_attribute *attr,
-                                const char *buf, size_t count)
+                                const char *buf, size_t len)
 {
-       struct net_device *ndev = to_net_dev(dev);
-       int ret = -EINVAL;
-
-       rtnl_lock();
-       if (dev_isalive(ndev)) {
-               ret = can_restart_now(ndev);
-               if (!ret)
-                       ret = count;
-       }
-       rtnl_unlock();
-       return ret;
+       return can_dev_store(dev, attr, buf, len, change_can_restart);
 }
 
-static DEVICE_ATTR(can_restart, S_IWUSR, NULL, can_store_restart);
-
-static const char *can_state_names[] = {
-       "active", "bus-warn", "bus-pass" , "bus-off",
-       "stopped", "sleeping", "unkown"
-};
+static DEVICE_ATTR(can_restart, S_IWUSR, NULL, store_can_restart);
 
-static ssize_t can_show_state(struct device *dev,
-                            struct device_attribute *attr,
-                            char *buf)
+/* Show a given attribute if the CAN bittiming group */
+static ssize_t can_btc_show(const struct device *d,
+                           struct device_attribute *attr, char *buf,
+                           unsigned long offset)
 {
-       struct net_device *ndev = to_net_dev(dev);
-       enum can_state state;
-       int ret = -EINVAL;
+       struct net_device *dev = to_net_dev(d);
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_bittiming_const *btc = priv->bittiming_const;
+       ssize_t ret = -EINVAL;
+
+       WARN_ON(offset >= sizeof(struct can_bittiming_const) ||
+               offset % sizeof(u32) != 0);
 
        read_lock(&dev_base_lock);
-       if (dev_isalive(ndev)) {
-               can_get_state(ndev, &state);
+       if (dev_isalive(dev) && btc)
+               ret = sprintf(buf, "%d\n",
+                             *(u32 *)(((u8 *)btc) + offset));
 
-               if (state >= ARRAY_SIZE(can_state_names))
-                       state = ARRAY_SIZE(can_state_names) - 1;
-               ret = snprintf(buf, PAGE_SIZE, "%s\n", can_state_names[state]);
-       }
        read_unlock(&dev_base_lock);
        return ret;
 }
 
-static DEVICE_ATTR(can_state, S_IRUGO, can_show_state, NULL);
-
-static ssize_t can_show_ctrlmode(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
+/* Generate a read-only bittiming const attribute */
+#define CAN_BT_CONST_ENTRY(name)                                       \
+static ssize_t show_##name(struct device *d,                           \
+                          struct device_attribute *attr, char *buf)    \
+{                                                                      \
+       return can_btc_show(d, attr, buf,                               \
+                           offsetof(struct can_bittiming_const, name));\
+}                                                                      \
+static DEVICE_ATTR(hw_##name, S_IRUGO, show_##name, NULL)
+
+CAN_BT_CONST_ENTRY(tseg1_min);
+CAN_BT_CONST_ENTRY(tseg1_max);
+CAN_BT_CONST_ENTRY(tseg2_min);
+CAN_BT_CONST_ENTRY(tseg2_max);
+CAN_BT_CONST_ENTRY(sjw_max);
+CAN_BT_CONST_ENTRY(brp_min);
+CAN_BT_CONST_ENTRY(brp_max);
+CAN_BT_CONST_ENTRY(brp_inc);
+
+static ssize_t can_bt_show(const struct device *d,
+                          struct device_attribute *attr, char *buf,
+                          unsigned long offset)
 {
-       struct net_device *ndev = to_net_dev(dev);
-       u32 ctrlmode;
-       int ret = -EINVAL;
+       struct net_device *dev = to_net_dev(d);
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_bittiming *bt = &priv->bittiming;
+       ssize_t ret = -EINVAL;
+       u32 *ptr, val;
+
+       WARN_ON(offset >= sizeof(struct can_bittiming) ||
+               offset % sizeof(u32) != 0);
 
        read_lock(&dev_base_lock);
-       if (dev_isalive(ndev)) {
-               can_get_ctrlmode(ndev, &ctrlmode);
-               ret = 0;
-               if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
-                       ret += sprintf(buf + ret, "listenonly");
-               if (ret)
-                       ret += sprintf(buf + ret, " ");
-               if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
-                       ret += sprintf(buf + ret, "loopback");
-               if (ret)
-                       ret += sprintf(buf + ret, "\n");
+       if (dev_isalive(dev)) {
+               ptr = (u32 *)(((u8 *)bt) + offset);
+               if (ptr == &bt->sample_point &&
+                   priv->state != CAN_STATE_STOPPED)
+                       val = can_sample_point(bt);
+               else
+                       val = *ptr;
+               ret = sprintf(buf, "%d\n", val);
        }
        read_unlock(&dev_base_lock);
        return ret;
 }
 
-static ssize_t can_store_ctrlmode(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
+static ssize_t can_bt_store(const struct device *d,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count,
+                           unsigned long offset)
 {
-       struct net_device *ndev = to_net_dev(dev);
-       u32 ctrlmode = 0;
-       int ret = -EINVAL;
+       struct net_device *dev = to_net_dev(d);
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_bittiming *bt = &priv->bittiming;
+       unsigned long new;
+       ssize_t ret = -EINVAL;
+       u32 *ptr;
+
+       if (priv->state != CAN_STATE_STOPPED)
+               return -EBUSY;
 
-       if (strstr(buf, "listenonly"))
-               ctrlmode |= CAN_CTRLMODE_LISTENONLY;
-       if (strstr(buf, "loopback"))
-               ctrlmode |= CAN_CTRLMODE_LOOPBACK;
+       WARN_ON(offset >= sizeof(struct can_bittiming) ||
+               offset % sizeof(u32) != 0);
 
+       ret = strict_strtoul(buf, 0, &new);
+       if (ret)
+               goto out;
+
+       ptr = (u32 *)(((u8 *)bt) + offset);
        rtnl_lock();
-       if (dev_isalive(ndev) && count) {
-               ret = can_set_ctrlmode(ndev, ctrlmode);
-               if (!ret)
-                       ret = count;
+       if (dev_isalive(dev)) {
+               *ptr = (u32)new;
+
+               if ((ptr == &bt->bitrate) || (ptr == &bt->sample_point)) {
+                       bt->tq = 0;
+                       bt->brp = 0;
+                       bt->sjw = 0;
+                       bt->prop_seg = 0;
+                       bt->phase_seg1 = 0;
+                       bt->phase_seg2 = 0;
+               } else {
+                       bt->bitrate = 0;
+                       bt->sample_point = 0;
+               }
+               ret = count;
        }
        rtnl_unlock();
+out:
        return ret;
 }
 
-static DEVICE_ATTR(can_ctrlmode, S_IRUGO | S_IWUSR,
-                  can_show_ctrlmode, can_store_ctrlmode);
-
-static ssize_t can_show_custombittime(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
-{
-       struct net_device *ndev = to_net_dev(dev);
-       struct can_bittime bt;
-       int ret = -EINVAL;
+#define CAN_BT_ENTRY_RO(name)                                          \
+static ssize_t show_##name(struct device *d,                           \
+                          struct device_attribute *attr, char *buf)    \
+{                                                                      \
+       return can_bt_show(d, attr, buf,                                \
+                          offsetof(struct can_bittiming, name));       \
+}                                                                      \
+static DEVICE_ATTR(hw_##name, S_IRUGO, show_##name, NULL)
 
-       read_lock(&dev_base_lock);
-       if (dev_isalive(ndev)) {
-               can_get_custombittime(ndev, &bt);
-
-               if (bt.type == CAN_BITTIME_STD)
-                       ret = snprintf(buf, PAGE_SIZE,
-                                      "std %#x %#x %#x %#x %#x %#x\n",
-                                      bt.std.brp, bt.std.prop_seg,
-                                      bt.std.phase_seg1, bt.std.phase_seg2,
-                                      bt.std.sjw, bt.std.sam);
-               else if (bt.type == CAN_BITTIME_BTR)
-                       ret = snprintf(buf, PAGE_SIZE,
-                                       "btr %#x %#x\n",
-                                       bt.btr.btr0, bt.btr.btr1);
-               else
-                       ret = snprintf(buf, PAGE_SIZE, "undefined\n");
-       }
-       read_unlock(&dev_base_lock);
-       return ret;
-}
+CAN_BT_ENTRY_RO(clock);
 
-static ssize_t can_store_custombittime(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct net_device *ndev = to_net_dev(dev);
-       struct can_bittime bt;
-       u32 val[6];
-       int ret = -EINVAL;
+#define CAN_BT_ENTRY(name)                                             \
+static ssize_t show_##name(struct device *d,                           \
+                          struct device_attribute *attr, char *buf)    \
+{                                                                      \
+       return can_bt_show(d, attr, buf,                                \
+                          offsetof(struct can_bittiming, name));       \
+}                                                                      \
+static ssize_t store_##name(struct device *d,                          \
+                           struct device_attribute *attr,              \
+                           const char *buf, size_t count)              \
+{                                                                      \
+       return can_bt_store(d, attr, buf, count,                        \
+                           offsetof(struct can_bittiming, name));      \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+
+CAN_BT_ENTRY(bitrate);
+CAN_BT_ENTRY(sample_point);
+CAN_BT_ENTRY(tq);
+CAN_BT_ENTRY(prop_seg);
+CAN_BT_ENTRY(phase_seg1);
+CAN_BT_ENTRY(phase_seg2);
+CAN_BT_ENTRY(sjw);
+
+static struct attribute *can_bittiming_attrs[] = {
+       &dev_attr_hw_tseg1_min.attr,
+       &dev_attr_hw_tseg1_max.attr,
+       &dev_attr_hw_tseg2_max.attr,
+       &dev_attr_hw_tseg2_min.attr,
+       &dev_attr_hw_sjw_max.attr,
+       &dev_attr_hw_brp_min.attr,
+       &dev_attr_hw_brp_max.attr,
+       &dev_attr_hw_brp_inc.attr,
+       &dev_attr_hw_clock.attr,
+       &dev_attr_bitrate.attr,
+       &dev_attr_sample_point.attr,
+       &dev_attr_tq.attr,
+       &dev_attr_prop_seg.attr,
+       &dev_attr_phase_seg1.attr,
+       &dev_attr_phase_seg2.attr,
+       &dev_attr_sjw.attr,
+       NULL
+};
 
-       if (!strncmp(buf, "std", 3)) {
-
-               if (sscanf(buf + 4, "%i %i %i %i %i %i",
-                          val, val + 1, val + 2, val + 3,
-                          val + 4, val + 5) == 6) {
-                       bt.type = CAN_BITTIME_STD;
-                       bt.std.brp = val[0];
-                       bt.std.prop_seg = val[1];
-                       bt.std.phase_seg1 = val[2];
-                       bt.std.phase_seg2 = val[3];
-                       bt.std.sjw = val[4];
-                       bt.std.sam = val[5];
-               }
+static struct attribute_group can_bittiming_group = {
+       .name = "can_bittiming",
+       .attrs = can_bittiming_attrs,
+};
 
-       } else if (!strncmp(buf, "btr", 3)) {
+/* Show a given attribute in the CAN statistics group */
+static ssize_t can_stat_show(const struct device *d,
+                            struct device_attribute *attr, char *buf,
+                            unsigned long offset)
+{
+       struct net_device *dev = to_net_dev(d);
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_device_stats *stats = &priv->can_stats;
+       ssize_t ret = -EINVAL;
 
-               if (sscanf(buf + 4, "%i %i", val, val + 1) == 2) {
-                       bt.type = CAN_BITTIME_BTR;
-                       bt.btr.btr0 = val[0];
-                       bt.btr.btr1 = val[1];
-               }
+       WARN_ON(offset >= sizeof(struct can_device_stats) ||
+               offset % sizeof(unsigned long) != 0);
 
-       } else
-               goto out;
+       read_lock(&dev_base_lock);
+       if (dev_isalive(dev))
+               ret = sprintf(buf, "%ld\n",
+                             *(unsigned long *)(((u8 *)stats) + offset));
 
-       rtnl_lock();
-       if (dev_isalive(ndev)) {
-               ret = can_set_custombittime(ndev, &bt);
-               if (!ret)
-                       ret = count;
-       }
-       rtnl_unlock();
-out:
+       read_unlock(&dev_base_lock);
        return ret;
 }
 
-static DEVICE_ATTR(can_custombittime, S_IRUGO | S_IWUSR,
-                  can_show_custombittime, can_store_custombittime);
+/* Generate a read-only CAN statistics attribute */
+#define CAN_STAT_ENTRY(name)                                           \
+static ssize_t show_##name(struct device *d,                           \
+                          struct device_attribute *attr, char *buf)    \
+{                                                                      \
+       return can_stat_show(d, attr, buf,                              \
+                            offsetof(struct can_device_stats, name));  \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+CAN_STAT_ENTRY(error_warning);
+CAN_STAT_ENTRY(error_passive);
+CAN_STAT_ENTRY(bus_error);
+CAN_STAT_ENTRY(arbitration_lost);
+CAN_STAT_ENTRY(data_overrun);
+CAN_STAT_ENTRY(wakeup);
+CAN_STAT_ENTRY(restarts);
 
-static struct attribute *can_stats_attrs[] = {
+static struct attribute *can_statistics_attrs[] = {
        &dev_attr_error_warning.attr,
        &dev_attr_error_passive.attr,
        &dev_attr_bus_error.attr,
@@ -481,42 +457,52 @@ static struct attribute *can_stats_attrs[] = {
        NULL
 };
 
-static struct attribute_group can_stats_group = {
+static struct attribute_group can_statistics_group = {
        .name = "can_statistics",
-       .attrs = can_stats_attrs,
+       .attrs = can_statistics_attrs,
 };
 
 void can_create_sysfs(struct net_device *dev)
 {
+       struct can_priv *priv = netdev_priv(dev);
        int err;
 
-       CAN_CREATE_FILE(dev, can_bitrate);
-       CAN_CREATE_FILE(dev, can_custombittime);
-       CAN_CREATE_FILE(dev, can_restart);
        CAN_CREATE_FILE(dev, can_ctrlmode);
+       CAN_CREATE_FILE(dev, can_echo);
+       CAN_CREATE_FILE(dev, can_restart);
        CAN_CREATE_FILE(dev, can_state);
        CAN_CREATE_FILE(dev, can_restart_ms);
-       CAN_CREATE_FILE(dev, can_clock);
-       CAN_CREATE_FILE(dev, can_echo);
 
-       err = sysfs_create_group(&(dev->dev.kobj), &can_stats_group);
+       err = sysfs_create_group(&(dev->dev.kobj),
+                                &can_statistics_group);
        if (err) {
                printk(KERN_EMERG
-                      "couldn't create sysfs group for CAN stats\n");
+                      "couldn't create sysfs group for CAN statistics\n");
+       }
+
+       if (priv->bittiming_const) {
+               err = sysfs_create_group(&(dev->dev.kobj),
+                                        &can_bittiming_group);
+               if (err) {
+                       printk(KERN_EMERG "couldn't create sysfs "
+                              "group for CAN bittiming\n");
+               }
        }
 }
 
 void can_remove_sysfs(struct net_device *dev)
 {
-       CAN_REMOVE_FILE(dev, can_bitrate);
-       CAN_REMOVE_FILE(dev, can_custombittime);
-       CAN_REMOVE_FILE(dev, can_restart);
+       struct can_priv *priv = netdev_priv(dev);
+
        CAN_REMOVE_FILE(dev, can_ctrlmode);
-       CAN_REMOVE_FILE(dev, can_state);
-       CAN_REMOVE_FILE(dev, can_clock);
        CAN_REMOVE_FILE(dev, can_echo);
+       CAN_REMOVE_FILE(dev, can_state);
+       CAN_REMOVE_FILE(dev, can_restart);
+       CAN_REMOVE_FILE(dev, can_restart_ms);
 
-       sysfs_remove_group(&(dev->dev.kobj), &can_stats_group);
+       sysfs_remove_group(&(dev->dev.kobj), &can_statistics_group);
+       if (priv->bittiming_const)
+               sysfs_remove_group(&(dev->dev.kobj), &can_bittiming_group);
 }
 
 #endif /* CONFIG_SYSFS */
index aee866d1bfb343981832846e43d0871e646333d1..ed72650b3ad4fe8f6108a36f48c81ad30da59e31 100644 (file)
 #include <linux/can/error.h>
 
 /*
- * CAN bitrate
+ * CAN bitrate and bit-timing
  */
-#define CAN_BITRATE_UNCONFIGURED       ((__u32) 0xFFFFFFFFU)
-#define CAN_BITRATE_UNKNOWN            0
-#define CAN_BITRATE_DEFAULT            500000
-
-/*
- * CAN custom bit time
- */
-enum can_bittimes {
-       CAN_BITTIME_STD,
-       CAN_BITTIME_BTR
-};
-
-/* TSEG1 of controllers usually is a sum of synch_seg (always 1),
- * prop_seg and phase_seg1, TSEG2 = phase_seg2 */
-
-struct can_bittime_std {
-       __u32 brp;        /* baud rate prescaler */
-       __u8  prop_seg;   /* from 1 to 8 */
-       __u8  phase_seg1; /* from 1 to 8 */
-       __u8  phase_seg2; /* from 1 to 8 */
-       __u8  sjw:7;      /* from 1 to 4 */
-       __u8  sam:1;      /* 1 - enable triple sampling */
-};
-
-struct can_bittime_btr {
-       __u8  btr0;
-       __u8  btr1;
+struct can_bittiming {
+       u32 bitrate;
+       u32 sample_point;
+       u32 tq;
+       u32 prop_seg;
+       u32 phase_seg1;
+       u32 phase_seg2;
+       u32 sjw;
+       u32 clock;
+       u32 brp;
 };
 
-struct can_bittime {
-       enum can_bittimes type;
-       union {
-               struct can_bittime_std std;
-               struct can_bittime_btr btr;
-       };
+struct can_bittiming_const {
+       u32 tseg1_min;
+       u32 tseg1_max;
+       u32 tseg2_min;
+       u32 tseg2_max;
+       u32 sjw_max;
+       u32 brp_min;
+       u32 brp_max;
+       u32 brp_inc;
 };
 
 /*
@@ -68,8 +54,9 @@ enum can_mode {
 /*
  * CAN controller mode
  */
-#define CAN_CTRLMODE_LOOPBACK   0x1
-#define CAN_CTRLMODE_LISTENONLY 0x2
+#define CAN_CTRLMODE_LOOPBACK  0x1
+#define CAN_CTRLMODE_LISTENONLY        0x2
+#define CAN_CTRLMODE_3_SAMPLES 0x4 /* Triple sampling mode */
 
 /*
  * CAN operational and error states
@@ -87,14 +74,14 @@ enum can_state {
  * CAN device statistics
  */
 struct can_device_stats {
-       int error_warning;
-       int data_overrun;
-       int wakeup;
-       int bus_error;
-       int error_passive;
-       int arbitration_lost;
-       int restarts;
-       int bus_error_at_init;
+       unsigned long error_warning;
+       unsigned long data_overrun;
+       unsigned long wakeup;
+       unsigned long bus_error;
+       unsigned long error_passive;
+       unsigned long arbitration_lost;
+       unsigned long restarts;
+       unsigned long bus_error_at_init;
 };
 
 /*
@@ -108,25 +95,8 @@ struct can_priv {
 #endif
        struct can_device_stats can_stats;
 
-       /*
-        * CAN bus oscillator frequency, in Hz, BE CAREFUL! SOME
-        * CONTROLLERS (LIKE SJA1000) FOOLISH ABOUT THIS FRQ (for
-        * sja1000 as ex. this clock must be xtal clock divided by 2).
-        */
-       u32 can_sys_clock;
-       /*
-        * By default max_brp is equal 64, but for a Freescale TouCAN,
-        * as ex., it can be 255.
-        */
-       u32 max_brp;
-       /*
-        * For the mostly all controllers, max_sjw is equal 4, but some,
-        * hmm, CAN implementations hardwared it to 1.
-        */
-       u8 max_sjw;
-
-       u32 bitrate;
-       struct can_bittime bittime;
+       struct can_bittiming bittiming;
+       struct can_bittiming_const *bittiming_const;
 
        spinlock_t irq_lock;
        /* Please hold this lock when touching net_stats/can_stats */
@@ -140,8 +110,7 @@ struct can_priv {
 
        struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX];
 
-       int (*do_set_bittime)(struct net_device *dev,
-                             struct can_bittime *br);
+       int (*do_set_bittiming)(struct net_device *dev);
        int (*do_get_state)(struct net_device *dev, u32 *state);
        int (*do_set_mode)(struct net_device *dev, u32 mode);
        int (*do_set_ctrlmode)(struct net_device *dev, u32 ctrlmode);
@@ -161,8 +130,9 @@ struct can_priv {
 struct net_device *alloc_candev(int sizeof_priv);
 void free_candev(struct net_device *dev);
 
+int can_set_bittiming(struct net_device *dev);
+
 int can_restart_now(struct net_device *dev);
-int can_set_bitrate(struct net_device *dev, u32 bitrate);
 
 void can_bus_off(struct net_device *dev);
 
@@ -171,4 +141,6 @@ void can_close_cleanup(struct net_device *dev);
 void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx);
 void can_get_echo_skb(struct net_device *dev, int idx);
 
+int can_sample_point(struct can_bittiming *bt);
+
 #endif /* CAN_DEVICE_H */