X-Git-Url: https://rtime.felk.cvut.cz/gitweb/linux-lin.git/blobdiff_plain/d9f6b0c8273753ac670fa256b0392a927970e302..3de7c46202e11310e2a05350af640309c9719d11:/sllin/sllin.c diff --git a/sllin/sllin.c b/sllin/sllin.c index fee14d1..2570bee 100644 --- a/sllin/sllin.c +++ b/sllin/sllin.c @@ -89,6 +89,9 @@ MODULE_PARM_DESC(maxdev, "Maximum number of sllin interfaces"); #define SLLIN_BUFF_ID 2 #define SLLIN_BUFF_DATA 3 +#define SLLIN_ID_MASK 0x3f +#define SLLIN_ID_MAX SLLIN_ID_MASK + enum slstate { SLSTATE_IDLE = 0, SLSTATE_BREAK_SENT, @@ -97,6 +100,21 @@ enum slstate { SLSTATE_RESPONSE_SENT, }; +struct sllin_conf_entry { + int dlc; /* Length of data in LIN frame */ +#define SLLIN_CANFR_FLAGS_OFFS 6 /* Lower 6 bits in can_id correspond to LIN ID */ +/* Save configuration for particualr LIN ID */ +#define SLLIN_SRC_ID_CONF (1 << SLLIN_CANFR_FLAGS_OFFS) +/* Publisher of particular LIN response is SLLIN Master */ +#define SLLIN_SRC_MASTER (1 << (SLLIN_CANFR_FLAGS_OFFS + 1)) +#define SLLIN_SRC_SLAVE (1 << (SLLIN_CANFR_FLAGS_OFFS + 2)) +#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)) + u32 frame_fl; /* LIN frame flags */ + u8 data[8]; /* LIN frame data payload */ +}; + struct sllin { int magic; @@ -133,6 +151,9 @@ struct sllin { 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 sllin_conf_entry linfr_cache[SLLIN_ID_MAX + 1]; /* List with configurations for + each of 0 to SLLIN_ID_MAX LIN IDs */ }; static struct net_device **sllin_devs; @@ -175,67 +196,27 @@ 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) { -// struct sk_buff *skb; -// struct can_frame cf; -// int i, dlc_pos, tmp; -// unsigned long ultmp; -// char cmd = sl->rbuff[0]; -// -// if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R')) -// return; -// -// if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */ -// dlc_pos = 4; /* dlc position tiiid */ -// else -// dlc_pos = 9; /* dlc position Tiiiiiiiid */ -// -// if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9'))) -// return; -// -// cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */ -// -// sl->rbuff[dlc_pos] = 0; /* terminate can_id string */ -// -// if (strict_strtoul(sl->rbuff+1, 16, &ultmp)) -// return; -// -// cf.can_id = ultmp; -// -// if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */ -// cf.can_id |= CAN_EFF_FLAG; -// -// if ((cmd | 0x20) == 'r') /* RTR frame */ -// cf.can_id |= CAN_RTR_FLAG; -// -// *(u64 *) (&cf.data) = 0; /* clear payload */ -// -// for (i = 0, dlc_pos++; i < cf.can_dlc; i++) { -// -// tmp = asc2nibble(sl->rbuff[dlc_pos++]); -// if (tmp > 0x0F) -// return; -// cf.data[i] = (tmp << 4); -// tmp = asc2nibble(sl->rbuff[dlc_pos++]); -// if (tmp > 0x0F) -// return; -// cf.data[i] |= tmp; -// } -// -// -// skb = dev_alloc_skb(sizeof(struct can_frame)); -// if (!skb) -// return; -// -// skb->dev = sl->dev; -// skb->protocol = htons(ETH_P_CAN); -// skb->pkt_type = PACKET_BROADCAST; -// skb->ip_summed = CHECKSUM_UNNECESSARY; -// memcpy(skb_put(skb, sizeof(struct can_frame)), -// &cf, sizeof(struct can_frame)); -// netif_rx(skb); -// -// sl->dev->stats.rx_packets++; -// sl->dev->stats.rx_bytes += cf.can_dlc; + 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); + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (!skb) + return; + + skb->dev = sl->dev; + skb->protocol = htons(ETH_P_CAN); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + memcpy(skb_put(skb, sizeof(struct can_frame)), + &cf, sizeof(struct can_frame)); + netif_rx(skb); + + sl->dev->stats.rx_packets++; + sl->dev->stats.rx_bytes += cf.can_dlc; } @@ -488,11 +469,25 @@ static void sllin_receive_buf(struct tty_struct *tty, /***************************************** * sllin message helper routines *****************************************/ +int sllin_configure_frame_cache(struct sllin *sl, struct can_frame *cf) +{ + struct sllin_conf_entry *sce; + if (!(cf->can_id & SLLIN_SRC_ID_CONF)) + return -1; + + sce = &sl->linfr_cache[cf->can_id & SLLIN_ID_MASK]; + + sce->dlc = (sce->dlc > 8) ? 8 : cf->can_dlc; + sce->frame_fl = (cf->can_id & ~SLLIN_ID_MASK) & CAN_EFF_FLAG; + memcpy(sce->data, cf->data, cf->can_dlc); + + return 0; +} int sllin_setup_msg(struct sllin *sl, int mode, int id, unsigned char *data, int len) { - if (id > 0x3f) + if (id > SLLIN_ID_MASK) return -1; sl->rx_cnt = 0; @@ -696,12 +691,12 @@ 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; - /* We do care only about SFF frames */ - if (cf->can_id & CAN_EFF_FLAG) - goto release_skb; - - if (cf->can_id & CAN_RTR_FLAG) { - printk(KERN_INFO "%s: RTR CAN frame, ID = %x\n", + /* "Configuration" frame */ + if (cf->can_id & CAN_EFF_FLAG) { + sllin_configure_frame_cache(sl, cf); + } + else if (cf->can_id & CAN_RTR_FLAG) { + printk(KERN_INFO "%s: RTR SFF CAN frame, ID = %x\n", __FUNCTION__, cf->can_id & CAN_SFF_MASK); if (sllin_setup_msg(sl, 0, cf->can_id & CAN_SFF_MASK, NULL, 0) != -1) { @@ -709,7 +704,7 @@ int sllin_kwthread(void *ptr) sl->data_to_send = false; } } else { - printk(KERN_INFO "%s: NON-RTR CAN frame, ID = %x\n", + printk(KERN_INFO "%s: NON-RTR SFF CAN frame, ID = %x\n", __FUNCTION__, (int)cf->can_id & CAN_SFF_MASK); if (sllin_setup_msg(sl, 0, cf->can_id & CAN_SFF_MASK, @@ -719,7 +714,8 @@ int sllin_kwthread(void *ptr) } } - release_skb: + sl->dev->stats.tx_packets++; + sl->dev->stats.tx_bytes += cf->can_dlc; clear_bit(SLF_MSGEVENT, &sl->flags); kfree_skb(sl->rec_skb); netif_wake_queue(sl->dev); @@ -766,6 +762,8 @@ int sllin_kwthread(void *ptr) sl->rx_buff[SLLIN_BUFF_ID], sl->rx_cnt - SLLIN_BUFF_DATA - 1); // check checksum in sl->rx_buff // send CAN non-RTR frame with data + printk(KERN_INFO "sllin: sending NON-RTR CAN frame with LIN payload."); + sll_bump(sl); //send packet to the network layer sl->id_to_send = false; sl->lin_state = SLSTATE_IDLE; break; @@ -785,7 +783,6 @@ int sllin_kwthread(void *ptr) - /* sll_bump(sl); send packet to the network layer */ /* sl->dev->stats.tx_packets++; send frames statistic */ /* netif_wake_queue(sl->dev); allow next Tx packet arrival */ @@ -863,7 +860,6 @@ static struct sllin *sll_alloc(dev_t line) } sl = netdev_priv(dev); - /* Initialize channel control data */ sl->magic = SLLIN_MAGIC; sl->dev = dev; @@ -938,7 +934,7 @@ static int sllin_open(struct tty_struct *tty) sl->lin_state = SLSTATE_IDLE; #define SAMPLES_PER_CHAR 10 -#define CHARS_TO_TIMEOUT 6 +#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); */