*
* 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)
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);
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
/*
* $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);
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;
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,
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 */