MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
#define SLLIN_MAGIC 0x53CA
+// #define BREAK_BY_BAUD
static int maxdev = 10; /* MAX number of SLLIN channels;
This can be overridden with
#define SLF_TXEVENT 3 /* Tx wake event */
#define SLF_MSGEVENT 4 /* CAN message to sent */
- unsigned char leased;
dev_t line;
struct task_struct *kwthread;
wait_queue_head_t kwt_wq;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
- //priv->io.speed = speed;
+
mutex_unlock(&tty->termios_mutex);
return 0;
/* Convert particular CAN frame into LIN frame and send it to TTY queue. */
static void sll_encaps(struct sllin *sl, struct can_frame *cf)
{
- 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;
- */
- }
-
+// 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;
+// */
+// }
+//
}
/*
struct sllin *sl = (struct sllin *) tty->disc_data;
/* First make sure we're connected. */
- if (!sl || sl->magic != SLLIN_MAGIC || !netif_running(sl->dev))
- return;
+ //if (!sl || sl->magic != SLLIN_MAGIC || !netif_running(sl->dev))
+ // return;
if (sl->lin_state != SLSTATE_BREAK_SENT)
remains = sl->tx_lim - sl->tx_cnt;
printk(KERN_INFO "sllin_receive_buf invoked\n");
- if (!sl || sl->magic != SLLIN_MAGIC || !netif_running(sl->dev))
- return;
+ //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++;
- printk(KERN_INFO "sllin_receive_buf char 0x%02x ignored due marker 0x%02x, flags 0x%lx\n",
+ printk(KERN_INFO "sllin_receive_buf char 0x%02x ignored "
+ "due marker 0x%02x, flags 0x%lx\n",
*cp, *(fp-1), sl->flags);
cp++;
continue;
}
- if (sl->rx_cnt < SLLIN_BUFF_LEN) {
+ 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;
+ }
+#endif
+ printk(KERN_INFO "LIN_RX[%d]: 0x%02x\n", sl->rx_cnt, *cp);
sl->rx_buff[sl->rx_cnt++] = *cp++;
}
}
- if(sl->rx_cnt >= sl->rx_expect) {
+ if (sl->rx_cnt >= sl->rx_expect) {
set_bit(SLF_RXEVENT, &sl->flags);
wake_up(&sl->kwt_wq);
printk(KERN_INFO "sllin_receive_buf count %d, wakeup\n", sl->rx_cnt);
int remains;
int res;
+#ifdef 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;
+#endif
res = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt, remains);
if (res < 0)
return 0;
}
+#ifdef BREAK_BY_BAUD
int sllin_send_break(struct sllin *sl)
{
struct tty_struct *tty = sl->tty;
- unsigned long break_baud = sl->lin_baud;
+ unsigned long break_baud;
int res;
- //break_baud = (break_baud * 8) / 14;
- break_baud /= 2;
-
+ break_baud = ((sl->lin_baud * 2) / 3);
sltty_change_speed(tty, break_baud);
- sl->rx_expect = SLLIN_BUFF_BREAK + 1;
+ tty->ops->flush_buffer(tty);
+ sl->rx_cnt = SLLIN_BUFF_BREAK;
+ sl->rx_expect = SLLIN_BUFF_BREAK + 1;
sl->lin_state = SLSTATE_BREAK_SENT;
res = sllin_send_tx_buff(sl);
return 0;
}
+#else /* BREAK_BY_BAUD */
+
+int sllin_send_break(struct sllin *sl)
+{
+ struct tty_struct *tty = sl->tty;
+ unsigned long break_baud;
+ unsigned long flags;
+ int retval;
+
+ sl->rx_cnt = SLLIN_BUFF_BREAK;
+ sl->rx_expect = SLLIN_BUFF_BREAK + 1;
+ sl->lin_state = SLSTATE_BREAK_SENT;
+
+ /* Do the break ourselves; Inspired by
+ http://lxr.linux.no/#linux+v3.1.2/drivers/tty/tty_io.c#L2452 */
+ retval = tty->ops->break_ctl(tty, -1);
+ if (retval)
+ return retval;
+
+ //udelay(712);
+ usleep_range(650, 750);
+
+ retval = tty->ops->break_ctl(tty, 0);
+ usleep_range(50, 100);
+
+ tty->ops->flush_buffer(tty);
+
+ sl->tx_cnt = SLLIN_BUFF_SYNC;
+ set_bit(SLF_RXEVENT, &sl->flags);
+ wake_up(&sl->kwt_wq);
+
+ return 0;
+}
+#endif /* BREAK_BY_BAUD */
/*****************************************
* sllin_kwthread - kernel worker thread
{
struct sllin *sl = (struct sllin *)ptr;
struct tty_struct *tty = sl->tty;
+ struct sched_param schparam = { .sched_priority = 40 };
int res;
+ unsigned char buff[8] = {0x2, 0x3, 0x4, 0x5};
printk(KERN_INFO "sllin: sllin_kwthread started.\n");
+ sched_setscheduler(current, SCHED_FIFO, &schparam);
clear_bit(SLF_ERROR, &sl->flags);
-
sltty_change_speed(tty, sl->lin_baud);
- sllin_setup_msg(sl, 0, 0x33, NULL, 0);
- sl->id_to_send = 1;
+ //sllin_setup_msg(sl, 0, 0x01, NULL, 0);
+ sllin_setup_msg(sl, 0, 0x02, buff, 4);
+ sl->id_to_send = true;
while (!kthread_should_stop()) {
-
if ((sl->lin_state == SLSTATE_IDLE) && sl->lin_master &&
sl->id_to_send) {
- if(sllin_send_break(sl)<0) {
+ if(sllin_send_break(sl) < 0) {
/* error processing */
}
-
}
wait_event_killable(sl->kwt_wq, kthread_should_stop() ||
case SLSTATE_BREAK_SENT:
if (sl->rx_cnt <= SLLIN_BUFF_BREAK)
continue;
-
+#ifdef BREAK_BY_BAUD
res = sltty_change_speed(tty, sl->lin_baud);
-
- sllin_send_tx_buff(sl);
+#endif
sl->lin_state = SLSTATE_ID_SENT;
-
+ sllin_send_tx_buff(sl);
break;
+
case SLSTATE_ID_SENT:
- sl->id_to_send = 0;
+ sl->id_to_send = false;
sl->lin_state = SLSTATE_IDLE;
break;
}
break;
sl = netdev_priv(dev);
- if (sl->tty || sl->leased)
+ if (sl->tty)
continue;
if (dev->flags & IFF_UP)
dev_close(dev);
/* Perform the low-level SLLIN initialization. */
sl->rx_cnt = 0;
sl->rx_expect = 0;
+ sl->rx_lim = 0;
sl->tx_cnt = 0;
sl->tx_lim = 0;
- sl->lin_baud = 2400;
+ sl->lin_baud = 19200;
sl->lin_master = 1;
sl->lin_state = SLSTATE_IDLE;
tty->disc_data = NULL;
sl->tty = NULL;
- if (!sl->leased)
- sl->line = 0;
/* Flush network side */
unregister_netdev(sl->dev);