Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
net
caif
cfserl.c
Go to the documentation of this file.
1
/*
2
* Copyright (C) ST-Ericsson AB 2010
3
* Author: Sjur Brendeland/
[email protected]
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
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->
usestx
= use_stx;
44
spin_lock_init
(&this->
sync
);
45
snprintf
(this->
layer
.name,
CAIF_LAYER_NAME_SZ
,
"ser1"
);
46
return
&this->
layer
;
47
}
48
49
static
int
cfserl_receive(
struct
cflayer
*
l
,
struct
cfpkt
*newpkt)
50
{
51
struct
cfserl
*layr =
container_obj
(l);
52
u16
pkt_len
;
53
struct
cfpkt
*pkt =
NULL
;
54
struct
cfpkt
*tail_pkt =
NULL
;
55
u8
tmp8;
56
u16
tmp
;
57
u8
stx =
CFSERL_STX
;
58
int
ret
;
59
u16
expectlen = 0;
60
61
caif_assert
(newpkt !=
NULL
);
62
spin_lock(&layr->
sync
);
63
64
if
(layr->
incomplete_frm
!=
NULL
) {
65
layr->
incomplete_frm
=
66
cfpkt_append
(layr->
incomplete_frm
, newpkt, expectlen);
67
pkt = layr->
incomplete_frm
;
68
if
(pkt ==
NULL
) {
69
spin_unlock(&layr->
sync
);
70
return
-
ENOMEM
;
71
}
72
}
else
{
73
pkt = newpkt;
74
}
75
layr->
incomplete_frm
=
NULL
;
76
77
do
{
78
/* Search for STX at start of pkt if STX is used */
79
if
(layr->
usestx
) {
80
cfpkt_extr_head
(pkt, &tmp8, 1);
81
if
(tmp8 !=
CFSERL_STX
) {
82
while
(
cfpkt_more
(pkt)
83
&& tmp8 !=
CFSERL_STX
) {
84
cfpkt_extr_head
(pkt, &tmp8, 1);
85
}
86
if
(!
cfpkt_more
(pkt)) {
87
cfpkt_destroy
(pkt);
88
layr->
incomplete_frm
=
NULL
;
89
spin_unlock(&layr->
sync
);
90
return
-
EPROTO
;
91
}
92
}
93
}
94
95
pkt_len =
cfpkt_getlen
(pkt);
96
97
/*
98
* pkt_len is the accumulated length of the packet data
99
* we have received so far.
100
* Exit if frame doesn't hold length.
101
*/
102
103
if
(pkt_len < 2) {
104
if
(layr->
usestx
)
105
cfpkt_add_head
(pkt, &stx, 1);
106
layr->
incomplete_frm
= pkt;
107
spin_unlock(&layr->
sync
);
108
return
0;
109
}
110
111
/*
112
* Find length of frame.
113
* expectlen is the length we need for a full frame.
114
*/
115
cfpkt_peek_head
(pkt, &tmp, 2);
116
expectlen =
le16_to_cpu
(tmp) + 2;
117
/*
118
* Frame error handling
119
*/
120
if
(expectlen <
SERIAL_MINIUM_PACKET_SIZE
121
|| expectlen >
SERIAL_MAX_FRAMESIZE
) {
122
if
(!layr->
usestx
) {
123
if
(pkt !=
NULL
)
124
cfpkt_destroy
(pkt);
125
layr->
incomplete_frm
=
NULL
;
126
expectlen = 0;
127
spin_unlock(&layr->
sync
);
128
return
-
EPROTO
;
129
}
130
continue
;
131
}
132
133
if
(pkt_len < expectlen) {
134
/* Too little received data */
135
if
(layr->
usestx
)
136
cfpkt_add_head
(pkt, &stx, 1);
137
layr->
incomplete_frm
= pkt;
138
spin_unlock(&layr->
sync
);
139
return
0;
140
}
141
142
/*
143
* Enough data for at least one frame.
144
* Split the frame, if too long
145
*/
146
if
(pkt_len > expectlen)
147
tail_pkt =
cfpkt_split
(pkt, expectlen);
148
else
149
tail_pkt =
NULL
;
150
151
/* Send the first part of packet upwards.*/
152
spin_unlock(&layr->
sync
);
153
ret = layr->
layer
.up->receive(layr->
layer
.up, pkt);
154
spin_lock(&layr->
sync
);
155
if
(ret == -
EILSEQ
) {
156
if
(layr->
usestx
) {
157
if
(tail_pkt !=
NULL
)
158
pkt =
cfpkt_append
(pkt, tail_pkt, 0);
159
/* Start search for next STX if frame failed */
160
continue
;
161
}
else
{
162
cfpkt_destroy
(pkt);
163
pkt =
NULL
;
164
}
165
}
166
167
pkt = tail_pkt;
168
169
}
while
(pkt !=
NULL
);
170
171
spin_unlock(&layr->
sync
);
172
return
0;
173
}
174
175
static
int
cfserl_transmit(
struct
cflayer
*layer,
struct
cfpkt
*newpkt)
176
{
177
struct
cfserl
*layr =
container_obj
(layer);
178
u8
tmp8 =
CFSERL_STX
;
179
if
(layr->
usestx
)
180
cfpkt_add_head
(newpkt, &tmp8, 1);
181
return
layer->
dn
->transmit(layer->
dn
, newpkt);
182
}
183
184
static
void
cfserl_ctrlcmd(
struct
cflayer
*layr,
enum
caif_ctrlcmd
ctrl
,
185
int
phyid)
186
{
187
layr->
up
->ctrlcmd(layr->
up
, ctrl, phyid);
188
}
Generated on Thu Jan 10 2013 14:57:18 for Linux Kernel by
1.8.2