]> rtime.felk.cvut.cz Git - linux-lin.git/blobdiff - sllin/sllin.c
sllin: Some more corrections to Slave mode.
[linux-lin.git] / sllin / sllin.c
index e07558994abde83283d66126ce0dc2902d390c3b..b754e93ab021f4812ff950c8947154e71e2c0c9b 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/* 
  * sllin.c - serial line LIN interface driver (using tty line discipline)
  *
  * This file is derived from drivers/net/can/slcan.c
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
  *
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
+ * Idea:       Oliver Hartkopp <oliver.hartkopp@volkswagen.de> 
+ * Copyright:  (c) 2011 Czech Technical University in Prague
+ *             (c) 2011 Volkswagen Group Research
+ * Authors:    Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             Rostislav Lisovy <lisovy@kormus.cz>
+ *             Michal Sojka <sojkam1@fel.cvut.cz>
+ * Funded by:  Volkswagen Group Research
  */
 
 #define DEBUG          1 /* Enables pr_debug() printouts */
@@ -70,11 +75,19 @@ static __initdata const char banner[] =
 MODULE_ALIAS_LDISC(N_SLLIN);
 MODULE_DESCRIPTION("serial line LIN interface");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("");
+MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
 
 #define SLLIN_MAGIC            0x53CA
 /* #define BREAK_BY_BAUD */
 
+static int master = true;
+static int baudrate = 0; /* Use LIN_DEFAULT_BAUDRATE when not set */
+
+module_param(master, bool, 0);
+MODULE_PARM_DESC(master, "LIN interface is Master device");
+module_param(baudrate, int, 0);
+MODULE_PARM_DESC(baudrate, "Baudrate of LIN interface");
+
 static int maxdev = 10;                /* MAX number of SLLIN channels;
                                   This can be overridden with
                                   insmod sllin.ko maxdev=nnn   */
@@ -91,7 +104,7 @@ MODULE_PARM_DESC(maxdev, "Maximum number of sllin interfaces");
 #define SLLIN_BUFF_DATA                3
 
 #define SLLIN_SAMPLES_PER_CHAR 10
-#define SLLIN_CHARS_TO_TIMEOUT 12
+#define SLLIN_CHARS_TO_TIMEOUT 24
 
 enum slstate {
        SLSTATE_IDLE = 0,
@@ -133,6 +146,8 @@ struct sllin {
        char                    id_to_send;     /* there is ID to be sent */
        char                    data_to_send;   /* there are data to be sent */
        char                    resp_len_known; /* Length of the response is known */
+       char                    header_received;/* In Slave mode, set when header was already
+                                                  received */
 
        unsigned long           flags;          /* Flag values/ mode etc     */
 #define SLF_INUSE              0               /* Channel in use            */
@@ -188,10 +203,16 @@ static int sltty_change_speed(struct tty_struct *tty, unsigned speed)
        mutex_lock(&tty->termios_mutex);
 
        old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
+
+       cflag = CS8 | CREAD | CLOCAL | HUPCL;
        cflag &= ~(CBAUD | CIBAUD);
        cflag |= BOTHER;
        tty->termios->c_cflag = cflag;
+       tty->termios->c_oflag = 0;
+       tty->termios->c_lflag = 0;
+
+       /* Enable interrupt when UART-Break or Framing error received */
+       tty->termios->c_iflag = BRKINT | INPCK;
 
        tty_encode_baud_rate(tty, speed, speed);
 
@@ -203,7 +224,6 @@ static int sltty_change_speed(struct tty_struct *tty, unsigned speed)
        return 0;
 }
 
-
 /* Send one can_frame to the network layer */
 static void sllin_send_canfr(struct sllin *sl, canid_t id, char *data, int len)
 {
@@ -230,8 +250,6 @@ static void sllin_send_canfr(struct sllin *sl, canid_t id, char *data, int len)
 
        sl->dev->stats.rx_packets++;
        sl->dev->stats.rx_bytes += cf.can_dlc;
-
-
 }
 
 /**
@@ -247,6 +265,12 @@ static void sll_bump(struct sllin *sl)
                sl->rx_cnt - SLLIN_BUFF_DATA - 1); /* without checksum */
 }
 
