4 * Copyright (C) ST-Ericsson AB 2010
5 * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
6 * License terms: GNU General Public License (GPL) version 2
9 #include <linux/stddef.h>
10 #include <linux/spinlock.h>
11 #include <linux/slab.h>
12 #include <linux/crc-ccitt.h>
13 #include <net/caif/caif_layer.h>
14 #include <net/caif/cfpkt.h>
15 #include <net/caif/cffrml.h>
17 #define container_obj(layr) container_of(layr, struct cffrml, layer)
21 bool dofcs
; /* !< FCS active */
24 static int cffrml_receive(struct cflayer
*layr
, struct cfpkt
*pkt
);
25 static int cffrml_transmit(struct cflayer
*layr
, struct cfpkt
*pkt
);
26 static void cffrml_ctrlcmd(struct cflayer
*layr
, enum caif_ctrlcmd ctrl
,
29 static u32 cffrml_rcv_error
;
30 static u32 cffrml_rcv_checsum_error
;
31 struct cflayer
*cffrml_create(u16 phyid
, bool use_fcs
)
33 struct cffrml
*this = kmalloc(sizeof(struct cffrml
), GFP_ATOMIC
);
35 pr_warning("CAIF: %s(): Out of memory\n", __func__
);
38 caif_assert(offsetof(struct cffrml
, layer
) == 0);
40 memset(this, 0, sizeof(struct cflayer
));
41 this->layer
.receive
= cffrml_receive
;
42 this->layer
.transmit
= cffrml_transmit
;
43 this->layer
.ctrlcmd
= cffrml_ctrlcmd
;
44 snprintf(this->layer
.name
, CAIF_LAYER_NAME_SZ
, "frm%d", phyid
);
45 this->dofcs
= use_fcs
;
46 this->layer
.id
= phyid
;
47 return (struct cflayer
*) this;
50 void cffrml_set_uplayer(struct cflayer
*this, struct cflayer
*up
)
55 void cffrml_set_dnlayer(struct cflayer
*this, struct cflayer
*dn
)
60 static u16
cffrml_checksum(u16 chks
, void *buf
, u16 len
)
62 /* FIXME: FCS should be moved to glue in order to use OS-Specific
65 return crc_ccitt(chks
, buf
, len
);
68 static int cffrml_receive(struct cflayer
*layr
, struct cfpkt
*pkt
)
75 this = container_obj(layr
);
77 cfpkt_extr_head(pkt
, &tmp
, 2);
78 len
= le16_to_cpu(tmp
);
80 /* Subtract for FCS on length if FCS is not used. */
84 if (cfpkt_setlen(pkt
, len
) < 0) {
86 pr_err("CAIF: %s():Framing length error (%d)\n", __func__
, len
);
91 * Don't do extract if FCS is false, rather do setlen - then we don't
95 cfpkt_extr_trail(pkt
, &tmp
, 2);
96 hdrchks
= le16_to_cpu(tmp
);
97 pktchks
= cfpkt_iterate(pkt
, cffrml_checksum
, 0xffff);
98 if (pktchks
!= hdrchks
) {
99 cfpkt_add_trail(pkt
, &tmp
, 2);
101 ++cffrml_rcv_checsum_error
;
102 pr_info("CAIF: %s(): Frame checksum error "
103 "(0x%x != 0x%x)\n", __func__
, hdrchks
, pktchks
);
107 if (cfpkt_erroneous(pkt
)) {
109 pr_err("CAIF: %s(): Packet is erroneous!\n", __func__
);
113 return layr
->up
->receive(layr
->up
, pkt
);
116 static int cffrml_transmit(struct cflayer
*layr
, struct cfpkt
*pkt
)
122 struct cffrml
*this = container_obj(layr
);
124 chks
= cfpkt_iterate(pkt
, cffrml_checksum
, 0xffff);
125 tmp
= cpu_to_le16(chks
);
126 cfpkt_add_trail(pkt
, &tmp
, 2);
128 cfpkt_pad_trail(pkt
, 2);
130 len
= cfpkt_getlen(pkt
);
131 tmp
= cpu_to_le16(len
);
132 cfpkt_add_head(pkt
, &tmp
, 2);
133 cfpkt_info(pkt
)->hdr_len
+= 2;
134 if (cfpkt_erroneous(pkt
)) {
135 pr_err("CAIF: %s(): Packet is erroneous!\n", __func__
);
138 ret
= layr
->dn
->transmit(layr
->dn
, pkt
);
140 /* Remove header on faulty packet. */
141 cfpkt_extr_head(pkt
, &tmp
, 2);
146 static void cffrml_ctrlcmd(struct cflayer
*layr
, enum caif_ctrlcmd ctrl
,
149 if (layr
->up
->ctrlcmd
)
150 layr
->up
->ctrlcmd(layr
->up
, ctrl
, layr
->id
);