X-Git-Url: https://rtime.felk.cvut.cz/gitweb/linux-lin.git/blobdiff_plain/080feeb899d8630a9314a3f44bcf93434626543a..6c1650d8219652b18fc0989a194aa6e196f27fc0:/sllin/sllin.c diff --git a/sllin/sllin.c b/sllin/sllin.c index 528d746..671ba1a 100644 --- a/sllin/sllin.c +++ b/sllin/sllin.c @@ -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 @@ -32,8 +32,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * - * Send feedback to - * + * Idea: Oliver Hartkopp + * Copyright: (c) 2011 Czech Technical University in Prague + * (c) 2011 Volkswagen Group Research + * Authors: Pavel Pisa + * Rostislav Lisovy + * Michal Sojka + * 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 "); #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 */ @@ -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 */ @@ -250,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. @@ -412,7 +433,7 @@ static void sllin_receive_buf(struct tty_struct *tty, { 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; @@ -430,6 +451,11 @@ static void sllin_receive_buf(struct tty_struct *tty, if (sl->lin_master == true) { wake_up(&sl->kwt_wq); return; + } else { + sl->rx_cnt = 0; + sl->rx_expect = SLLIN_BUFF_ID + 1; + sl->header_received = false; + return; } cp++; @@ -439,8 +465,9 @@ static void sllin_receive_buf(struct tty_struct *tty, 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 @@ -449,12 +476,45 @@ 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; + + /* Received whole header */ + 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); + sl->rx_cnt = 0; + sl->rx_expect = SLLIN_BUFF_ID + 1; + sl->header_received = false; + } } } @@ -475,7 +535,7 @@ void sllin_report_error(struct sllin *sl, int err) sl->dev->stats.rx_crc_errors++; break; - case LIN_ERR_RX_TIMEOUT: + case LIN_ERR_RX_TIMEOUT: sl->dev->stats.rx_errors++; break; @@ -1116,11 +1176,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 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;