From 2e243ee2db62f787a706895b5f25136e4b10dcc0 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Mon, 29 Jul 2019 19:07:14 +0200 Subject: [PATCH] sllin: runtime selectable break by baudrate switching. It is used as fallback for case when provided TTY does not support break_ctl operation. Signed-off-by: Pavel Pisa --- sllin/sllin.c | 77 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/sllin/sllin.c b/sllin/sllin.c index 91a18c7..ff9b0fe 100644 --- a/sllin/sllin.c +++ b/sllin/sllin.c @@ -104,11 +104,18 @@ MODULE_AUTHOR("Pavel Pisa "); static bool master = true; static int baudrate; /* Use LIN_DEFAULT_BAUDRATE when not set */ +#ifndef BREAK_BY_BAUD +static bool break_by_baud = false; +#else /*BREAK_BY_BAUD*/ +static bool break_by_baud = true; +#endif /*BREAK_BY_BAUD*/ module_param(master, bool, 0444); MODULE_PARM_DESC(master, "LIN interface is Master device"); module_param(baudrate, int, 0444); MODULE_PARM_DESC(baudrate, "Baudrate of LIN interface"); +module_param(break_by_baud, bool, 0444); +MODULE_PARM_DESC(break_by_baud, "Break is sent by temporal baudrate switching"); static int maxdev = 10; /* MAX number of SLLIN channels; This can be overridden with @@ -164,6 +171,7 @@ struct sllin { int tx_lim; /* actual limit of bytes to Tx */ int tx_cnt; /* number of already Tx bytes */ char lin_master; /* node is a master node */ + bool lin_break_by_baud; /* send break character by baudrate switching */ int lin_baud; /* LIN baudrate */ int lin_state; /* state */ char id_to_send; /* there is ID to be sent */ @@ -661,13 +669,14 @@ static void sllin_master_receive_buf(struct tty_struct *tty, } } -#ifndef BREAK_BY_BAUD - /* We didn't receive Break character -- fake it! */ - if ((sl->rx_cnt == SLLIN_BUFF_BREAK) && (*cp == 0x55)) { - netdev_dbg(sl->dev, "LIN_RX[%d]: 0x00\n", sl->rx_cnt); - sl->rx_buff[sl->rx_cnt++] = 0x00; + if (!sl->lin_break_by_baud ) { + /* We didn't receive Break character -- fake it! */ + if ((sl->rx_cnt == SLLIN_BUFF_BREAK) && (*cp == 0x55)) { + netdev_dbg(sl->dev, "LIN_RX[%d]: 0x00\n", + sl->rx_cnt); + sl->rx_buff[sl->rx_cnt++] = 0x00; + } } -#endif /* BREAK_BY_BAUD */ if (sl->rx_cnt < SLLIN_BUFF_LEN) { netdev_dbg(sl->dev, "LIN_RX[%d]: 0x%02x\n", sl->rx_cnt, *cp); @@ -1025,14 +1034,14 @@ static int sllin_send_tx_buff(struct sllin *sl) smp_mb__after_atomic(); #endif -#ifdef BREAK_BY_BAUD - if (sl->lin_state != SLSTATE_BREAK_SENT) + if (sl->lin_break_by_baud) { + if (sl->lin_state != SLSTATE_BREAK_SENT) + remains = sl->tx_lim - sl->tx_cnt; + else + remains = 1; + } else { remains = sl->tx_lim - sl->tx_cnt; - else - remains = 1; -#else - remains = sl->tx_lim - sl->tx_cnt; -#endif + } res = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt, remains); if (res < 0) @@ -1077,8 +1086,7 @@ error_in_write: } -#ifdef BREAK_BY_BAUD -static int sllin_send_break(struct sllin *sl) +static int sllin_send_break_by_baud(struct sllin *sl) { struct tty_struct *tty = sl->tty; unsigned long break_baud; @@ -1087,7 +1095,7 @@ static int sllin_send_break(struct sllin *sl) break_baud = ((sl->lin_baud * 2) / 3); sltty_change_speed(tty, break_baud); - if (tty != NULL && tty->ops != NULL && tty->ops->flush_buffer != NULL) { + if (tty->ops->flush_buffer != NULL) { tty->ops->flush_buffer(tty); } else { netdev_dbg(sl->dev, "flush_buffer is not implemented.\n"); @@ -1105,9 +1113,8 @@ static int sllin_send_break(struct sllin *sl) return 0; } -#else /* BREAK_BY_BAUD */ -static int sllin_send_break(struct sllin *sl) +static int sllin_send_break_by_usleep(struct sllin *sl) { struct tty_struct *tty = sl->tty; int retval; @@ -1150,8 +1157,14 @@ static int sllin_send_break(struct sllin *sl) return 0; } -#endif /* BREAK_BY_BAUD */ +static int sllin_send_break(struct sllin *sl) +{ + if (sl->lin_break_by_baud) + return sllin_send_break_by_baud(sl); + else + return sllin_send_break_by_usleep(sl); +} static enum hrtimer_restart sllin_rx_timeout_handler(struct hrtimer *hrtimer) { @@ -1331,12 +1344,12 @@ static int sllin_kwthread(void *ptr) break; case SLSTATE_BREAK_SENT: -#ifdef BREAK_BY_BAUD - if (sl->rx_cnt <= SLLIN_BUFF_BREAK) - continue; + if (sl->lin_break_by_baud) { + if (sl->rx_cnt <= SLLIN_BUFF_BREAK) + continue; - res = sltty_change_speed(tty, sl->lin_baud); -#endif + sltty_change_speed(tty, sl->lin_baud); + } sl->lin_state = SLSTATE_ID_SENT; sllin_send_tx_buff(sl); @@ -1636,6 +1649,13 @@ static int sllin_open(struct tty_struct *tty) sl->lin_baud = (baudrate == 0) ? LIN_DEFAULT_BAUDRATE : baudrate; pr_debug("sllin: Baudrate set to %u\n", sl->lin_baud); + sl->lin_break_by_baud = break_by_baud; + + if (tty->ops->break_ctl == NULL && !sl->lin_break_by_baud) { + sl->lin_break_by_baud = true; + pr_notice ("sllin: break_ctl, switching to break_by_baud\n"); + } + sl->lin_state = SLSTATE_IDLE; hrtimer_init(&sl->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); @@ -1784,11 +1804,10 @@ static int __init sllin_init(void) kfree(sllin_devs); } -#ifdef BREAK_BY_BAUD - pr_debug("sllin: Break is generated by baud-rate change."); -#else - pr_debug("sllin: Break is generated manually with tiny sleep."); -#endif + if (break_by_baud) + pr_debug("sllin: Break is generated by baud-rate change."); + else + pr_debug("sllin: Break is generated manually with tiny sleep."); return status; } -- 2.39.2