| .. | .. |
|---|
| 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 | }; |
|---|