0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
0008
0009 #include <linux/stddef.h>
0010 #include <linux/spinlock.h>
0011 #include <linux/slab.h>
0012 #include <net/caif/caif_layer.h>
0013 #include <net/caif/cfpkt.h>
0014 #include <net/caif/cfserl.h>
0015
0016 #define container_obj(layr) ((struct cfserl *) layr)
0017
0018 #define CFSERL_STX 0x02
0019 #define SERIAL_MINIUM_PACKET_SIZE 4
0020 #define SERIAL_MAX_FRAMESIZE 4096
0021 struct cfserl {
0022 struct cflayer layer;
0023 struct cfpkt *incomplete_frm;
0024
0025 spinlock_t sync;
0026 bool usestx;
0027 };
0028
0029 static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt);
0030 static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt);
0031 static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
0032 int phyid);
0033
0034 void cfserl_release(struct cflayer *layer)
0035 {
0036 kfree(layer);
0037 }
0038
0039 struct cflayer *cfserl_create(int instance, bool use_stx)
0040 {
0041 struct cfserl *this = kzalloc(sizeof(struct cfserl), GFP_ATOMIC);
0042 if (!this)
0043 return NULL;
0044 caif_assert(offsetof(struct cfserl, layer) == 0);
0045 this->layer.receive = cfserl_receive;
0046 this->layer.transmit = cfserl_transmit;
0047 this->layer.ctrlcmd = cfserl_ctrlcmd;
0048 this->usestx = use_stx;
0049 spin_lock_init(&this->sync);
0050 snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1");
0051 return &this->layer;
0052 }
0053
0054 static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
0055 {
0056 struct cfserl *layr = container_obj(l);
0057 u16 pkt_len;
0058 struct cfpkt *pkt = NULL;
0059 struct cfpkt *tail_pkt = NULL;
0060 u8 tmp8;
0061 u16 tmp;
0062 u8 stx = CFSERL_STX;
0063 int ret;
0064 u16 expectlen = 0;
0065
0066 caif_assert(newpkt != NULL);
0067 spin_lock(&layr->sync);
0068
0069 if (layr->incomplete_frm != NULL) {
0070 layr->incomplete_frm =
0071 cfpkt_append(layr->incomplete_frm, newpkt, expectlen);
0072 pkt = layr->incomplete_frm;
0073 if (pkt == NULL) {
0074 spin_unlock(&layr->sync);
0075 return -ENOMEM;
0076 }
0077 } else {
0078 pkt = newpkt;
0079 }
0080 layr->incomplete_frm = NULL;
0081
0082 do {
0083
0084 if (layr->usestx) {
0085 cfpkt_extr_head(pkt, &tmp8, 1);
0086 if (tmp8 != CFSERL_STX) {
0087 while (cfpkt_more(pkt)
0088 && tmp8 != CFSERL_STX) {
0089 cfpkt_extr_head(pkt, &tmp8, 1);
0090 }
0091 if (!cfpkt_more(pkt)) {
0092 cfpkt_destroy(pkt);
0093 layr->incomplete_frm = NULL;
0094 spin_unlock(&layr->sync);
0095 return -EPROTO;
0096 }
0097 }
0098 }
0099
0100 pkt_len = cfpkt_getlen(pkt);
0101
0102
0103
0104
0105
0106
0107
0108 if (pkt_len < 2) {
0109 if (layr->usestx)
0110 cfpkt_add_head(pkt, &stx, 1);
0111 layr->incomplete_frm = pkt;
0112 spin_unlock(&layr->sync);
0113 return 0;
0114 }
0115
0116
0117
0118
0119
0120 cfpkt_peek_head(pkt, &tmp, 2);
0121 expectlen = le16_to_cpu(tmp) + 2;
0122
0123
0124
0125 if (expectlen < SERIAL_MINIUM_PACKET_SIZE
0126 || expectlen > SERIAL_MAX_FRAMESIZE) {
0127 if (!layr->usestx) {
0128 if (pkt != NULL)
0129 cfpkt_destroy(pkt);
0130 layr->incomplete_frm = NULL;
0131 spin_unlock(&layr->sync);
0132 return -EPROTO;
0133 }
0134 continue;
0135 }
0136
0137 if (pkt_len < expectlen) {
0138
0139 if (layr->usestx)
0140 cfpkt_add_head(pkt, &stx, 1);
0141 layr->incomplete_frm = pkt;
0142 spin_unlock(&layr->sync);
0143 return 0;
0144 }
0145
0146
0147
0148
0149
0150 if (pkt_len > expectlen)
0151 tail_pkt = cfpkt_split(pkt, expectlen);
0152 else
0153 tail_pkt = NULL;
0154
0155
0156 spin_unlock(&layr->sync);
0157 ret = layr->layer.up->receive(layr->layer.up, pkt);
0158 spin_lock(&layr->sync);
0159 if (ret == -EILSEQ) {
0160 if (layr->usestx) {
0161 if (tail_pkt != NULL)
0162 pkt = cfpkt_append(pkt, tail_pkt, 0);
0163
0164 continue;
0165 } else {
0166 cfpkt_destroy(pkt);
0167 pkt = NULL;
0168 }
0169 }
0170
0171 pkt = tail_pkt;
0172
0173 } while (pkt != NULL);
0174
0175 spin_unlock(&layr->sync);
0176 return 0;
0177 }
0178
0179 static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt)
0180 {
0181 struct cfserl *layr = container_obj(layer);
0182 u8 tmp8 = CFSERL_STX;
0183 if (layr->usestx)
0184 cfpkt_add_head(newpkt, &tmp8, 1);
0185 return layer->dn->transmit(layer->dn, newpkt);
0186 }
0187
0188 static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
0189 int phyid)
0190 {
0191 layr->up->ctrlcmd(layr->up, ctrl, phyid);
0192 }