X-Git-Url: https://rtime.felk.cvut.cz/gitweb/linux-lin.git/blobdiff_plain/597b435d5bb9257a74b09e3647f183d5f23a30e0..b819ec2c6a6c411bd6b35822f4b8d389be9e0ef0:/sllin/sllin.c diff --git a/sllin/sllin.c b/sllin/sllin.c index eaf1187..51b501d 100644 --- a/sllin/sllin.c +++ b/sllin/sllin.c @@ -1,11 +1,8 @@ /* * sllin.c - serial line LIN interface driver (using tty line discipline) * - * This file is derived from linux/drivers/net/slip.c - * - * slip.c Authors : Laurence Culhane - * Fred N. van Kempen - * sllin.c Author : Oliver Hartkopp + * This file is derived from drivers/net/can/slcan.c + * slcan.c Author: Oliver Hartkopp * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -69,7 +66,7 @@ static __initdata const char banner[] = MODULE_ALIAS_LDISC(N_SLLIN); MODULE_DESCRIPTION("serial line LIN interface"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Oliver Hartkopp "); +MODULE_AUTHOR(""); #define SLLIN_MAGIC 0x53CA // #define BREAK_BY_BAUD @@ -91,12 +88,16 @@ MODULE_PARM_DESC(maxdev, "Maximum number of sllin interfaces"); #define SLLIN_ID_MASK 0x3f #define SLLIN_ID_MAX SLLIN_ID_MASK +#define SLLIN_STATUS_FLAG SLLIN_EFF_FLAG enum slstate { SLSTATE_IDLE = 0, SLSTATE_BREAK_SENT, SLSTATE_ID_SENT, - SLSTATE_RESPONSE_WAIT, + SLSTATE_RESPONSE_WAIT, /* Wait for response */ + SLSTATE_RESPONSE_WAIT_BUS, /* Wait for response from LIN bus + only (CAN frames from network stack + are not processed in this moment) */ SLSTATE_RESPONSE_SENT, }; @@ -111,6 +112,11 @@ struct sllin_conf_entry { #define SLLIN_SLAVE_LOCAL (1 << (SLLIN_CANFR_FLAGS_OFFS + 3)) #define SLLIN_SLAVE_REMOTE (1 << (SLLIN_CANFR_FLAGS_OFFS + 4)) #define SLLIN_LOC_SLAVE_CACHE (1 << (SLLIN_CANFR_FLAGS_OFFS + 5)) + +#define SLLIN_ERR_RX_TIMEOUT (1 << (SLLIN_CANFR_FLAGS_OFFS + 6)) +#define SLLIN_ERR_CHECKSUM (1 << (SLLIN_CANFR_FLAGS_OFFS + 7)) +//#define SLLIN_ERR_FRAMING (1 << (SLLIN_CANFR_FLAGS_OFFS + 8)) + canid_t frame_fl; /* LIN frame flags. Passed from userspace as canid_t data type */ u8 data[8]; /* LIN frame data payload */ }; @@ -136,6 +142,7 @@ struct sllin { int lin_state; /* state */ 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 */ unsigned long flags; /* Flag values/ mode etc */ #define SLF_INUSE 0 /* Channel in use */ @@ -150,7 +157,8 @@ struct sllin { wait_queue_head_t kwt_wq; struct hrtimer rx_timer; /* RX timeout timer */ ktime_t rx_timer_timeout; /* RX timeout timer value */ - struct sk_buff *rec_skb; /* Socket buffer with received CAN frame */ + struct sk_buff *tx_req_skb; /* Socket buffer with CAN frame received + from network stack*/ struct sllin_conf_entry linfr_cache[SLLIN_ID_MAX + 1]; /* List with configurations for each of 0 to SLLIN_ID_MAX LIN IDs */ @@ -193,15 +201,17 @@ static int sltty_change_speed(struct tty_struct *tty, unsigned speed) } -/* Send one completely decapsulated can_frame to the network layer */ -static void sll_bump(struct sllin *sl) +/* Send one can_frame to the network layer */ +static void sllin_send_canfr(struct sllin *sl, canid_t id, char *data, int len) { struct sk_buff *skb; struct can_frame cf; - cf.can_id = sl->rx_buff[SLLIN_BUFF_ID] & SLLIN_ID_MASK; - cf.can_dlc = sl->rx_cnt - SLLIN_BUFF_DATA; - memcpy(&cf.data, sl->rx_buff + SLLIN_BUFF_DATA, cf.can_dlc); + cf.can_id = id; + cf.can_dlc = len; + if (cf.can_dlc > 0) { + memcpy(&cf.data, data, cf.can_dlc); + } skb = dev_alloc_skb(sizeof(struct can_frame)); if (!skb) @@ -217,59 +227,15 @@ static void sll_bump(struct sllin *sl) sl->dev->stats.rx_packets++; sl->dev->stats.rx_bytes += cf.can_dlc; -} - /************************************************************************ - * STANDARD SLLIN ENCAPSULATION * - ************************************************************************/ +} -/* Convert particular CAN frame into LIN frame and send it to TTY queue. */ -static void sll_encaps(struct sllin *sl, struct can_frame *cf) +static void sll_bump(struct sllin *sl) { -// int actual, idx, i; -// char lframe[16] = {0x00, 0x55}; /* Fake break, Sync byte */ -// struct tty_struct *tty = sl->tty; -// -// pr_debug("sllin: %s() invoked\n", __FUNCTION__); -// -// /* We do care only about SFF frames */ -// if (cf->can_id & CAN_EFF_FLAG) -// return; -// -// /* Send only header */ -// if (cf->can_id & CAN_RTR_FLAG) { -// pr_debug("sllin: %s() RTR CAN frame\n", __FUNCTION__); -// lframe[2] = (u8)cf->can_id; /* Get one byte LIN ID */ -// -// sltty_change_speed(tty, sl->lin_baud * 2 / 3); -// tty->ops->write(tty, &lframe[0], 1); -// sltty_change_speed(tty, sl->lin_baud); -// tty->ops->write(tty, &lframe[1], 1); -// tty->ops->write(tty, &lframe[2], 1); -// } else { -// pr_debug("sllin: %s() non-RTR CAN frame\n", __FUNCTION__); -// /* idx = strlen(sl->xbuff); -// -// for (i = 0; i < cf->can_dlc; i++) -// sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]); -// -// * Order of next two lines is *very* important. -// * When we are sending a little amount of data, -// * the transfer may be completed inside the ops->write() -// * routine, because it's running with interrupts enabled. -// * In this case we *never* got WRITE_WAKEUP event, -// * if we did not request it before write operation. -// * 14 Oct 1994 Dmitry Gorodchanin. -// -// set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); -// actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff)); -// sl->xleft = strlen(sl->xbuff) - actual; -// sl->xhead = sl->xbuff + actual; -// sl->dev->stats.tx_bytes += cf->can_dlc; -// */ -// } -// + sllin_send_canfr(sl, sl->rx_buff[SLLIN_BUFF_ID] & SLLIN_ID_MASK, + sl->rx_buff + SLLIN_BUFF_DATA, + sl->rx_cnt - SLLIN_BUFF_DATA); } /* @@ -330,7 +296,7 @@ static netdev_tx_t sll_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(sl->dev); - sl->rec_skb = skb; + sl->tx_req_skb = skb; set_bit(SLF_MSGEVENT, &sl->flags); wake_up(&sl->kwt_wq); spin_unlock(&sl->lock); @@ -469,6 +435,12 @@ static void sllin_receive_buf(struct tty_struct *tty, /***************************************** * sllin message helper routines *****************************************/ +void sllin_report_error(struct sllin *sl, int err) +{ + sllin_send_canfr(sl, 0 | CAN_EFF_FLAG | + (err & ~SLLIN_ID_MASK), NULL, 0); +} + int sllin_configure_frame_cache(struct sllin *sl, struct can_frame *cf) { struct sllin_conf_entry *sce; @@ -486,16 +458,22 @@ int sllin_configure_frame_cache(struct sllin *sl, struct can_frame *cf) return 0; } +#define SLLIN_STPMSG_RESPONLY (1) /* Message will be LIN Response only */ +#define SLLIN_STPMSG_CHCKSUMV1 (1 << 1) +#define SLLIN_STPMSG_CHCKSUMV2 (1 << 2) + int sllin_setup_msg(struct sllin *sl, int mode, int id, unsigned char *data, int len) { if (id > SLLIN_ID_MASK) return -1; - sl->rx_cnt = 0; - sl->tx_cnt = 0; - sl->rx_expect = 0; - sl->rx_lim = SLLIN_BUFF_LEN; + if (!(mode & SLLIN_STPMSG_RESPONLY)) { + sl->rx_cnt = 0; + sl->tx_cnt = 0; + sl->rx_expect = 0; + sl->rx_lim = SLLIN_BUFF_LEN; + } sl->tx_buff[SLLIN_BUFF_BREAK] = 0; sl->tx_buff[SLLIN_BUFF_SYNC] = 0x55; @@ -504,7 +482,7 @@ int sllin_setup_msg(struct sllin *sl, int mode, int id, if ((data != NULL) && len) { int i; - unsigned csum = 0; + unsigned csum = 0; sl->tx_lim += len; memcpy(sl->tx_buff + SLLIN_BUFF_DATA, data, len); @@ -593,10 +571,13 @@ int sllin_send_break(struct sllin *sl) int sllin_send_break(struct sllin *sl) { struct tty_struct *tty = sl->tty; - unsigned long break_baud; unsigned long flags; int retval; + unsigned long break_baud; + unsigned long usleep_range_min; + unsigned long usleep_range_max; + break_baud = ((sl->lin_baud * 2) / 3); sl->rx_cnt = SLLIN_BUFF_BREAK; sl->rx_expect = SLLIN_BUFF_BREAK + 1; sl->lin_state = SLSTATE_BREAK_SENT; @@ -608,10 +589,14 @@ int sllin_send_break(struct sllin *sl) return retval; //udelay(712); - usleep_range(650, 750); + usleep_range_min = (1000000l * SLLIN_SAMPLES_PER_CHAR) / break_baud; + usleep_range_max = usleep_range_min + 50; + usleep_range(usleep_range_min, usleep_range_max); retval = tty->ops->break_ctl(tty, 0); - usleep_range(50, 100); + usleep_range_min = (1000000l * 1 /* 1 bit */) / break_baud; + usleep_range_max = usleep_range_min + 30; + usleep_range(usleep_range_min, usleep_range_max); tty->ops->flush_buffer(tty); @@ -630,6 +615,7 @@ static enum hrtimer_restart sllin_rx_timeout_handler(struct hrtimer *hrtimer) { struct sllin *sl = container_of(hrtimer, struct sllin, rx_timer); + sllin_report_error(sl, SLLIN_ERR_RX_TIMEOUT); set_bit(SLF_TMOUTEVENT, &sl->flags); wake_up(&sl->kwt_wq); @@ -648,7 +634,7 @@ int sllin_kwthread(void *ptr) struct sched_param schparam = { .sched_priority = 40 }; int res; struct can_frame *cf; - char *lin_data; + u8 *lin_data; int lin_dlc; int tx_bytes = 0; /* Used for Network statistics */ @@ -671,7 +657,9 @@ int sllin_kwthread(void *ptr) test_bit(SLF_RXEVENT, &sl->flags) || test_bit(SLF_TXEVENT, &sl->flags) || test_bit(SLF_TMOUTEVENT, &sl->flags) || - ((sl->lin_state == SLSTATE_IDLE) && test_bit(SLF_MSGEVENT, &sl->flags))); + (((sl->lin_state == SLSTATE_IDLE) || + (sl->lin_state == SLSTATE_RESPONSE_WAIT)) + && test_bit(SLF_MSGEVENT, &sl->flags))); if (test_and_clear_bit(SLF_RXEVENT, &sl->flags)) { printk(KERN_INFO "sllin_kthread RXEVENT \n"); @@ -695,7 +683,7 @@ int sllin_kwthread(void *ptr) } if ((sl->lin_state == SLSTATE_IDLE) && test_bit(SLF_MSGEVENT, &sl->flags)) { - cf = (struct can_frame *)sl->rec_skb->data; + cf = (struct can_frame *)sl->tx_req_skb->data; /* EFF CAN frame -> "Configuration" frame */ if (cf->can_id & CAN_EFF_FLAG) { @@ -716,7 +704,7 @@ int sllin_kwthread(void *ptr) lin_dlc = sl->linfr_cache[cf->can_id & SLLIN_ID_MASK].dlc; } else { lin_data = NULL; - lin_dlc = 0; + lin_dlc = sl->linfr_cache[cf->can_id & SLLIN_ID_MASK].dlc; } } else { /* SFF NON-RTR CAN frame -> LIN header + LIN response */ printk(KERN_INFO "%s: NON-RTR SFF CAN frame, ID = %x\n", @@ -730,14 +718,15 @@ int sllin_kwthread(void *ptr) lin_data, lin_dlc) != -1) { sl->id_to_send = true; - sl->data_to_send = (lin_dlc > 0) ? true : false; + sl->data_to_send = (lin_data != NULL) ? true : false; + sl->resp_len_known = (lin_dlc > 0) ? true : false; sl->dev->stats.tx_packets++; sl->dev->stats.tx_bytes += tx_bytes; } free_skb: clear_bit(SLF_MSGEVENT, &sl->flags); - kfree_skb(sl->rec_skb); + kfree_skb(sl->tx_req_skb); netif_wake_queue(sl->dev); } @@ -762,7 +751,11 @@ int sllin_kwthread(void *ptr) sl->rx_expect = sl->tx_lim; goto slstate_response_sent; } else { - sl->rx_expect = SLLIN_BUFF_DATA + 2; + if (sl->resp_len_known) { + sl->rx_expect = sl->rx_lim; + } else { + sl->rx_expect = SLLIN_BUFF_DATA + 2; + } sl->lin_state = SLSTATE_RESPONSE_WAIT; /* If we don't receive anything, timer will "unblock" us */ hrtimer_start(&sl->rx_timer, @@ -774,6 +767,48 @@ int sllin_kwthread(void *ptr) case SLSTATE_RESPONSE_WAIT: slstate_response_wait: + if (test_bit(SLF_MSGEVENT, &sl->flags)) { + cf = (struct can_frame *)sl->tx_req_skb->data; + + /* EFF CAN frame -> "Configuration" frame */ + if (cf->can_id & CAN_EFF_FLAG) { + sllin_configure_frame_cache(sl, cf); + + clear_bit(SLF_MSGEVENT, &sl->flags); + kfree_skb(sl->tx_req_skb); + netif_wake_queue(sl->dev); + } else { + unsigned char *lin_buff; + lin_buff = (sl->lin_master) ? sl->tx_buff : sl->rx_buff; + if (cf->can_id == lin_buff[SLLIN_BUFF_ID] & SLLIN_ID_MASK) { + if (sllin_setup_msg(sl, SLLIN_STPMSG_RESPONLY, + cf->can_id & SLLIN_ID_MASK, + cf->data, cf->can_dlc) != -1) { + + sl->rx_expect = sl->tx_lim; + sl->data_to_send = true; + sl->dev->stats.tx_packets++; + sl->dev->stats.tx_bytes += tx_bytes; + + if (!sl->lin_master) { + sl->tx_cnt = SLLIN_BUFF_DATA; + } + + sllin_send_tx_buff(sl); + clear_bit(SLF_MSGEVENT, &sl->flags); + kfree_skb(sl->tx_req_skb); + netif_wake_queue(sl->dev); + + sl->lin_state = SLSTATE_RESPONSE_SENT; + goto slstate_response_sent; + } + } else { + sl->lin_state = SLSTATE_RESPONSE_WAIT_BUS; + } + } + } + + case SLSTATE_RESPONSE_WAIT_BUS: if (sl->rx_cnt < sl->rx_expect) continue; @@ -788,7 +823,7 @@ int sllin_kwthread(void *ptr) sl->id_to_send = false; sl->lin_state = SLSTATE_IDLE; break; - + case SLSTATE_RESPONSE_SENT: slstate_response_sent: if (sl->rx_cnt < sl->tx_lim) @@ -955,14 +990,12 @@ static int sllin_open(struct tty_struct *tty) sl->lin_state = SLSTATE_IDLE; -#define SAMPLES_PER_CHAR 10 -#define CHARS_TO_TIMEOUT 12 hrtimer_init(&sl->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); sl->rx_timer.function = sllin_rx_timeout_handler; /* timeval_to_ktime(msg_head->ival1); */ sl->rx_timer_timeout = ns_to_ktime( - (1000000000 / sl->lin_baud) * - SAMPLES_PER_CHAR * CHARS_TO_TIMEOUT); + (1000000000l / sl->lin_baud) * + SLLIN_SAMPLES_PER_CHAR * SLLIN_CHARS_TO_TIMEOUT); set_bit(SLF_INUSE, &sl->flags);