return 0;
}
+static void sllin_slave_finish_rx_msg(struct sllin *sl)
+{
+ if (sllin_rx_validate(sl) == -1) {
+ netdev_dbg(sl->dev, "sllin: RX validation failed.\n");
+ sllin_report_error(sl, LIN_ERR_CHECKSUM);
+ } else {
+ /* Send CAN non-RTR frame with data */
+ netdev_dbg(sl->dev, "sllin: sending NON-RTR CAN frame with LIN payload.");
+ sll_bump(sl); /* send packet to the network layer */
+ }
+ /* Prepare for reception of new header */
+ sl->rx_cnt = 0;
+ sl->rx_expect = SLLIN_BUFF_ID + 1;
+ sl->rx_len_unknown = false; /* We do know exact length of the header */
+ sl->header_received = false;
+}
+
static void sllin_slave_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
+ /*
+ * If we don't know the length of the current message
+ * we received the break of the next message.
+ * Evaluate the previous one before continuing
+ */
+ if (sl->rx_len_unknown == true)
+ {
+ hrtimer_cancel(&sl->rx_timer);
+ sllin_slave_finish_rx_msg(sl);
+
+ set_bit(SLF_RXEVENT, &sl->flags);
+ wake_up(&sl->kwt_wq);
+ }
+
netdev_dbg(sl->dev, "sllin_slave_receive_buf char 0x%02x ignored "
"due marker 0x%02x, flags 0x%lx\n",
*cp, *(fp-1), sl->flags);
sl->header_received = true;
+ hrtimer_start(&sl->rx_timer,
+ ktime_add(ktime_get(), sl->rx_timer_timeout),
+ HRTIMER_MODE_ABS);
sll_send_rtr(sl);
continue;
}
/* Response received */
if ((sl->header_received == true) &&
- ((sl->rx_cnt >= sl->rx_expect) ||
- ((sl->rx_len_unknown == true) && (count == 0)))) {
+ ((sl->rx_cnt >= sl->rx_expect))) {
- sll_bump(sl);
+ hrtimer_cancel(&sl->rx_timer);
netdev_dbg(sl->dev, "Received LIN header & LIN response. "
"rx_cnt = %u, rx_expect = %u\n", sl->rx_cnt,
sl->rx_expect);
+ sllin_slave_finish_rx_msg(sl);
- /* Prepare for reception of new header */
- sl->rx_cnt = 0;
- sl->rx_expect = SLLIN_BUFF_ID + 1;
- sl->rx_len_unknown = false; /* We do know exact length of the header */
- sl->header_received = false;
}
}
}
{
struct sllin *sl = container_of(hrtimer, struct sllin, rx_timer);
- sllin_report_error(sl, LIN_ERR_RX_TIMEOUT);
- set_bit(SLF_TMOUTEVENT, &sl->flags);
+ if (sl->lin_master) {
+ sllin_report_error(sl, LIN_ERR_RX_TIMEOUT);
+ set_bit(SLF_TMOUTEVENT, &sl->flags);
+ } else {
+ sllin_slave_finish_rx_msg(sl);
+ set_bit(SLF_RXEVENT, &sl->flags);
+ }
wake_up(&sl->kwt_wq);
return HRTIMER_NORESTART;