-/*
+/*
* 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 */
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 */
#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,
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 */
+ char rx_len_unknown; /* We are not sure how much data will be sent to us --
+ we just guess the length */
unsigned long flags; /* Flag values/ mode etc */
#define SLF_INUSE 0 /* Channel in use */
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);
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)
{
*/
static void sll_bump(struct sllin *sl)
{
+ int len = sl->rx_cnt - SLLIN_BUFF_DATA - 1; /* without checksum */
+ len = (len < 0) ? 0 : len;
+
sllin_send_canfr(sl, sl->rx_buff[SLLIN_BUFF_ID] & LIN_ID_MASK,
- sl->rx_buff + SLLIN_BUFF_DATA,
- sl->rx_cnt - SLLIN_BUFF_DATA - 1); /* without checksum */
+ sl->rx_buff + SLLIN_BUFF_DATA, len);
+}
+
+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);
}
/*
/******************************************
Routines looking at TTY side.
******************************************/
+#define SLL_RESPONSE_RECEIVED ((sl->header_received == true) && \
+ ((sl->rx_cnt >= sl->rx_expect) || \
+ ((sl->rx_len_unknown == true) && (count == 0))))
+
+#define SLL_HEADER_RECEIVED ((sl->header_received == false) && \
+ (sl->rx_cnt >= (SLLIN_BUFF_ID + 1)))
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;
/* 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->rx_len_unknown = false; /* We do know exact length of the header */
+ sl->header_received = false;
+ }
}
- if (sl->rx_cnt < SLLIN_BUFF_LEN) {
#ifndef BREAK_BY_BAUD
- /* We didn't receive Break character */
- if ((sl->rx_cnt == SLLIN_BUFF_BREAK) && (*cp == 0x55)) {
- sl->rx_buff[sl->rx_cnt++] = 0x00;
- }
+ /* 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
+ if (sl->rx_cnt < SLLIN_BUFF_LEN) {
pr_debug("sllin: LIN_RX[%d]: 0x%02x\n", sl->rx_cnt, *cp);
sl->rx_buff[sl->rx_cnt++] = *cp++;
}
- }
- 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 (SLL_RESPONSE_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);
+
+ if (SLL_HEADER_RECEIVED) {
+ 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;
+ sl->rx_len_unknown = false;
+ } else {
+ sl->rx_expect += SLLIN_DATA_MAX + 1; /* + checksum */
+ sl->rx_len_unknown = true;
+ }
+
+ sl->header_received = true;
+ sll_send_rtr(sl);
+ continue;
+ }
+
+ if (SLL_RESPONSE_RECEIVED) {
+ 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->rx_len_unknown = false; /* We do know exact length of the header */
+ sl->header_received = false;
+ }
+ }
}
}
sl->dev->stats.rx_crc_errors++;
break;
- case LIN_ERR_RX_TIMEOUT:
+ 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 |
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)
{
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)));
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;
}
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);
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;