Drop fake bittimings in favor of bitrate table
[elmcan.git] / module / elmcan.c
index e4552024d3ae3015657133f74fc87e0fba5eefe7..d5c289c82bc4c3b603115aca13592407cb420f89 100644 (file)
@@ -81,8 +81,6 @@ struct elmcan {
        struct tty_struct       *tty;
        struct net_device       *dev;
 
-       char                    ifname[IFNAMSIZ];
-
        /* Per-channel lock */
        spinlock_t              lock;
 
@@ -95,6 +93,11 @@ struct elmcan {
         */
        atomic_t                refcount;
 
+       /* Stop the channel on hardware failure.
+        * Once this is true, nothing will be sent to the TTY.
+        */
+       bool                    hw_failure;
+
        /* TTY TX helpers */
        struct work_struct      tx_work;        /* Flushes TTY TX buffer   */
        unsigned char           txbuf[32];
@@ -137,6 +140,8 @@ struct elmcan {
 static DEFINE_SPINLOCK(elmcan_discdata_lock);
 
 
+static inline void elm327_hw_failure(struct elmcan *elm);
+
 
 
  /************************************************************************
@@ -149,6 +154,10 @@ static void elm327_send(struct elmcan *elm, const void *buf, size_t len)
 {
        int actual;
 
+       if (elm->hw_failure) {
+               return;
+       }
+
        memcpy(elm->txbuf, buf, len);
 
        /* Order of next two lines is *very* important.
@@ -161,6 +170,12 @@ static void elm327_send(struct elmcan *elm, const void *buf, size_t len)
         */
        set_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
        actual = elm->tty->ops->write(elm->tty, elm->txbuf, len);
+       if (actual < 0) {
+               netdev_err(elm->dev, "Failed to write to tty %s.\n", elm->tty->name);
+               elm327_hw_failure(elm);
+               return;
+       }
+
        elm->txleft = len - actual;
        elm->txhead = elm->txbuf + actual;
 }
@@ -312,23 +327,29 @@ static void elm327_feed_frame_to_netdev(struct elmcan *elm, const struct can_fra
 
 
  /************************************************************************
-  *            ELM327: Panic handler                           *
+  *            ELM327: "Panic" handler                         *
   *                                                            *
   * (assumes elm->lock taken)                                  *
   ************************************************************************/
 
-static inline void elm327_panic(struct elmcan *elm)
+/* Called when we're out of ideas and just want it all to end. */
+static inline void elm327_hw_failure(struct elmcan *elm)
 {
-       struct can_frame frame = {0};
+       struct can_frame frame;
 
-       frame.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
+       memset(&frame, 0, sizeof(frame));
+       frame.can_id = CAN_ERR_FLAG;
        frame.can_dlc = CAN_ERR_DLC;
+       frame.data[5] = 'R';
+       frame.data[6] = 'I';
+       frame.data[7] = 'P';
        elm327_feed_frame_to_netdev(elm, &frame);
 
-       pr_err("ELM327 misbehaved. Re-initializing.\n");
+       netdev_err(elm->dev, "ELM327 misbehaved. "
+                       "Blocking further communication.\n");
 
-       elm->can.can_stats.restarts++;
-       elm327_init(elm);
+       elm->hw_failure = true;
+       can_bus_off(elm->dev);
 }
 
 
@@ -341,15 +362,16 @@ static inline void elm327_panic(struct elmcan *elm)
 
 static void elm327_parse_error(struct elmcan *elm, int len)
 {
-       struct can_frame frame = {0};
+       struct can_frame frame;
 
+       memset(&frame, 0, sizeof(frame));
        frame.can_id = CAN_ERR_FLAG;
        frame.can_dlc = CAN_ERR_DLC;
 
        switch(len) {
                case 17:
                        if (!memcmp(elm->rxbuf, "UNABLE TO CONNECT", 17)) {
-                               pr_err("The ELM327 reported UNABLE TO CONNECT. Please check your setup.\n");
+                               netdev_err(elm->dev, "The ELM327 reported UNABLE TO CONNECT. Please check your setup.\n");
                        }
                        break;
                case 11:
@@ -384,7 +406,7 @@ static void elm327_parse_error(struct elmcan *elm, int len)
                        break;
                case 5:
                        if (!memcmp(elm->rxbuf, "ERR", 3)) {
-                               pr_err("The ELM327 reported an ERR%c%c. Please power it off and on again.\n",
+                               netdev_err(elm->dev, "The ELM327 reported an ERR%c%c. Please power it off and on again.\n",
                                        elm->rxbuf[3], elm->rxbuf[4]);
                                frame.can_id |= CAN_ERR_CRTL;
                        }
@@ -400,11 +422,13 @@ static void elm327_parse_error(struct elmcan *elm, int len)
 
 static int elm327_parse_frame(struct elmcan *elm, int len)
 {
-       struct can_frame frame = {0};
+       struct can_frame frame;
        int hexlen;
        int datastart;
        int i;
 
+       memset(&frame, 0, sizeof(frame));
+
        /* Find first non-hex and non-space character:
         *  - In the simplest case, there is none.
         *  - For RTR frames, 'R' is the first non-hex character.
@@ -543,14 +567,14 @@ static void elm327_handle_prompt(struct elmcan *elm)
 {
        if (elm->cmds_todo) {
                struct can_frame *frame = &elm->can_frame;
-               char txbuf[20];
+               char local_txbuf[20];
 
                if (test_bit(ELM_TODO_INIT, &elm->cmds_todo)) {
                        elm327_send(elm, *elm->next_init_cmd, strlen(*elm->next_init_cmd));
                        elm->next_init_cmd++;
                        if (!(*elm->next_init_cmd)) {
                                clear_bit(ELM_TODO_INIT, &elm->cmds_todo);
-                               pr_info("%s: Initialization finished.\n", elm->dev->name);
+                               netdev_info(elm->dev, "Initialization finished.\n");
                        }
 
                        /* Some chips are unreliable and need extra time after
@@ -559,36 +583,56 @@ static void elm327_handle_prompt(struct elmcan *elm)
                         */
                        elm->state = ELM_NOTINIT;
                        elm327_kick_into_cmd_mode(elm);
+
+                       return;
+
                } else if (test_and_clear_bit(ELM_TODO_SILENT_MONITOR, &elm->cmds_todo)) {
-                       snprintf(txbuf, sizeof(txbuf), "ATCSM%i\r", !(!(elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)));
+                       sprintf(local_txbuf, "ATCSM%i\r",
+                               !(!(elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)));
+
                } else if (test_and_clear_bit(ELM_TODO_RESPONSES, &elm->cmds_todo)) {
-                       snprintf(txbuf, sizeof(txbuf), "ATR%i\r", !(elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
+                       sprintf(local_txbuf, "ATR%i\r",
+                               !(elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
+
                } else if (test_and_clear_bit(ELM_TODO_CAN_CONFIG, &elm->cmds_todo)) {
-                       snprintf(txbuf, sizeof(txbuf), "ATPB%04X\r", elm->can_config);
+                       sprintf(local_txbuf, "ATPB%04X\r",
+                               elm->can_config);
+
                } else if (test_and_clear_bit(ELM_TODO_CANID_29BIT_HIGH, &elm->cmds_todo)) {
-                       snprintf(txbuf, sizeof(txbuf), "ATCP%02X\r", (frame->can_id & CAN_EFF_MASK) >> 24);
+                       sprintf(local_txbuf, "ATCP%02X\r",
+                               (frame->can_id & CAN_EFF_MASK) >> 24);
+
                } else if (test_and_clear_bit(ELM_TODO_CANID_29BIT_LOW, &elm->cmds_todo)) {
-                       snprintf(txbuf, sizeof(txbuf), "ATSH%06X\r", frame->can_id & CAN_EFF_MASK & ((1 << 24) - 1));
+                       sprintf(local_txbuf, "ATSH%06X\r",
+                               frame->can_id & CAN_EFF_MASK & ((1 << 24) - 1));
+
                } else if (test_and_clear_bit(ELM_TODO_CANID_11BIT, &elm->cmds_todo)) {
-                       snprintf(txbuf, sizeof(txbuf), "ATSH%03X\r", frame->can_id & CAN_SFF_MASK);
+                       sprintf(local_txbuf, "ATSH%03X\r",
+                               frame->can_id & CAN_SFF_MASK);
+
                } else if (test_and_clear_bit(ELM_TODO_CAN_DATA, &elm->cmds_todo)) {
                        if (frame->can_id & CAN_RTR_FLAG) {
-                               snprintf(txbuf, sizeof(txbuf), "ATRTR\r");
+                               /* Send an RTR frame. Their DLC is fixed.
+                                * Some chips don't send them at all.
+                                */
+                               sprintf(local_txbuf, "ATRTR\r");
                        } else {
+                               /* Send a regular CAN data frame */
                                int i;
 
                                for (i = 0; i < frame->can_dlc; i++) {
-                                       sprintf(&txbuf[2*i], "%02X", frame->data[i]);
+                                       sprintf(&local_txbuf[2*i], "%02X",
+                                               frame->data[i]);
                                }
 
-                               sprintf(&txbuf[2*i], "\r");
+                               sprintf(&local_txbuf[2*i], "\r");
                        }
 
                        elm->drop_next_line = 1;
                        elm->state = ELM_RECEIVING;
                }
 
-               elm327_send(elm, txbuf, strlen(txbuf));
+               elm327_send(elm, local_txbuf, strlen(local_txbuf));
        } else {
                /* Enter CAN monitor mode */
                elm327_send(elm, "ATMA\r", 5);
@@ -657,8 +701,9 @@ static void elm327_parse_rxbuf(struct elmcan *elm)
                        /* Line exceeds buffer. It's probably all garbage.
                         * Did we even connect at the right baud rate?
                         */
-                       pr_err("RX buffer overflow. Faulty ELM327 connected?\n");
-                       elm327_panic(elm);
+                       netdev_err(elm->dev, "RX buffer overflow. Faulty ELM327 connected?\n");
+                       elm327_hw_failure(elm);
+                       return;
                } else if (len == elm->rxfill) {
                        if (elm->state == ELM_RECEIVING
                                && elm->rxbuf[elm->rxfill - 1] == ELM327_READY_CHAR) {
@@ -701,18 +746,6 @@ static void elm327_parse_rxbuf(struct elmcan *elm)
   * (takes elm->lock)                                          *
   ************************************************************************/
 
-static int elmcan_netdev_init(struct net_device *dev)
-{
-       struct elmcan *elm = netdev_priv(dev);
-
-       /* Copy the interface name here, so the SIOCGIFNAME case in
-        * elmcan_ldisc_ioctl() doesn't race against unregister_candev().
-        */
-       memcpy(elm->ifname, dev->name, IFNAMSIZ);
-
-       return 0;
-}
-
 /* Netdevice DOWN -> UP routine */
 static int elmcan_netdev_open(struct net_device *dev)
 {
@@ -720,6 +753,13 @@ static int elmcan_netdev_open(struct net_device *dev)
        int err;
 
        spin_lock_bh(&elm->lock);
+       if (elm->hw_failure) {
+               netdev_err(elm->dev, "Refusing to open interface after "
+                               "a hardware fault has been detected.\n");
+               spin_unlock_bh(&elm->lock);
+               return -EIO;
+       }
+
        if (elm->tty == NULL) {
                spin_unlock_bh(&elm->lock);
                return -ENODEV;
@@ -785,7 +825,7 @@ static netdev_tx_t elmcan_netdev_start_xmit(struct sk_buff *skb, struct net_devi
                goto out;
 
        if (!netif_running(dev))  {
-               pr_warn("%s: xmit: iface is down\n", dev->name);
+               netdev_warn(elm->dev, "xmit: iface is down.\n");
                goto out;
        }
 
@@ -793,6 +833,12 @@ static netdev_tx_t elmcan_netdev_start_xmit(struct sk_buff *skb, struct net_devi
         * See Documentation/networking/netdevices.txt
         */
        spin_lock(&elm->lock);
+
+       /* We shouldn't get here after a hardware fault:
+        * can_bus_off() calls netif_carrier_off()
+        */
+       BUG_ON(elm->hw_failure);
+
        if (elm->tty == NULL
                || elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
                spin_unlock(&elm->lock);
@@ -820,7 +866,6 @@ static int elmcan_netdev_change_mtu(struct net_device *dev, int new_mtu)
 }
 
 static const struct net_device_ops elmcan_netdev_ops = {
-       .ndo_init       = elmcan_netdev_init,
        .ndo_open       = elmcan_netdev_open,
        .ndo_stop       = elmcan_netdev_close,
        .ndo_start_xmit = elmcan_netdev_start_xmit,
@@ -894,10 +939,10 @@ static void elmcan_ldisc_rx(struct tty_struct *tty,
        /* Read the characters out of the buffer */
        while (count-- && elm->rxfill < sizeof(elm->rxbuf)) {
                if (fp && *fp++) {
-                       pr_err("Error in received character stream. Check your wiring.");
+                       netdev_err(elm->dev, "Error in received character stream. Check your wiring.");
 
                        spin_lock_bh(&elm->lock);
-                       elm327_panic(elm);
+                       elm327_hw_failure(elm);
                        spin_unlock_bh(&elm->lock);
 
                        put_elm(elm);
@@ -910,10 +955,10 @@ static void elmcan_ldisc_rx(struct tty_struct *tty,
        }
 
        if (count >= 0) {
-               pr_err("Receive buffer overflowed. Bad chip or wiring?");
+               netdev_err(elm->dev, "Receive buffer overflowed. Bad chip or wiring?");
 
                spin_lock_bh(&elm->lock);
-               elm327_panic(elm);
+               elm327_hw_failure(elm);
                spin_unlock_bh(&elm->lock);
 
                put_elm(elm);
@@ -940,7 +985,11 @@ static void elmcan_ldisc_tx_worker(struct work_struct *work)
        ssize_t actual;
 
        spin_lock_bh(&elm->lock);
-       /* First make sure we're connected. */
+       if (elm->hw_failure) {
+               spin_unlock_bh(&elm->lock);
+               return;
+       }
+
        if (!elm->tty || !netif_running(elm->dev)) {
                spin_unlock_bh(&elm->lock);
                return;
@@ -958,8 +1007,10 @@ static void elmcan_ldisc_tx_worker(struct work_struct *work)
 
        actual = elm->tty->ops->write(elm->tty, elm->txhead, elm->txleft);
        if (actual < 0) {
-               pr_err("Failed to write to tty for %s.\n", elm->dev->name);
-               elm327_panic(elm);
+               netdev_err(elm->dev, "Failed to write to tty %s.\n", elm->tty->name);
+               elm327_hw_failure(elm);
+               spin_unlock_bh(&elm->lock);
+               return;
        }
 
        elm->txleft -= actual;
@@ -986,19 +1037,30 @@ static void elmcan_ldisc_tx_wakeup(struct tty_struct *tty)
 
 
 
-/* Some fake bit timings to allow bitrate setting */
-static const struct can_bittiming_const elmcan_bittiming_const = {
-       .name = "elmcan",
-       .tseg1_min = 1,
-       .tseg1_max = 1,
-       .tseg2_min = 0,
-       .tseg2_max = 0,
-       .sjw_max = 1,
-       .brp_min = 1,
-       .brp_max = 500,
-       .brp_inc = 1,
+/* ELM327 can only handle bitrates that are integer divisors of 500 kHz,
+ * or 7/8 of that. Divisors are 1 to 64.
+ * Currently we don't implement support for 7/8 rates.
+ */
+static const u32 elmcan_bitrate_const[64] = {
+       7812, 7936, 8064, 8196, 8333, 8474, 8620, 8771,
+       8928, 9090, 9259, 9433, 9615, 9803, 10000, 10204,
+       10416, 10638, 10869, 11111, 11363, 11627, 11904, 12195,
+       12500, 12820, 13157, 13513, 13888, 14285, 14705, 15151,
+       15625, 16129, 16666, 17241, 17857, 18518, 19230, 20000,
+       20833, 21739, 22727, 23809, 25000, 26315, 27777, 29411,
+       31250, 33333, 35714, 38461, 41666, 45454, 50000, 55555,
+       62500, 71428, 83333, 100000, 125000, 166666, 250000, 500000
 };
 
+/* Dummy function to claim we're changing the bitrate.
+ * We actually do this when opening the net device.
+ */
+static int elmcan_do_set_bittiming(struct net_device *netdev)
+{
+       return 0;
+}
+
+
 /*
  * Open the high-level part of the elmcan channel.
  * This function is called by the TTY module when the
@@ -1034,8 +1096,9 @@ static int elmcan_ldisc_open(struct tty_struct *tty)
 
        /* Configure CAN metadata */
        elm->can.state = CAN_STATE_STOPPED;
-       elm->can.clock.freq = 1000000;
-       elm->can.bittiming_const = &elmcan_bittiming_const;
+       elm->can.bitrate_const = elmcan_bitrate_const;
+       elm->can.bitrate_const_cnt = ARRAY_SIZE(elmcan_bitrate_const);
+       elm->can.do_set_bittiming = elmcan_do_set_bittiming;
        elm->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY;
 
        /* Configure netlink interface */
@@ -1124,14 +1187,13 @@ static int elmcan_ldisc_ioctl(struct tty_struct *tty, struct file *file,
        struct elmcan *elm = get_elm(tty);
        unsigned int tmp;
 
-       /* First make sure we're connected. */
        if (!elm)
                return -EINVAL;
 
        switch (cmd) {
        case SIOCGIFNAME:
-               tmp = strlen(elm->ifname) + 1;
-               if (copy_to_user((void __user *)arg, elm->ifname, tmp)) {
+               tmp = strlen(elm->dev->name) + 1;
+               if (copy_to_user((void __user *)arg, elm->dev->name, tmp)) {
                        put_elm(elm);
                        return -EFAULT;
                }