diff options
author | Andreas Gröger <andreas24groeger@gmail.com> | 2016-05-06 04:04:37 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2016-05-09 05:07:28 -0400 |
commit | b16e368ed6193d8d1774b4cc874d7892d55c4780 (patch) | |
tree | 44ac40c4a84432521612c7ca648e9f806de0dcc4 /drivers/net/can | |
parent | bb208f144cf3f59d8f89a09a80efd04389718907 (diff) |
can: janz-ican3: error handling for CAL/CANopen firmware
My patch of May 2015 was missing the changed handling of error
indications. With CAL/CANopen firmware the NMTS-SlaveEventIndication
must be used instead of CAN-EventIndication. An appropriate slave node
must be configured to report the errors.
In our department (about 15 development systems with Janz ICAN3-
modules with firmware 1.48, my system also with firmware ICANOS 1.35)
we use the driver with this patch for about one year: no known problems.
Signed-off-by: Andreas Gröger <andreas24groeger@gmail.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r-- | drivers/net/can/janz-ican3.c | 104 |
1 files changed, 95 insertions, 9 deletions
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 5d04f5464faf..f13bb8d9bb84 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c | |||
@@ -84,6 +84,7 @@ | |||
84 | #define MSG_COFFREQ 0x42 | 84 | #define MSG_COFFREQ 0x42 |
85 | #define MSG_CONREQ 0x43 | 85 | #define MSG_CONREQ 0x43 |
86 | #define MSG_CCONFREQ 0x47 | 86 | #define MSG_CCONFREQ 0x47 |
87 | #define MSG_NMTS 0xb0 | ||
87 | #define MSG_LMTS 0xb4 | 88 | #define MSG_LMTS 0xb4 |
88 | 89 | ||
89 | /* | 90 | /* |
@@ -130,6 +131,22 @@ | |||
130 | 131 | ||
131 | #define ICAN3_CAN_DLC_MASK 0x0f | 132 | #define ICAN3_CAN_DLC_MASK 0x0f |
132 | 133 | ||
134 | /* Janz ICAN3 NMTS subtypes */ | ||
135 | #define NMTS_CREATE_NODE_REQ 0x0 | ||
136 | #define NMTS_SLAVE_STATE_IND 0x8 | ||
137 | #define NMTS_SLAVE_EVENT_IND 0x9 | ||
138 | |||
139 | /* Janz ICAN3 LMTS subtypes */ | ||
140 | #define LMTS_BUSON_REQ 0x0 | ||
141 | #define LMTS_BUSOFF_REQ 0x1 | ||
142 | #define LMTS_CAN_CONF_REQ 0x2 | ||
143 | |||
144 | /* Janz ICAN3 NMTS Event indications */ | ||
145 | #define NE_LOCAL_OCCURRED 0x3 | ||
146 | #define NE_LOCAL_RESOLVED 0x2 | ||
147 | #define NE_REMOTE_OCCURRED 0xc | ||
148 | #define NE_REMOTE_RESOLVED 0x8 | ||
149 | |||
133 | /* | 150 | /* |
134 | * SJA1000 Status and Error Register Definitions | 151 | * SJA1000 Status and Error Register Definitions |
135 | * | 152 | * |
@@ -800,21 +817,41 @@ static int ican3_set_bus_state(struct ican3_dev *mod, bool on) | |||
800 | return ican3_send_msg(mod, &msg); | 817 | return ican3_send_msg(mod, &msg); |
801 | 818 | ||
802 | } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) { | 819 | } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) { |
820 | /* bittiming + can-on/off request */ | ||
803 | memset(&msg, 0, sizeof(msg)); | 821 | memset(&msg, 0, sizeof(msg)); |
804 | msg.spec = MSG_LMTS; | 822 | msg.spec = MSG_LMTS; |
805 | if (on) { | 823 | if (on) { |
806 | msg.len = cpu_to_le16(4); | 824 | msg.len = cpu_to_le16(4); |
807 | msg.data[0] = 0; | 825 | msg.data[0] = LMTS_BUSON_REQ; |
808 | msg.data[1] = 0; | 826 | msg.data[1] = 0; |
809 | msg.data[2] = btr0; | 827 | msg.data[2] = btr0; |
810 | msg.data[3] = btr1; | 828 | msg.data[3] = btr1; |
811 | } else { | 829 | } else { |
812 | msg.len = cpu_to_le16(2); | 830 | msg.len = cpu_to_le16(2); |
813 | msg.data[0] = 1; | 831 | msg.data[0] = LMTS_BUSOFF_REQ; |
814 | msg.data[1] = 0; | 832 | msg.data[1] = 0; |
815 | } | 833 | } |
834 | res = ican3_send_msg(mod, &msg); | ||
835 | if (res) | ||
836 | return res; | ||
816 | 837 | ||
817 | return ican3_send_msg(mod, &msg); | 838 | if (on) { |
839 | /* create NMT Slave Node for error processing | ||
840 | * class 2 (with error capability, see CiA/DS203-1) | ||
841 | * id 1 | ||
842 | * name locnod1 (must be exactly 7 bytes) | ||
843 | */ | ||
844 | memset(&msg, 0, sizeof(msg)); | ||
845 | msg.spec = MSG_NMTS; | ||
846 | msg.len = cpu_to_le16(11); | ||
847 | msg.data[0] = NMTS_CREATE_NODE_REQ; | ||
848 | msg.data[1] = 0; | ||
849 | msg.data[2] = 2; /* node class */ | ||
850 | msg.data[3] = 1; /* node id */ | ||
851 | strcpy(msg.data + 4, "locnod1"); /* node name */ | ||
852 | return ican3_send_msg(mod, &msg); | ||
853 | } | ||
854 | return 0; | ||
818 | } | 855 | } |
819 | return -ENOTSUPP; | 856 | return -ENOTSUPP; |
820 | } | 857 | } |
@@ -849,12 +886,23 @@ static int ican3_set_buserror(struct ican3_dev *mod, u8 quota) | |||
849 | { | 886 | { |
850 | struct ican3_msg msg; | 887 | struct ican3_msg msg; |
851 | 888 | ||
852 | memset(&msg, 0, sizeof(msg)); | 889 | if (mod->fwtype == ICAN3_FWTYPE_ICANOS) { |
853 | msg.spec = MSG_CCONFREQ; | 890 | memset(&msg, 0, sizeof(msg)); |
854 | msg.len = cpu_to_le16(2); | 891 | msg.spec = MSG_CCONFREQ; |
855 | msg.data[0] = 0x00; | 892 | msg.len = cpu_to_le16(2); |
856 | msg.data[1] = quota; | 893 | msg.data[0] = 0x00; |
857 | 894 | msg.data[1] = quota; | |
895 | } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) { | ||
896 | memset(&msg, 0, sizeof(msg)); | ||
897 | msg.spec = MSG_LMTS; | ||
898 | msg.len = cpu_to_le16(4); | ||
899 | msg.data[0] = LMTS_CAN_CONF_REQ; | ||
900 | msg.data[1] = 0x00; | ||
901 | msg.data[2] = 0x00; | ||
902 | msg.data[3] = quota; | ||
903 | } else { | ||
904 | return -ENOTSUPP; | ||
905 | } | ||
858 | return ican3_send_msg(mod, &msg); | 906 | return ican3_send_msg(mod, &msg); |
859 | } | 907 | } |
860 | 908 | ||
@@ -1150,6 +1198,41 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) | |||
1150 | } | 1198 | } |
1151 | } | 1199 | } |
1152 | 1200 | ||
1201 | /* Handle NMTS Slave Event Indication Messages from the firmware */ | ||
1202 | static void ican3_handle_nmtsind(struct ican3_dev *mod, struct ican3_msg *msg) | ||
1203 | { | ||
1204 | u16 subspec; | ||
1205 | |||
1206 | subspec = msg->data[0] + msg->data[1] * 0x100; | ||
1207 | if (subspec == NMTS_SLAVE_EVENT_IND) { | ||
1208 | switch (msg->data[2]) { | ||
1209 | case NE_LOCAL_OCCURRED: | ||
1210 | case NE_LOCAL_RESOLVED: | ||
1211 | /* now follows the same message as Raw ICANOS CEVTIND | ||
1212 | * shift the data at the same place and call this method | ||
1213 | */ | ||
1214 | le16_add_cpu(&msg->len, -3); | ||
1215 | memmove(msg->data, msg->data + 3, le16_to_cpu(msg->len)); | ||
1216 | ican3_handle_cevtind(mod, msg); | ||
1217 | break; | ||
1218 | case NE_REMOTE_OCCURRED: | ||
1219 | case NE_REMOTE_RESOLVED: | ||
1220 | /* should not occurre, ignore */ | ||
1221 | break; | ||
1222 | default: | ||
1223 | netdev_warn(mod->ndev, "unknown NMTS event indication %x\n", | ||
1224 | msg->data[2]); | ||
1225 | break; | ||
1226 | } | ||
1227 | } else if (subspec == NMTS_SLAVE_STATE_IND) { | ||
1228 | /* ignore state indications */ | ||
1229 | } else { | ||
1230 | netdev_warn(mod->ndev, "unhandled NMTS indication %x\n", | ||
1231 | subspec); | ||
1232 | return; | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1153 | static void ican3_handle_unknown_message(struct ican3_dev *mod, | 1236 | static void ican3_handle_unknown_message(struct ican3_dev *mod, |
1154 | struct ican3_msg *msg) | 1237 | struct ican3_msg *msg) |
1155 | { | 1238 | { |
@@ -1179,6 +1262,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) | |||
1179 | case MSG_INQUIRY: | 1262 | case MSG_INQUIRY: |
1180 | ican3_handle_inquiry(mod, msg); | 1263 | ican3_handle_inquiry(mod, msg); |
1181 | break; | 1264 | break; |
1265 | case MSG_NMTS: | ||
1266 | ican3_handle_nmtsind(mod, msg); | ||
1267 | break; | ||
1182 | default: | 1268 | default: |
1183 | ican3_handle_unknown_message(mod, msg); | 1269 | ican3_handle_unknown_message(mod, msg); |
1184 | break; | 1270 | break; |