From: Wolfgang Grandegger <wg@grandegger.com>
To: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Wolfgang Grandegger <wg@grandegger.com>
Subject: [PATCH 2/2] iproute2: Support for the CAN netlink
Date: Tue, 12 May 2009 11:42:50 +0200 [thread overview]
Message-ID: <20090512094248.764585154@denx.de> (raw)
In-Reply-To: 20090512094248.439786706@denx.de
[-- Attachment #1: 02-iplink-can.patch --]
[-- Type: text/plain, Size: 11983 bytes --]
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
include/linux/can/netlink.h | 113 ++++++++++++++++++
ip/Makefile | 2
ip/iplink.c | 2
ip/iplink_can.c | 264 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 379 insertions(+), 2 deletions(-)
Index: iproute2/ip/Makefile
===================================================================
--- iproute2.orig/ip/Makefile
+++ iproute2/ip/Makefile
@@ -2,7 +2,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o ipr
rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \
ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
- iplink_vlan.o link_veth.o link_gre.o
+ iplink_vlan.o link_veth.o link_gre.o iplink_can.o
RTMONOBJ=rtmon.o
Index: iproute2/ip/iplink_can.c
===================================================================
--- /dev/null
+++ iproute2/ip/iplink_can.c
@@ -0,0 +1,264 @@
+/*
+ * iplink_can.c CAN device support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Wolfgang Grandegger <wg@grandegger.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/can/netlink.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: ip link set DEVICE type can\n"
+ "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | \n"
+ "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n "
+ "\t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n"
+ "\n"
+ "\t[ loopback { on | off } ]\n"
+ "\t[ listen-only { on | off } ]\n"
+ "\t[ triple-sampling { on | off } ]\n"
+ "\n"
+ "\t[ restart-ms TIME-MS ]\n"
+ "\t[ restart ]\n"
+ "\n"
+ "\tWhere: BITRATE := { 1..1000000 }\n"
+ "\t SAMPLE-POINT := { 0.000..0.999 }\n"
+ "\t TQ := { NUMBER }\n"
+ "\t PROP-SEG := { 1..8 }\n"
+ "\t PHASE-SEG1 := { 1..8 }\n"
+ "\t PHASE-SEG2 := { 1..8 }\n"
+ "\t SJW := { 1..4 }\n"
+ "\t RESTART-MS := { 0 | NUMBER }\n"
+ );
+}
+
+static int get_float(float *val, const char *arg)
+{
+ float res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtof(arg, &ptr);
+ if (!ptr || ptr == arg || *ptr)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+static void set_ctrlmode(char* name, char *arg,
+ struct can_ctrlmode *cm, __u32 flags)
+{
+ if (strcmp(arg, "on") == 0) {
+ cm->flags |= flags;
+ } else if (strcmp(arg, "off") != 0) {
+ fprintf(stderr,
+ "Error: argument of \"%s\" must be \"on\" or \"off\"\n",
+ name);
+ exit(-1);
+ }
+ cm->mask |= flags;
+}
+
+static void print_ctrlmode(FILE *f, __u32 cm)
+{
+ fprintf(f, "<");
+#define _PF(cmflag, cmname) \
+ if (cm & cmflag) { \
+ cm &= ~cmflag; \
+ fprintf(f, "%s%s", cmname, cm ? "," : ""); \
+ }
+ _PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK");
+ _PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY");
+ _PF(CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING");
+#undef _PF
+ if (cm)
+ fprintf(f, "%x", cm);
+ fprintf(f, "> ");
+}
+
+static int can_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct can_bittiming bt;
+ struct can_ctrlmode cm = {0, 0};
+
+ memset(&bt, 0, sizeof(bt));
+ while (argc > 0) {
+ if (matches(*argv, "bitrate") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.bitrate, *argv, 0))
+ invarg("invalid \"bitrate\" value\n", *argv);
+ } else if (matches(*argv, "sample-point") == 0) {
+ float sp;
+
+ NEXT_ARG();
+ if (get_float(&sp, *argv))
+ invarg("invalid \"sample-point\" value\n",
+ *argv);
+ bt.sample_point = (__u32)(sp * 1000);
+ } else if (matches(*argv, "tq") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.tq, *argv, 0))
+ invarg("invalid \"tq\" value\n", *argv);
+ } else if (matches(*argv, "prop-seg") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.prop_seg, *argv, 0))
+ invarg("invalid \"prop-seg\" value\n", *argv);
+ } else if (matches(*argv, "phase-seg1") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.phase_seg1, *argv, 0))
+ invarg("invalid \"phase-seg1\" value\n", *argv);
+ } else if (matches(*argv, "phase-seg2") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.phase_seg2, *argv, 0))
+ invarg("invalid \"phase-seg2\" value\n", *argv);
+ } else if (matches(*argv, "sjw") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.sjw, *argv, 0))
+ invarg("invalid \"sjw\" value\n", *argv);
+ } else if (matches(*argv, "loopback") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("loopback", *argv, &cm,
+ CAN_CTRLMODE_LOOPBACK);
+ } else if (matches(*argv, "listen-only") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("listen-only", *argv, &cm,
+ CAN_CTRLMODE_LISTENONLY);
+ } else if (matches(*argv, "triple-sampling") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("triple-sampling", *argv, &cm,
+ CAN_CTRLMODE_3_SAMPLES);
+ } else if (matches(*argv, "restart") == 0) {
+ __u32 val = 1;
+
+ addattr32(n, 1024, IFLA_CAN_RESTART, val);
+ } else if (matches(*argv, "restart-ms") == 0) {
+ __u32 val;
+
+ NEXT_ARG();
+ if (get_u32(&val, *argv, 0))
+ invarg("invalid \"restart-ms\" value\n", *argv);
+ addattr32(n, 1024, IFLA_CAN_RESTART_MS, val);
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ return -1;
+ } else {
+ fprintf(stderr, "can: what is \"%s\"?\n", *argv);
+ usage();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ if (bt.bitrate || bt.tq)
+ addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
+ if (cm.mask)
+ addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
+
+ return 0;
+}
+
+static const char *can_state_names[] = {
+ [CAN_STATE_ERROR_ACTIVE] = "ERROR-ACTIVE",
+ [CAN_STATE_ERROR_WARNING] = "ERROR-WARNING",
+ [CAN_STATE_ERROR_PASSIVE] = "ERROR-PASSIVE",
+ [CAN_STATE_BUS_OFF] = "BUS-OFF",
+ [CAN_STATE_STOPPED] = "STOPPED",
+ [CAN_STATE_SLEEPING] = "SLEEPING"
+};
+
+static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ if (!tb)
+ return;
+
+ if (tb[IFLA_CAN_CTRLMODE]) {
+ struct can_ctrlmode *cm = RTA_DATA(tb[IFLA_CAN_CTRLMODE]);
+
+ if (cm->flags)
+ print_ctrlmode(f, cm->flags);
+ }
+
+ if (tb[IFLA_CAN_STATE]) {
+ int *state = RTA_DATA(tb[IFLA_CAN_STATE]);
+
+ fprintf(f, "state %s ", *state <= CAN_STATE_MAX ?
+ can_state_names[*state] : "UNKNOWN");
+ }
+
+ if (tb[IFLA_CAN_RESTART_MS]) {
+ __u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]);
+
+ fprintf(f, "restart-ms %d ", *restart_ms);
+ }
+
+ if (tb[IFLA_CAN_BITTIMING]) {
+ struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]);
+
+ fprintf(f, "\n "
+ "bitrate %d sample-point %.3f ",
+ bt->bitrate, (float)bt->sample_point / 1000.);
+ fprintf(f, "\n "
+ "tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
+ bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2,
+ bt->sjw);
+ }
+
+ if (tb[IFLA_CAN_BITTIMING_CONST]) {
+ struct can_bittiming_const *btc =
+ RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]);
+
+ fprintf(f, "\n "
+ "%s: tseg1 %d..%d tseg2 %d..%d "
+ "sjw 1..%d brp %d..%d brp-inc %d",
+ btc->name, btc->tseg1_min, btc->tseg1_max,
+ btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
+ btc->brp_min, btc->brp_max, btc->brp_inc);
+ }
+
+ if (tb[IFLA_CAN_CLOCK]) {
+ struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]);
+
+ fprintf(f, "\n clock %d", clock->freq);
+ }
+
+}
+
+static void can_print_xstats(struct link_util *lu,
+ FILE *f, struct rtattr *xstats)
+{
+ struct can_device_stats *stats;
+
+ if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) {
+ stats = RTA_DATA(xstats);
+ fprintf(f, "\n "
+ "re-started bus-errors arbit-lost "
+ "error-warn error-pass bus-off");
+ fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d",
+ stats->restarts, stats->bus_error,
+ stats->arbitration_lost, stats->error_warning,
+ stats->error_passive, stats->bus_off);
+ }
+}
+
+struct link_util can_link_util = {
+ .id = "can",
+ .maxattr = IFLA_CAN_MAX,
+ .parse_opt = can_parse_opt,
+ .print_opt = can_print_opt,
+ .print_xstats = can_print_xstats,
+};
Index: iproute2/ip/iplink.c
===================================================================
--- iproute2.orig/ip/iplink.c
+++ iproute2/ip/iplink.c
@@ -72,7 +72,7 @@ void iplink_usage(void)
if (iplink_have_newlink()) {
fprintf(stderr, "\n");
- fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan }\n");
+ fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }\n");
}
exit(-1);
}
Index: iproute2/include/linux/can/netlink.h
===================================================================
--- /dev/null
+++ iproute2/include/linux/can/netlink.h
@@ -0,0 +1,113 @@
+/*
+ * linux/can/netlink.h
+ *
+ * Definitions for the CAN netlink interface
+ *
+ * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_NETLINK_H
+#define CAN_NETLINK_H
+
+#include <linux/types.h>
+
+/*
+ * CAN bit-timing parameters
+ *
+ * For futher information, please read chapter "8 BIT TIMING
+ * REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
+ * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
+ */
+struct can_bittiming {
+ __u32 bitrate; /* Bit-rate in bits/second */
+ __u32 sample_point; /* Sample point in one-tenth of a percent */
+ __u32 tq; /* Time quanta (TQ) in nanoseconds */
+ __u32 prop_seg; /* Propagation segment in TQs */
+ __u32 phase_seg1; /* Phase buffer segment 1 in TQs */
+ __u32 phase_seg2; /* Phase buffer segment 2 in TQs */
+ __u32 sjw; /* Synchronisation jump width in TQs */
+ __u32 brp; /* Bit-rate prescaler */
+};
+
+/*
+ * CAN harware-dependent bit-timing constant
+ *
+ * Used for calculating and checking bit-timing parameters
+ */
+struct can_bittiming_const {
+ char name[16]; /* Name of the CAN controller hardware */
+ __u32 tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */
+ __u32 tseg1_max;
+ __u32 tseg2_min; /* Time segement 2 = phase_seg2 */
+ __u32 tseg2_max;
+ __u32 sjw_max; /* Synchronisation jump width */
+ __u32 brp_min; /* Bit-rate prescaler */
+ __u32 brp_max;
+ __u32 brp_inc;
+};
+
+/*
+ * CAN clock parameters
+ */
+struct can_clock {
+ __u32 freq; /* CAN system clock frequency in Hz */
+};
+
+/*
+ * CAN operational and error states
+ */
+enum can_state {
+ CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */
+ CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */
+ CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */
+ CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */
+ CAN_STATE_STOPPED, /* Device is stopped */
+ CAN_STATE_SLEEPING, /* Device is sleeping */
+ CAN_STATE_MAX
+};
+
+/*
+ * CAN controller mode
+ */
+struct can_ctrlmode {
+ __u32 mask;
+ __u32 flags;
+};
+
+#define CAN_CTRLMODE_LOOPBACK 0x1 /* Loopback mode */
+#define CAN_CTRLMODE_LISTENONLY 0x2 /* Listen-only mode */
+#define CAN_CTRLMODE_3_SAMPLES 0x4 /* Triple sampling mode */
+
+/*
+ * CAN device statistics
+ */
+struct can_device_stats {
+ __u32 bus_error; /* Bus errors */
+ __u32 error_warning; /* Changes to error warning state */
+ __u32 error_passive; /* Changes to error passive state */
+ __u32 bus_off; /* Changes to bus off state */
+ __u32 arbitration_lost; /* Arbitration lost errors */
+ __u32 restarts; /* CAN controller re-starts */
+};
+
+/*
+ * CAN netlink interface
+ */
+enum {
+ IFLA_CAN_UNSPEC,
+ IFLA_CAN_BITTIMING,
+ IFLA_CAN_BITTIMING_CONST,
+ IFLA_CAN_CLOCK,
+ IFLA_CAN_STATE,
+ IFLA_CAN_CTRLMODE,
+ IFLA_CAN_RESTART_MS,
+ IFLA_CAN_RESTART,
+ __IFLA_CAN_MAX
+};
+
+#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1)
+
+#endif /* CAN_NETLINK_H */
next prev parent reply other threads:[~2009-05-12 9:43 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-12 9:42 [PATCH 0/2] iproute2: Support for CAN network devices Wolfgang Grandegger
2009-05-12 9:42 ` [PATCH 1/2] iproute2: Fixes an issue with cross-compilation Wolfgang Grandegger
2009-05-12 9:42 ` Wolfgang Grandegger [this message]
2009-05-20 7:54 ` [PATCH 0/2] iproute2: Support for CAN network devices Wolfgang Grandegger
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=20090512094248.764585154@denx.de \
--to=wg@grandegger.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.