1 /* 2 * Copyright (C) ST-Ericsson AB 2010 3 * Author: Sjur Brendeland/sjur.brandeland@stericsson.com 4 * License terms: GNU General Public License (GPL) version 2 5 */ 6 7 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ 8 9 #include <linux/stddef.h> 10 #include <linux/spinlock.h> 11 #include <linux/slab.h> 12 #include <net/caif/caif_layer.h> 13 #include <net/caif/cfpkt.h> 14 #include <net/caif/cfserl.h> 15 16 #define container_obj(layr) ((struct cfserl *) layr) 17 18 #define CFSERL_STX 0x02 19 #define SERIAL_MINIUM_PACKET_SIZE 4 20 #define SERIAL_MAX_FRAMESIZE 4096 21 struct cfserl { 22 struct cflayer layer; 23 struct cfpkt *incomplete_frm; 24 /* Protects parallel processing of incoming packets */ 25 spinlock_t sync; 26 bool usestx; 27 }; 28 29 static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt); 30 static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt); 31 static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, 32 int phyid); 33 34 struct cflayer *cfserl_create(int type, int instance, bool use_stx) 35 { 36 struct cfserl *this = kzalloc(sizeof(struct cfserl), GFP_ATOMIC); 37 if (!this) 38 return NULL; 39 caif_assert(offsetof(struct cfserl, layer) == 0); 40 this->layer.receive = cfserl_receive; 41 this->layer.transmit = cfserl_transmit; 42 this->layer.ctrlcmd = cfserl_ctrlcmd; 43 this->layer.type = type; 44 this->usestx = use_stx; 45 spin_lock_init(&this->sync); 46 snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1"); 47 return &this->layer; 48 } 49 50 static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) 51 { 52 struct cfserl *layr = container_obj(l); 53 u16 pkt_len; 54 struct cfpkt *pkt = NULL; 55 struct cfpkt *tail_pkt = NULL; 56 u8 tmp8; 57 u16 tmp; 58 u8 stx = CFSERL_STX; 59 int ret; 60 u16 expectlen = 0; 61 62 caif_assert(newpkt != NULL); 63 spin_lock(&layr->sync); 64 65 if (layr->incomplete_frm != NULL) { 66 layr->incomplete_frm = 67 cfpkt_append(layr->incomplete_frm, newpkt, expectlen); 68 pkt = layr->incomplete_frm; 69 if (pkt == NULL) { 70 spin_unlock(&layr->sync); 71 return -ENOMEM; 72 } 73 } else { 74 pkt = newpkt; 75 } 76 layr->incomplete_frm = NULL; 77 78 do { 79 /* Search for STX at start of pkt if STX is used */ 80 if (layr->usestx) { 81 cfpkt_extr_head(pkt, &tmp8, 1); 82 if (tmp8 != CFSERL_STX) { 83 while (cfpkt_more(pkt) 84 && tmp8 != CFSERL_STX) { 85 cfpkt_extr_head(pkt, &tmp8, 1); 86 } 87 if (!cfpkt_more(pkt)) { 88 cfpkt_destroy(pkt); 89 layr->incomplete_frm = NULL; 90 spin_unlock(&layr->sync); 91 return -EPROTO; 92 } 93 } 94 } 95 96 pkt_len = cfpkt_getlen(pkt); 97 98 /* 99 * pkt_len is the accumulated length of the packet data 100 * we have received so far. 101 * Exit if frame doesn't hold length. 102 */ 103 104 if (pkt_len < 2) { 105 if (layr->usestx) 106 cfpkt_add_head(pkt, &stx, 1); 107 layr->incomplete_frm = pkt; 108 spin_unlock(&layr->sync); 109 return 0; 110 } 111 112 /* 113 * Find length of frame. 114 * expectlen is the length we need for a full frame. 115 */ 116 cfpkt_peek_head(pkt, &tmp, 2); 117 expectlen = le16_to_cpu(tmp) + 2; 118 /* 119 * Frame error handling 120 */ 121 if (expectlen < SERIAL_MINIUM_PACKET_SIZE 122 || expectlen > SERIAL_MAX_FRAMESIZE) { 123 if (!layr->usestx) { 124 if (pkt != NULL) 125 cfpkt_destroy(pkt); 126 layr->incomplete_frm = NULL; 127 expectlen = 0; 128 spin_unlock(&layr->sync); 129 return -EPROTO; 130 } 131 continue; 132 } 133 134 if (pkt_len < expectlen) { 135 /* Too little received data */ 136 if (layr->usestx) 137 cfpkt_add_head(pkt, &stx, 1); 138 layr->incomplete_frm = pkt; 139 spin_unlock(&layr->sync); 140 return 0; 141 } 142 143 /* 144 * Enough data for at least one frame. 145 * Split the frame, if too long 146 */ 147 if (pkt_len > expectlen) 148 tail_pkt = cfpkt_split(pkt, expectlen); 149 else 150 tail_pkt = NULL; 151 152 /* Send the first part of packet upwards.*/ 153 spin_unlock(&layr->sync); 154 ret = layr->layer.up->receive(layr->layer.up, pkt); 155 spin_lock(&layr->sync); 156 if (ret == -EILSEQ) { 157 if (layr->usestx) { 158 if (tail_pkt != NULL) 159 pkt = cfpkt_append(pkt, tail_pkt, 0); 160 /* Start search for next STX if frame failed */ 161 continue; 162 } else { 163 cfpkt_destroy(pkt); 164 pkt = NULL; 165 } 166 } 167 168 pkt = tail_pkt; 169 170 } while (pkt != NULL); 171 172 spin_unlock(&layr->sync); 173 return 0; 174 } 175 176 static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) 177 { 178 struct cfserl *layr = container_obj(layer); 179 u8 tmp8 = CFSERL_STX; 180 if (layr->usestx) 181 cfpkt_add_head(newpkt, &tmp8, 1); 182 return layer->dn->transmit(layer->dn, newpkt); 183 } 184 185 static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, 186 int phyid) 187 { 188 layr->up->ctrlcmd(layr->up, ctrl, phyid); 189 } 190