+static void sll_send_rtr(struct sllin *sl)
+{
+       sllin_send_canfr(sl, (sl->rx_buff[SLLIN_BUFF_ID] & LIN_ID_MASK) |
+               CAN_RTR_FLAG, NULL, 0);
+}
+
 /*
  * Called by the driver when there's room for more data.  If we have
  * more packets to send, we send them here.
@@ -408,8 +432,7 @@ static void sllin_receive_buf(struct tty_struct *tty,
                              const unsigned char *cp, char *fp, int count)
 {
        struct sllin *sl = (struct sllin *) tty->disc_data;
-
-       pr_debug("sllin: sllin_receive_buf invoked\n");
+       pr_debug("sllin: sllin_receive_buf invoked, count = %u\n", count);
 
        if (!sl || sl->magic != SLLIN_MAGIC || !netif_running(sl->dev))
                return;
@@ -417,19 +440,27 @@ static void sllin_receive_buf(struct tty_struct *tty,
        /* Read the characters out of the buffer */
        while (count--) {
                if (fp && *fp++) {
-                       if (!test_and_set_bit(SLF_ERROR, &sl->flags))
-                               sl->dev->stats.rx_errors++;
                        pr_debug("sllin: sllin_receive_buf char 0x%02x ignored "
                                "due marker 0x%02x, flags 0x%lx\n",
                                *cp, *(fp-1), sl->flags);
-                       cp++;
-                       continue;
+
+                       if (sl->lin_master == true) { /* Report error */
+                               set_bit(SLF_ERROR, &sl->flags);
+                               wake_up(&sl->kwt_wq);
+                               return;
+                       } else { /* Received Break */
+                               sl->rx_cnt = 0;
+                               sl->rx_expect = SLLIN_BUFF_ID + 1;
+                               sl->header_received = false;
+                               return;
+                       }
                }
 
                if (sl->rx_cnt < SLLIN_BUFF_LEN) {
 #ifndef BREAK_BY_BAUD
-                       /* We didn't receive Break character */
+                       /* We didn't receive Break character -- fake it! */
                        if ((sl->rx_cnt == SLLIN_BUFF_BREAK) && (*cp == 0x55)) {
+                               pr_debug("sllin: LIN_RX[%d]: 0x00\n", sl->rx_cnt);
                                sl->rx_buff[sl->rx_cnt++] = 0x00;
                        }
 #endif
@@ -438,12 +469,50 @@ static void sllin_receive_buf(struct tty_struct *tty,
                }
        }
 
-       if (sl->rx_cnt >= sl->rx_expect) {
-               set_bit(SLF_RXEVENT, &sl->flags);
-               wake_up(&sl->kwt_wq);
-               pr_debug("sllin: sllin_receive_buf count %d, wakeup\n", sl->rx_cnt);
-       } else {
-               pr_debug("sllin: sllin_receive_buf count %d, waiting\n", sl->rx_cnt);
+       if (sl->lin_master == true) {
+               if (sl->rx_cnt >= sl->rx_expect) { /* Probably whole frame was received */
+                       set_bit(SLF_RXEVENT, &sl->flags);
+                       wake_up(&sl->kwt_wq);
+                       pr_debug("sllin: sllin_receive_buf count %d, wakeup\n", sl->rx_cnt);
+               } else {
+                       pr_debug("sllin: sllin_receive_buf count %d, waiting\n", sl->rx_cnt);
+               }
+       } else { /* LIN slave */
+               int lin_id;
+               struct sllin_conf_entry *sce;
+
+               pr_debug("sllin: rx_cnt = %u; header_received = %u\n",
+                       sl->rx_cnt, sl->header_received);
+
+               /* Whole header was received */
+               if ((sl->rx_cnt >= (SLLIN_BUFF_ID + 1)) &&
+                       (sl->header_received == false))
+               {
+                       lin_id = sl->rx_buff[SLLIN_BUFF_ID] & LIN_ID_MASK;
+                       sce = &sl->linfr_cache[lin_id];
+
+                       /* Is the length of data set in frame cache? */
+                       if (sce->frame_fl & LIN_LOC_SLAVE_CACHE)
+                               sl->rx_expect += sce->dlc;
+                       else
+                               sl->rx_expect += 2; /* 1 data byte + checksum */
+
+                       sl->header_received = true;
+                       sll_send_rtr(sl);
+               }
+
+               /* Probably whole frame was received */
+               if ((sl->rx_cnt >= sl->rx_expect) && (sl->rx_cnt > SLLIN_BUFF_DATA)) {
+                       sll_bump(sl);
+                       pr_debug("sllin: Received LIN header & LIN response. "
+                               "rx_cnt = %u, rx_expect = %u\n", sl->rx_cnt,
+                               sl->rx_expect);
+
+                       /* Prepare for reception of new header */
+                       sl->rx_cnt = 0;
+                       sl->rx_expect = SLLIN_BUFF_ID + 1;
+                       sl->header_received = false;
+               }
        }
 }
 
@@ -459,6 +528,20 @@ static void sllin_receive_buf(struct tty_struct *tty,
  */
 void sllin_report_error(struct sllin *sl, int err)
 {
+       switch (err) {
+               case LIN_ERR_CHECKSUM:
+                       sl->dev->stats.rx_crc_errors++;
+                       break;
+
+               case LIN_ERR_RX_TIMEOUT:
+                       sl->dev->stats.rx_errors++;
+                       break;
+
+               case LIN_ERR_FRAMING:
+                       sl->dev->stats.rx_frame_errors++;
+                       break;
+       }
+
        sllin_send_canfr(sl, 0 | CAN_EFF_FLAG |
                (err & ~LIN_ID_MASK), NULL, 0);
 }
@@ -553,6 +636,16 @@ int sllin_setup_msg(struct sllin *sl, int mode, int id,
        return 0;
 }
 
+static void sllin_reset_buffs(struct sllin *sl)
+{
+       sl->rx_cnt = 0;
+       sl->rx_expect = 0;
+       sl->rx_lim = sl->lin_master ? 0 : SLLIN_BUFF_LEN;
+       sl->tx_cnt = 0;
+       sl->tx_lim = 0;
+       sl->id_to_send = false;
+       sl->data_to_send = false;
+}
 
 int sllin_send_tx_buff(struct sllin *sl)
 {
@@ -744,6 +837,7 @@ int sllin_kwthread(void *ptr)
                        test_bit(SLF_RXEVENT, &sl->flags) ||
                        test_bit(SLF_TXEVENT, &sl->flags) ||
                        test_bit(SLF_TMOUTEVENT, &sl->flags) ||
+                       test_bit(SLF_ERROR, &sl->flags) ||
                        (((sl->lin_state == SLSTATE_IDLE) ||
                                (sl->lin_state == SLSTATE_RESPONSE_WAIT))
                                && test_bit(SLF_MSGEVENT, &sl->flags)));
@@ -752,19 +846,30 @@ int sllin_kwthread(void *ptr)
                        pr_debug("sllin: sllin_kthread RXEVENT\n");
                }
 
+               if (test_and_clear_bit(SLF_ERROR, &sl->flags)) {
+                       unsigned long usleep_range_min;
+                       unsigned long usleep_range_max;
+                       hrtimer_cancel(&sl->rx_timer);
+                       pr_debug("sllin: sllin_kthread ERROR\n");
+
+                       if (sl->lin_state != SLSTATE_IDLE)
+                               sllin_report_error(sl, LIN_ERR_FRAMING);
+
+                       usleep_range_min = (1000000l * SLLIN_SAMPLES_PER_CHAR * 10) /
+                                               sl->lin_baud;
+                       usleep_range_max = usleep_range_min + 50;
+                       usleep_range(usleep_range_min, usleep_range_max);
+                       sllin_reset_buffs(sl);
+                       sl->lin_state = SLSTATE_IDLE;
+               }
+
                if (test_and_clear_bit(SLF_TXEVENT, &sl->flags)) {
                        pr_debug("sllin: sllin_kthread TXEVENT\n");
                }
 
                if (test_and_clear_bit(SLF_TMOUTEVENT, &sl->flags)) {
                        pr_debug("sllin: sllin_kthread TMOUTEVENT\n");
-                       sl->rx_cnt = 0;
-                       sl->rx_expect = 0;
-                       sl->rx_lim = sl->lin_master ? 0 : SLLIN_BUFF_LEN;
-                       sl->tx_cnt = 0;
-                       sl->tx_lim = 0;
-                       sl->id_to_send = false;
-                       sl->data_to_send = false;
+                       sllin_reset_buffs(sl);
 
                        sl->lin_state = SLSTATE_IDLE;
                }
@@ -823,6 +928,9 @@ int sllin_kwthread(void *ptr)
                                clear_bit(SLF_MSGEVENT, &sl->flags);
                                kfree_skb(sl->tx_req_skb);
                                netif_wake_queue(sl->dev);
+                               hrtimer_start(&sl->rx_timer,
+                                       ktime_add(ktime_get(), sl->rx_timer_timeout),
+                                       HRTIMER_MODE_ABS);
                                break;
 
                        case SLSTATE_BREAK_SENT:
@@ -838,6 +946,7 @@ int sllin_kwthread(void *ptr)
                                break;
 
                        case SLSTATE_ID_SENT:
+                               hrtimer_cancel(&sl->rx_timer);
                                sl->id_to_send = false;
                                if (sl->data_to_send) {
                                        sllin_send_tx_buff(sl);
@@ -867,6 +976,8 @@ int sllin_kwthread(void *ptr)
 
                                        lin_buff = (sl->lin_master) ? sl->tx_buff : sl->rx_buff;
                                        if (cf->can_id == (lin_buff[SLLIN_BUFF_ID] & LIN_ID_MASK)) {
+                                               hrtimer_cancel(&sl->rx_timer);
+                                               pr_debug("sllin: received LIN response in a CAN frame.\n");
                                                if (sllin_setup_msg(sl, SLLIN_STPMSG_RESPONLY,
                                                        cf->can_id & LIN_ID_MASK,
                                                        cf->data, cf->can_dlc) != -1) {
@@ -905,7 +1016,6 @@ int sllin_kwthread(void *ptr)
                                if (sllin_rx_validate(sl) == -1) {
                                        pr_debug("sllin: RX validation failed.\n");
                                        sllin_report_error(sl, LIN_ERR_CHECKSUM);
-                                       /* FIXME tx_stat.err++ */
                                } else {
                                        /* Send CAN non-RTR frame with data */
                                        pr_debug("sllin: sending NON-RTR CAN"
@@ -922,6 +1032,7 @@ int sllin_kwthread(void *ptr)
                                if (sl->rx_cnt < sl->tx_lim)
                                        continue;
 
+                               hrtimer_cancel(&sl->rx_timer);
                                sll_bump(sl); /* send packet to the network layer */
                                pr_debug("sllin: response sent ID %d len %d\n",
                                        sl->rx_buff[SLLIN_BUFF_ID], sl->rx_cnt - SLLIN_BUFF_DATA - 1);
@@ -930,12 +1041,6 @@ int sllin_kwthread(void *ptr)
                                sl->lin_state = SLSTATE_IDLE;
                                break;
                }
-
-
-
-
-               /* sl->dev->stats.tx_packets++; send frames statistic */
-               /* netif_wake_queue(sl->dev); allow next Tx packet arrival */
        }
 
        hrtimer_cancel(&sl->rx_timer);
@@ -1069,17 +1174,18 @@ static int sllin_open(struct tty_struct *tty)
 
        if (!test_bit(SLF_INUSE, &sl->flags)) {
                /* Perform the low-level SLLIN initialization. */
-               sl->lin_master = true;
+               sl->lin_master = master;
+#ifdef DEBUG
+               if (master)
+                       pr_debug("sllin: Configured as MASTER\n");
+               else
+                       pr_debug("sllin: Configured as SLAVE\n");
+#endif
 
-               sl->rx_cnt = 0;
-               sl->rx_expect = 0;
-               sl->rx_lim = sl->lin_master ? 0 : SLLIN_BUFF_LEN;
-               sl->tx_cnt = 0;
-               sl->tx_lim = 0;
-               sl->id_to_send = false;
-               sl->data_to_send = false;
+               sllin_reset_buffs(sl);
 
-               sl->lin_baud  = 19200;
+               sl->lin_baud = (baudrate == 0) ? LIN_DEFAULT_BAUDRATE : baudrate;
+               pr_debug("sllin: Baudrate set to %u\n", sl->lin_baud);
 
                sl->lin_state = SLSTATE_IDLE;