.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * CAN driver for PEAK System PCAN-USB adapter |
---|
3 | 4 | * Derived from the PCAN project file driver/src/pcan_usb.c |
---|
.. | .. |
---|
6 | 7 | * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> |
---|
7 | 8 | * |
---|
8 | 9 | * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify it |
---|
11 | | - * under the terms of the GNU General Public License as published |
---|
12 | | - * by the Free Software Foundation; version 2 of the License. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope that it will be useful, but |
---|
15 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
17 | | - * General Public License for more details. |
---|
18 | 10 | */ |
---|
19 | 11 | #include <linux/netdevice.h> |
---|
20 | 12 | #include <linux/usb.h> |
---|
.. | .. |
---|
41 | 33 | #define PCAN_USB_CMD_ARGS_LEN 14 |
---|
42 | 34 | #define PCAN_USB_CMD_LEN (PCAN_USB_CMD_ARGS + \ |
---|
43 | 35 | PCAN_USB_CMD_ARGS_LEN) |
---|
| 36 | + |
---|
| 37 | +/* PCAN-USB commands */ |
---|
| 38 | +#define PCAN_USB_CMD_BITRATE 1 |
---|
| 39 | +#define PCAN_USB_CMD_SET_BUS 3 |
---|
| 40 | +#define PCAN_USB_CMD_DEVID 4 |
---|
| 41 | +#define PCAN_USB_CMD_SN 6 |
---|
| 42 | +#define PCAN_USB_CMD_REGISTER 9 |
---|
| 43 | +#define PCAN_USB_CMD_EXT_VCC 10 |
---|
| 44 | +#define PCAN_USB_CMD_ERR_FR 11 |
---|
| 45 | + |
---|
| 46 | +/* PCAN_USB_CMD_SET_BUS number arg */ |
---|
| 47 | +#define PCAN_USB_BUS_XCVER 2 |
---|
| 48 | +#define PCAN_USB_BUS_SILENT_MODE 3 |
---|
| 49 | + |
---|
| 50 | +/* PCAN_USB_CMD_xxx functions */ |
---|
| 51 | +#define PCAN_USB_GET 1 |
---|
| 52 | +#define PCAN_USB_SET 2 |
---|
44 | 53 | |
---|
45 | 54 | /* PCAN-USB command timeout (ms.) */ |
---|
46 | 55 | #define PCAN_USB_COMMAND_TIMEOUT 1000 |
---|
.. | .. |
---|
74 | 83 | #define PCAN_USB_ERROR_QOVR 0x40 |
---|
75 | 84 | #define PCAN_USB_ERROR_TXQFULL 0x80 |
---|
76 | 85 | |
---|
| 86 | +#define PCAN_USB_ERROR_BUS (PCAN_USB_ERROR_BUS_LIGHT | \ |
---|
| 87 | + PCAN_USB_ERROR_BUS_HEAVY | \ |
---|
| 88 | + PCAN_USB_ERROR_BUS_OFF) |
---|
| 89 | + |
---|
77 | 90 | /* SJA1000 modes */ |
---|
78 | 91 | #define SJA1000_MODE_NORMAL 0x00 |
---|
79 | 92 | #define SJA1000_MODE_INIT 0x01 |
---|
.. | .. |
---|
93 | 106 | #define PCAN_USB_REC_TS 4 |
---|
94 | 107 | #define PCAN_USB_REC_BUSEVT 5 |
---|
95 | 108 | |
---|
| 109 | +/* CAN bus events notifications selection mask */ |
---|
| 110 | +#define PCAN_USB_ERR_RXERR 0x02 /* ask for rxerr counter */ |
---|
| 111 | +#define PCAN_USB_ERR_TXERR 0x04 /* ask for txerr counter */ |
---|
| 112 | + |
---|
| 113 | +/* This mask generates an usb packet each time the state of the bus changes. |
---|
| 114 | + * In other words, its interest is to know which side among rx and tx is |
---|
| 115 | + * responsible of the change of the bus state. |
---|
| 116 | + */ |
---|
| 117 | +#define PCAN_USB_BERR_MASK (PCAN_USB_ERR_RXERR | PCAN_USB_ERR_TXERR) |
---|
| 118 | + |
---|
| 119 | +/* identify bus event packets with rx/tx error counters */ |
---|
| 120 | +#define PCAN_USB_ERR_CNT_DEC 0x00 /* counters are decreasing */ |
---|
| 121 | +#define PCAN_USB_ERR_CNT_INC 0x80 /* counters are increasing */ |
---|
| 122 | + |
---|
96 | 123 | /* private to PCAN-USB adapter */ |
---|
97 | 124 | struct pcan_usb { |
---|
98 | 125 | struct peak_usb_device dev; |
---|
99 | 126 | struct peak_time_ref time_ref; |
---|
100 | 127 | struct timer_list restart_timer; |
---|
| 128 | + struct can_berr_counter bec; |
---|
101 | 129 | }; |
---|
102 | 130 | |
---|
103 | 131 | /* incoming message context for decoding */ |
---|
.. | .. |
---|
180 | 208 | [1] = mode, |
---|
181 | 209 | }; |
---|
182 | 210 | |
---|
183 | | - return pcan_usb_send_cmd(dev, 9, 2, args); |
---|
| 211 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_REGISTER, PCAN_USB_SET, |
---|
| 212 | + args); |
---|
184 | 213 | } |
---|
185 | 214 | |
---|
186 | 215 | static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff) |
---|
.. | .. |
---|
189 | 218 | [0] = !!onoff, |
---|
190 | 219 | }; |
---|
191 | 220 | |
---|
192 | | - return pcan_usb_send_cmd(dev, 3, 2, args); |
---|
| 221 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_SET_BUS, PCAN_USB_BUS_XCVER, |
---|
| 222 | + args); |
---|
193 | 223 | } |
---|
194 | 224 | |
---|
195 | 225 | static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff) |
---|
.. | .. |
---|
198 | 228 | [0] = !!onoff, |
---|
199 | 229 | }; |
---|
200 | 230 | |
---|
201 | | - return pcan_usb_send_cmd(dev, 3, 3, args); |
---|
| 231 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_SET_BUS, |
---|
| 232 | + PCAN_USB_BUS_SILENT_MODE, args); |
---|
| 233 | +} |
---|
| 234 | + |
---|
| 235 | +/* send the cmd to be notified from bus errors */ |
---|
| 236 | +static int pcan_usb_set_err_frame(struct peak_usb_device *dev, u8 err_mask) |
---|
| 237 | +{ |
---|
| 238 | + u8 args[PCAN_USB_CMD_ARGS_LEN] = { |
---|
| 239 | + [0] = err_mask, |
---|
| 240 | + }; |
---|
| 241 | + |
---|
| 242 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_ERR_FR, PCAN_USB_SET, args); |
---|
202 | 243 | } |
---|
203 | 244 | |
---|
204 | 245 | static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) |
---|
.. | .. |
---|
207 | 248 | [0] = !!onoff, |
---|
208 | 249 | }; |
---|
209 | 250 | |
---|
210 | | - return pcan_usb_send_cmd(dev, 10, 2, args); |
---|
| 251 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args); |
---|
211 | 252 | } |
---|
212 | 253 | |
---|
213 | 254 | /* |
---|
.. | .. |
---|
231 | 272 | args[0] = btr1; |
---|
232 | 273 | args[1] = btr0; |
---|
233 | 274 | |
---|
234 | | - return pcan_usb_send_cmd(dev, 1, 2, args); |
---|
| 275 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_BITRATE, PCAN_USB_SET, args); |
---|
235 | 276 | } |
---|
236 | 277 | |
---|
237 | 278 | /* |
---|
.. | .. |
---|
315 | 356 | u8 args[PCAN_USB_CMD_ARGS_LEN]; |
---|
316 | 357 | int err; |
---|
317 | 358 | |
---|
318 | | - err = pcan_usb_wait_rsp(dev, 6, 1, args); |
---|
| 359 | + err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_SN, PCAN_USB_GET, args); |
---|
319 | 360 | if (err) { |
---|
320 | 361 | netdev_err(dev->netdev, "getting serial failure: %d\n", err); |
---|
321 | 362 | } else if (serial_number) { |
---|
.. | .. |
---|
336 | 377 | u8 args[PCAN_USB_CMD_ARGS_LEN]; |
---|
337 | 378 | int err; |
---|
338 | 379 | |
---|
339 | | - err = pcan_usb_wait_rsp(dev, 4, 1, args); |
---|
| 380 | + err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args); |
---|
340 | 381 | if (err) |
---|
341 | 382 | netdev_err(dev->netdev, "getting device id failure: %d\n", err); |
---|
342 | 383 | else if (device_id) |
---|
.. | .. |
---|
423 | 464 | new_state = CAN_STATE_ERROR_WARNING; |
---|
424 | 465 | break; |
---|
425 | 466 | } |
---|
426 | | - /* else: fall through */ |
---|
| 467 | + fallthrough; |
---|
427 | 468 | |
---|
428 | 469 | case CAN_STATE_ERROR_WARNING: |
---|
429 | 470 | if (n & PCAN_USB_ERROR_BUS_HEAVY) { |
---|
.. | .. |
---|
434 | 475 | new_state = CAN_STATE_BUS_OFF; |
---|
435 | 476 | break; |
---|
436 | 477 | } |
---|
437 | | - if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) { |
---|
| 478 | + if (n & ~PCAN_USB_ERROR_BUS) { |
---|
438 | 479 | /* |
---|
439 | 480 | * trick to bypass next comparison and process other |
---|
440 | 481 | * errors |
---|
.. | .. |
---|
458 | 499 | new_state = CAN_STATE_ERROR_WARNING; |
---|
459 | 500 | break; |
---|
460 | 501 | } |
---|
461 | | - if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) { |
---|
| 502 | + if (n & ~PCAN_USB_ERROR_BUS) { |
---|
462 | 503 | /* |
---|
463 | 504 | * trick to bypass next comparison and process other |
---|
464 | 505 | * errors |
---|
.. | .. |
---|
497 | 538 | |
---|
498 | 539 | case CAN_STATE_ERROR_PASSIVE: |
---|
499 | 540 | cf->can_id |= CAN_ERR_CRTL; |
---|
500 | | - cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE | |
---|
501 | | - CAN_ERR_CRTL_RX_PASSIVE; |
---|
| 541 | + cf->data[1] = (mc->pdev->bec.txerr > mc->pdev->bec.rxerr) ? |
---|
| 542 | + CAN_ERR_CRTL_TX_PASSIVE : |
---|
| 543 | + CAN_ERR_CRTL_RX_PASSIVE; |
---|
| 544 | + cf->data[6] = mc->pdev->bec.txerr; |
---|
| 545 | + cf->data[7] = mc->pdev->bec.rxerr; |
---|
| 546 | + |
---|
502 | 547 | mc->pdev->dev.can.can_stats.error_passive++; |
---|
503 | 548 | break; |
---|
504 | 549 | |
---|
505 | 550 | case CAN_STATE_ERROR_WARNING: |
---|
506 | 551 | cf->can_id |= CAN_ERR_CRTL; |
---|
507 | | - cf->data[1] |= CAN_ERR_CRTL_TX_WARNING | |
---|
508 | | - CAN_ERR_CRTL_RX_WARNING; |
---|
| 552 | + cf->data[1] = (mc->pdev->bec.txerr > mc->pdev->bec.rxerr) ? |
---|
| 553 | + CAN_ERR_CRTL_TX_WARNING : |
---|
| 554 | + CAN_ERR_CRTL_RX_WARNING; |
---|
| 555 | + cf->data[6] = mc->pdev->bec.txerr; |
---|
| 556 | + cf->data[7] = mc->pdev->bec.rxerr; |
---|
| 557 | + |
---|
509 | 558 | mc->pdev->dev.can.can_stats.error_warning++; |
---|
510 | 559 | break; |
---|
511 | 560 | |
---|
512 | 561 | case CAN_STATE_ERROR_ACTIVE: |
---|
513 | 562 | cf->can_id |= CAN_ERR_CRTL; |
---|
514 | 563 | cf->data[1] = CAN_ERR_CRTL_ACTIVE; |
---|
| 564 | + |
---|
| 565 | + /* sync local copies of rxerr/txerr counters */ |
---|
| 566 | + mc->pdev->bec.txerr = 0; |
---|
| 567 | + mc->pdev->bec.rxerr = 0; |
---|
515 | 568 | break; |
---|
516 | 569 | |
---|
517 | 570 | default: |
---|
518 | 571 | /* CAN_STATE_MAX (trick to handle other errors) */ |
---|
519 | | - cf->can_id |= CAN_ERR_CRTL; |
---|
520 | | - cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; |
---|
521 | | - mc->netdev->stats.rx_over_errors++; |
---|
522 | | - mc->netdev->stats.rx_errors++; |
---|
| 572 | + if (n & PCAN_USB_ERROR_TXQFULL) |
---|
| 573 | + netdev_dbg(mc->netdev, "device Tx queue full)\n"); |
---|
| 574 | + |
---|
| 575 | + if (n & PCAN_USB_ERROR_RXQOVR) { |
---|
| 576 | + netdev_dbg(mc->netdev, "data overrun interrupt\n"); |
---|
| 577 | + cf->can_id |= CAN_ERR_CRTL; |
---|
| 578 | + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; |
---|
| 579 | + mc->netdev->stats.rx_over_errors++; |
---|
| 580 | + mc->netdev->stats.rx_errors++; |
---|
| 581 | + } |
---|
| 582 | + |
---|
| 583 | + cf->data[6] = mc->pdev->bec.txerr; |
---|
| 584 | + cf->data[7] = mc->pdev->bec.rxerr; |
---|
523 | 585 | |
---|
524 | 586 | new_state = mc->pdev->dev.can.state; |
---|
525 | 587 | break; |
---|
.. | .. |
---|
537 | 599 | mc->netdev->stats.rx_packets++; |
---|
538 | 600 | mc->netdev->stats.rx_bytes += cf->can_dlc; |
---|
539 | 601 | netif_rx(skb); |
---|
| 602 | + |
---|
| 603 | + return 0; |
---|
| 604 | +} |
---|
| 605 | + |
---|
| 606 | +/* decode bus event usb packet: first byte contains rxerr while 2nd one contains |
---|
| 607 | + * txerr. |
---|
| 608 | + */ |
---|
| 609 | +static int pcan_usb_handle_bus_evt(struct pcan_usb_msg_context *mc, u8 ir) |
---|
| 610 | +{ |
---|
| 611 | + struct pcan_usb *pdev = mc->pdev; |
---|
| 612 | + |
---|
| 613 | + /* acccording to the content of the packet */ |
---|
| 614 | + switch (ir) { |
---|
| 615 | + case PCAN_USB_ERR_CNT_DEC: |
---|
| 616 | + case PCAN_USB_ERR_CNT_INC: |
---|
| 617 | + |
---|
| 618 | + /* save rx/tx error counters from in the device context */ |
---|
| 619 | + pdev->bec.rxerr = mc->ptr[1]; |
---|
| 620 | + pdev->bec.txerr = mc->ptr[2]; |
---|
| 621 | + break; |
---|
| 622 | + |
---|
| 623 | + default: |
---|
| 624 | + /* reserved */ |
---|
| 625 | + break; |
---|
| 626 | + } |
---|
540 | 627 | |
---|
541 | 628 | return 0; |
---|
542 | 629 | } |
---|
.. | .. |
---|
595 | 682 | break; |
---|
596 | 683 | |
---|
597 | 684 | case PCAN_USB_REC_BUSEVT: |
---|
598 | | - /* error frame/bus event */ |
---|
599 | | - if (n & PCAN_USB_ERROR_TXQFULL) |
---|
600 | | - netdev_dbg(mc->netdev, "device Tx queue full)\n"); |
---|
| 685 | + /* bus event notifications (get rxerr/txerr) */ |
---|
| 686 | + err = pcan_usb_handle_bus_evt(mc, n); |
---|
| 687 | + if (err) |
---|
| 688 | + return err; |
---|
601 | 689 | break; |
---|
602 | 690 | default: |
---|
603 | 691 | netdev_err(mc->netdev, "unexpected function %u\n", f); |
---|
.. | .. |
---|
781 | 869 | return 0; |
---|
782 | 870 | } |
---|
783 | 871 | |
---|
| 872 | +/* socket callback used to copy berr counters values received through USB */ |
---|
| 873 | +static int pcan_usb_get_berr_counter(const struct net_device *netdev, |
---|
| 874 | + struct can_berr_counter *bec) |
---|
| 875 | +{ |
---|
| 876 | + struct peak_usb_device *dev = netdev_priv(netdev); |
---|
| 877 | + struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); |
---|
| 878 | + |
---|
| 879 | + *bec = pdev->bec; |
---|
| 880 | + |
---|
| 881 | + /* must return 0 */ |
---|
| 882 | + return 0; |
---|
| 883 | +} |
---|
| 884 | + |
---|
784 | 885 | /* |
---|
785 | 886 | * start interface |
---|
786 | 887 | */ |
---|
787 | 888 | static int pcan_usb_start(struct peak_usb_device *dev) |
---|
788 | 889 | { |
---|
789 | 890 | struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); |
---|
| 891 | + int err; |
---|
790 | 892 | |
---|
791 | 893 | /* number of bits used in timestamps read from adapter struct */ |
---|
792 | 894 | peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb); |
---|
793 | 895 | |
---|
| 896 | + pdev->bec.rxerr = 0; |
---|
| 897 | + pdev->bec.txerr = 0; |
---|
| 898 | + |
---|
| 899 | + /* be notified on error counter changes (if requested by user) */ |
---|
| 900 | + if (dev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { |
---|
| 901 | + err = pcan_usb_set_err_frame(dev, PCAN_USB_BERR_MASK); |
---|
| 902 | + if (err) |
---|
| 903 | + netdev_warn(dev->netdev, |
---|
| 904 | + "Asking for BERR reporting error %u\n", |
---|
| 905 | + err); |
---|
| 906 | + } |
---|
| 907 | + |
---|
794 | 908 | /* if revision greater than 3, can put silent mode on/off */ |
---|
795 | 909 | if (dev->device_rev > 3) { |
---|
796 | | - int err; |
---|
797 | | - |
---|
798 | 910 | err = pcan_usb_set_silent(dev, |
---|
799 | 911 | dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY); |
---|
800 | 912 | if (err) |
---|
.. | .. |
---|
881 | 993 | .name = "PCAN-USB", |
---|
882 | 994 | .device_id = PCAN_USB_PRODUCT_ID, |
---|
883 | 995 | .ctrl_count = 1, |
---|
884 | | - .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, |
---|
| 996 | + .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | |
---|
| 997 | + CAN_CTRLMODE_BERR_REPORTING, |
---|
885 | 998 | .clock = { |
---|
886 | 999 | .freq = PCAN_USB_CRYSTAL_HZ / 2 , |
---|
887 | 1000 | }, |
---|
.. | .. |
---|
914 | 1027 | .dev_encode_msg = pcan_usb_encode_msg, |
---|
915 | 1028 | .dev_start = pcan_usb_start, |
---|
916 | 1029 | .dev_restart_async = pcan_usb_restart_async, |
---|
| 1030 | + .do_get_berr_counter = pcan_usb_get_berr_counter, |
---|
917 | 1031 | }; |
---|