diff options
Diffstat (limited to 'drivers/isdn/gigaset/asyncdata.c')
-rw-r--r-- | drivers/isdn/gigaset/asyncdata.c | 662 |
1 files changed, 351 insertions, 311 deletions
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 44a58e6f8f65..ccb2a7b7c41d 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | /* check if byte must be stuffed/escaped | 20 | /* check if byte must be stuffed/escaped |
21 | * I'm not sure which data should be encoded. | 21 | * I'm not sure which data should be encoded. |
22 | * Therefore I will go the hard way and decode every value | 22 | * Therefore I will go the hard way and encode every value |
23 | * less than 0x20, the flag sequence and the control escape char. | 23 | * less than 0x20, the flag sequence and the control escape char. |
24 | */ | 24 | */ |
25 | static inline int muststuff(unsigned char c) | 25 | static inline int muststuff(unsigned char c) |
@@ -35,303 +35,383 @@ static inline int muststuff(unsigned char c) | |||
35 | 35 | ||
36 | /* == data input =========================================================== */ | 36 | /* == data input =========================================================== */ |
37 | 37 | ||
38 | /* process a block of received bytes in command mode (modem response) | 38 | /* process a block of received bytes in command mode |
39 | * (mstate != MS_LOCKED && (inputstate & INS_command)) | ||
40 | * Append received bytes to the command response buffer and forward them | ||
41 | * line by line to the response handler. Exit whenever a mode/state change | ||
42 | * might have occurred. | ||
39 | * Return value: | 43 | * Return value: |
40 | * number of processed bytes | 44 | * number of processed bytes |
41 | */ | 45 | */ |
42 | static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, | 46 | static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf) |
43 | struct inbuf_t *inbuf) | ||
44 | { | 47 | { |
48 | unsigned char *src = inbuf->data + inbuf->head; | ||
45 | struct cardstate *cs = inbuf->cs; | 49 | struct cardstate *cs = inbuf->cs; |
46 | unsigned cbytes = cs->cbytes; | 50 | unsigned cbytes = cs->cbytes; |
47 | int inputstate = inbuf->inputstate; | 51 | unsigned procbytes = 0; |
48 | int startbytes = numbytes; | 52 | unsigned char c; |
49 | 53 | ||
50 | for (;;) { | 54 | while (procbytes < numbytes) { |
51 | cs->respdata[cbytes] = c; | 55 | c = *src++; |
52 | if (c == 10 || c == 13) { | 56 | procbytes++; |
53 | gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", | 57 | |
58 | switch (c) { | ||
59 | case '\n': | ||
60 | if (cbytes == 0 && cs->respdata[0] == '\r') { | ||
61 | /* collapse LF with preceding CR */ | ||
62 | cs->respdata[0] = 0; | ||
63 | break; | ||
64 | } | ||
65 | /* --v-- fall through --v-- */ | ||
66 | case '\r': | ||
67 | /* end of message line, pass to response handler */ | ||
68 | gig_dbg(DEBUG_TRANSCMD, "%s: End of Message (%d Bytes)", | ||
54 | __func__, cbytes); | 69 | __func__, cbytes); |
70 | if (cbytes >= MAX_RESP_SIZE) { | ||
71 | dev_warn(cs->dev, "response too large (%d)\n", | ||
72 | cbytes); | ||
73 | cbytes = MAX_RESP_SIZE; | ||
74 | } | ||
55 | cs->cbytes = cbytes; | 75 | cs->cbytes = cbytes; |
56 | gigaset_handle_modem_response(cs); /* can change | 76 | gigaset_handle_modem_response(cs); |
57 | cs->dle */ | ||
58 | cbytes = 0; | 77 | cbytes = 0; |
59 | 78 | ||
60 | if (cs->dle && | 79 | /* store EOL byte for CRLF collapsing */ |
61 | !(inputstate & INS_DLE_command)) { | 80 | cs->respdata[0] = c; |
62 | inputstate &= ~INS_command; | ||
63 | break; | ||
64 | } | ||
65 | } else { | ||
66 | /* advance in line buffer, checking for overflow */ | ||
67 | if (cbytes < MAX_RESP_SIZE - 1) | ||
68 | cbytes++; | ||
69 | else | ||
70 | dev_warn(cs->dev, "response too large\n"); | ||
71 | } | ||
72 | 81 | ||
73 | if (!numbytes) | 82 | /* cs->dle may have changed */ |
74 | break; | 83 | if (cs->dle && !(inbuf->inputstate & INS_DLE_command)) |
75 | c = *src++; | 84 | inbuf->inputstate &= ~INS_command; |
76 | --numbytes; | 85 | |
77 | if (c == DLE_FLAG && | 86 | /* return for reevaluating state */ |
78 | (cs->dle || inputstate & INS_DLE_command)) { | 87 | goto exit; |
79 | inputstate |= INS_DLE_char; | 88 | |
80 | break; | 89 | case DLE_FLAG: |
90 | if (inbuf->inputstate & INS_DLE_char) { | ||
91 | /* quoted DLE: clear quote flag */ | ||
92 | inbuf->inputstate &= ~INS_DLE_char; | ||
93 | } else if (cs->dle || | ||
94 | (inbuf->inputstate & INS_DLE_command)) { | ||
95 | /* DLE escape, pass up for handling */ | ||
96 | inbuf->inputstate |= INS_DLE_char; | ||
97 | goto exit; | ||
98 | } | ||
99 | /* quoted or not in DLE mode: treat as regular data */ | ||
100 | /* --v-- fall through --v-- */ | ||
101 | default: | ||
102 | /* append to line buffer if possible */ | ||
103 | if (cbytes < MAX_RESP_SIZE) | ||
104 | cs->respdata[cbytes] = c; | ||
105 | cbytes++; | ||
81 | } | 106 | } |
82 | } | 107 | } |
83 | 108 | exit: | |
84 | cs->cbytes = cbytes; | 109 | cs->cbytes = cbytes; |
85 | inbuf->inputstate = inputstate; | 110 | return procbytes; |
86 | |||
87 | return startbytes - numbytes; | ||
88 | } | 111 | } |
89 | 112 | ||
90 | /* process a block of received bytes in lock mode (tty i/f) | 113 | /* process a block of received bytes in lock mode |
114 | * All received bytes are passed unmodified to the tty i/f. | ||
91 | * Return value: | 115 | * Return value: |
92 | * number of processed bytes | 116 | * number of processed bytes |
93 | */ | 117 | */ |
94 | static inline int lock_loop(unsigned char *src, int numbytes, | 118 | static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf) |
95 | struct inbuf_t *inbuf) | ||
96 | { | 119 | { |
97 | struct cardstate *cs = inbuf->cs; | 120 | unsigned char *src = inbuf->data + inbuf->head; |
98 | |||
99 | gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", | ||
100 | numbytes, src); | ||
101 | gigaset_if_receive(cs, src, numbytes); | ||
102 | 121 | ||
122 | gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src); | ||
123 | gigaset_if_receive(inbuf->cs, src, numbytes); | ||
103 | return numbytes; | 124 | return numbytes; |
104 | } | 125 | } |
105 | 126 | ||
127 | /* set up next receive skb for data mode | ||
128 | */ | ||
129 | static void new_rcv_skb(struct bc_state *bcs) | ||
130 | { | ||
131 | struct cardstate *cs = bcs->cs; | ||
132 | unsigned short hw_hdr_len = cs->hw_hdr_len; | ||
133 | |||
134 | if (bcs->ignore) { | ||
135 | bcs->skb = NULL; | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); | ||
140 | if (bcs->skb == NULL) { | ||
141 | dev_warn(cs->dev, "could not allocate new skb\n"); | ||
142 | return; | ||
143 | } | ||
144 | skb_reserve(bcs->skb, hw_hdr_len); | ||
145 | } | ||
146 | |||
106 | /* process a block of received bytes in HDLC data mode | 147 | /* process a block of received bytes in HDLC data mode |
148 | * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) | ||
107 | * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. | 149 | * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. |
108 | * When a frame is complete, check the FCS and pass valid frames to the LL. | 150 | * When a frame is complete, check the FCS and pass valid frames to the LL. |
109 | * If DLE is encountered, return immediately to let the caller handle it. | 151 | * If DLE is encountered, return immediately to let the caller handle it. |
110 | * Return value: | 152 | * Return value: |
111 | * number of processed bytes | 153 | * number of processed bytes |
112 | * numbytes (all bytes processed) on error --FIXME | ||
113 | */ | 154 | */ |
114 | static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, | 155 | static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) |
115 | struct inbuf_t *inbuf) | ||
116 | { | 156 | { |
117 | struct cardstate *cs = inbuf->cs; | 157 | struct cardstate *cs = inbuf->cs; |
118 | struct bc_state *bcs = inbuf->bcs; | 158 | struct bc_state *bcs = cs->bcs; |
119 | int inputstate = bcs->inputstate; | 159 | int inputstate = bcs->inputstate; |
120 | __u16 fcs = bcs->fcs; | 160 | __u16 fcs = bcs->fcs; |
121 | struct sk_buff *skb = bcs->skb; | 161 | struct sk_buff *skb = bcs->skb; |
122 | unsigned char error; | 162 | unsigned char *src = inbuf->data + inbuf->head; |
123 | struct sk_buff *compskb; | 163 | unsigned procbytes = 0; |
124 | int startbytes = numbytes; | 164 | unsigned char c; |
125 | int l; | ||
126 | 165 | ||
127 | if (unlikely(inputstate & INS_byte_stuff)) { | 166 | if (inputstate & INS_byte_stuff) { |
167 | if (!numbytes) | ||
168 | return 0; | ||
128 | inputstate &= ~INS_byte_stuff; | 169 | inputstate &= ~INS_byte_stuff; |
129 | goto byte_stuff; | 170 | goto byte_stuff; |
130 | } | 171 | } |
131 | for (;;) { | 172 | |
132 | if (unlikely(c == PPP_ESCAPE)) { | 173 | while (procbytes < numbytes) { |
133 | if (unlikely(!numbytes)) { | 174 | c = *src++; |
134 | inputstate |= INS_byte_stuff; | 175 | procbytes++; |
176 | if (c == DLE_FLAG) { | ||
177 | if (inputstate & INS_DLE_char) { | ||
178 | /* quoted DLE: clear quote flag */ | ||
179 | inputstate &= ~INS_DLE_char; | ||
180 | } else if (cs->dle || (inputstate & INS_DLE_command)) { | ||
181 | /* DLE escape, pass up for handling */ | ||
182 | inputstate |= INS_DLE_char; | ||
135 | break; | 183 | break; |
136 | } | 184 | } |
137 | c = *src++; | 185 | } |
138 | --numbytes; | 186 | |
139 | if (unlikely(c == DLE_FLAG && | 187 | if (c == PPP_ESCAPE) { |
140 | (cs->dle || | 188 | /* byte stuffing indicator: pull in next byte */ |
141 | inbuf->inputstate & INS_DLE_command))) { | 189 | if (procbytes >= numbytes) { |
142 | inbuf->inputstate |= INS_DLE_char; | 190 | /* end of buffer, save for later processing */ |
143 | inputstate |= INS_byte_stuff; | 191 | inputstate |= INS_byte_stuff; |
144 | break; | 192 | break; |
145 | } | 193 | } |
146 | byte_stuff: | 194 | byte_stuff: |
195 | c = *src++; | ||
196 | procbytes++; | ||
197 | if (c == DLE_FLAG) { | ||
198 | if (inputstate & INS_DLE_char) { | ||
199 | /* quoted DLE: clear quote flag */ | ||
200 | inputstate &= ~INS_DLE_char; | ||
201 | } else if (cs->dle || | ||
202 | (inputstate & INS_DLE_command)) { | ||
203 | /* DLE escape, pass up for handling */ | ||
204 | inputstate |= | ||
205 | INS_DLE_char | INS_byte_stuff; | ||
206 | break; | ||
207 | } | ||
208 | } | ||
147 | c ^= PPP_TRANS; | 209 | c ^= PPP_TRANS; |
148 | if (unlikely(!muststuff(c))) | ||
149 | gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); | ||
150 | } else if (unlikely(c == PPP_FLAG)) { | ||
151 | if (unlikely(inputstate & INS_skip_frame)) { | ||
152 | #ifdef CONFIG_GIGASET_DEBUG | ||
153 | if (!(inputstate & INS_have_data)) { /* 7E 7E */ | ||
154 | ++bcs->emptycount; | ||
155 | } else | ||
156 | gig_dbg(DEBUG_HDLC, | ||
157 | "7e----------------------------"); | ||
158 | #endif | ||
159 | |||
160 | /* end of frame */ | ||
161 | error = 1; | ||
162 | gigaset_rcv_error(NULL, cs, bcs); | ||
163 | } else if (!(inputstate & INS_have_data)) { /* 7E 7E */ | ||
164 | #ifdef CONFIG_GIGASET_DEBUG | 210 | #ifdef CONFIG_GIGASET_DEBUG |
165 | ++bcs->emptycount; | 211 | if (!muststuff(c)) |
212 | gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); | ||
166 | #endif | 213 | #endif |
167 | break; | 214 | } else if (c == PPP_FLAG) { |
168 | } else { | 215 | /* end of frame: process content if any */ |
216 | if (inputstate & INS_have_data) { | ||
169 | gig_dbg(DEBUG_HDLC, | 217 | gig_dbg(DEBUG_HDLC, |
170 | "7e----------------------------"); | 218 | "7e----------------------------"); |
171 | 219 | ||
172 | /* end of frame */ | 220 | /* check and pass received frame */ |
173 | error = 0; | 221 | if (!skb) { |
174 | 222 | /* skipped frame */ | |
175 | if (unlikely(fcs != PPP_GOODFCS)) { | 223 | gigaset_isdn_rcv_err(bcs); |
224 | } else if (skb->len < 2) { | ||
225 | /* frame too short for FCS */ | ||
226 | dev_warn(cs->dev, | ||
227 | "short frame (%d)\n", | ||
228 | skb->len); | ||
229 | gigaset_isdn_rcv_err(bcs); | ||
230 | dev_kfree_skb_any(skb); | ||
231 | } else if (fcs != PPP_GOODFCS) { | ||
232 | /* frame check error */ | ||
176 | dev_err(cs->dev, | 233 | dev_err(cs->dev, |
177 | "Checksum failed, %u bytes corrupted!\n", | 234 | "Checksum failed, %u bytes corrupted!\n", |
178 | skb->len); | 235 | skb->len); |
179 | compskb = NULL; | 236 | gigaset_isdn_rcv_err(bcs); |
180 | gigaset_rcv_error(compskb, cs, bcs); | 237 | dev_kfree_skb_any(skb); |
181 | error = 1; | ||
182 | } else { | 238 | } else { |
183 | if (likely((l = skb->len) > 2)) { | 239 | /* good frame */ |
184 | skb->tail -= 2; | 240 | __skb_trim(skb, skb->len - 2); |
185 | skb->len -= 2; | 241 | gigaset_skb_rcvd(bcs, skb); |
186 | } else { | ||
187 | dev_kfree_skb(skb); | ||
188 | skb = NULL; | ||
189 | inputstate |= INS_skip_frame; | ||
190 | if (l == 1) { | ||
191 | dev_err(cs->dev, | ||
192 | "invalid packet size (1)!\n"); | ||
193 | error = 1; | ||
194 | gigaset_rcv_error(NULL, | ||
195 | cs, bcs); | ||
196 | } | ||
197 | } | ||
198 | if (likely(!(error || | ||
199 | (inputstate & | ||
200 | INS_skip_frame)))) { | ||
201 | gigaset_rcv_skb(skb, cs, bcs); | ||
202 | } | ||
203 | } | 242 | } |
204 | } | ||
205 | 243 | ||
206 | if (unlikely(error)) | 244 | /* prepare reception of next frame */ |
207 | if (skb) | 245 | inputstate &= ~INS_have_data; |
208 | dev_kfree_skb(skb); | 246 | new_rcv_skb(bcs); |
209 | 247 | skb = bcs->skb; | |
210 | fcs = PPP_INITFCS; | ||
211 | inputstate &= ~(INS_have_data | INS_skip_frame); | ||
212 | if (unlikely(bcs->ignore)) { | ||
213 | inputstate |= INS_skip_frame; | ||
214 | skb = NULL; | ||
215 | } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) { | ||
216 | skb_reserve(skb, HW_HDR_LEN); | ||
217 | } else { | 248 | } else { |
218 | dev_warn(cs->dev, | 249 | /* empty frame (7E 7E) */ |
219 | "could not allocate new skb\n"); | 250 | #ifdef CONFIG_GIGASET_DEBUG |
220 | inputstate |= INS_skip_frame; | 251 | ++bcs->emptycount; |
252 | #endif | ||
253 | if (!skb) { | ||
254 | /* skipped (?) */ | ||
255 | gigaset_isdn_rcv_err(bcs); | ||
256 | new_rcv_skb(bcs); | ||
257 | skb = bcs->skb; | ||
258 | } | ||
221 | } | 259 | } |
222 | 260 | ||
223 | break; | 261 | fcs = PPP_INITFCS; |
224 | } else if (unlikely(muststuff(c))) { | 262 | continue; |
263 | #ifdef CONFIG_GIGASET_DEBUG | ||
264 | } else if (muststuff(c)) { | ||
225 | /* Should not happen. Possible after ZDLE=1<CR><LF>. */ | 265 | /* Should not happen. Possible after ZDLE=1<CR><LF>. */ |
226 | gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); | 266 | gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); |
267 | #endif | ||
227 | } | 268 | } |
228 | 269 | ||
229 | /* add character */ | 270 | /* regular data byte, append to skb */ |
230 | |||
231 | #ifdef CONFIG_GIGASET_DEBUG | 271 | #ifdef CONFIG_GIGASET_DEBUG |
232 | if (unlikely(!(inputstate & INS_have_data))) { | 272 | if (!(inputstate & INS_have_data)) { |
233 | gig_dbg(DEBUG_HDLC, "7e (%d x) ================", | 273 | gig_dbg(DEBUG_HDLC, "7e (%d x) ================", |
234 | bcs->emptycount); | 274 | bcs->emptycount); |
235 | bcs->emptycount = 0; | 275 | bcs->emptycount = 0; |
236 | } | 276 | } |
237 | #endif | 277 | #endif |
238 | |||
239 | inputstate |= INS_have_data; | 278 | inputstate |= INS_have_data; |
240 | 279 | if (skb) { | |
241 | if (likely(!(inputstate & INS_skip_frame))) { | 280 | if (skb->len == SBUFSIZE) { |
242 | if (unlikely(skb->len == SBUFSIZE)) { | ||
243 | dev_warn(cs->dev, "received packet too long\n"); | 281 | dev_warn(cs->dev, "received packet too long\n"); |
244 | dev_kfree_skb_any(skb); | 282 | dev_kfree_skb_any(skb); |
245 | skb = NULL; | 283 | /* skip remainder of packet */ |
246 | inputstate |= INS_skip_frame; | 284 | bcs->skb = skb = NULL; |
247 | break; | 285 | } else { |
286 | *__skb_put(skb, 1) = c; | ||
287 | fcs = crc_ccitt_byte(fcs, c); | ||
248 | } | 288 | } |
249 | *__skb_put(skb, 1) = c; | ||
250 | fcs = crc_ccitt_byte(fcs, c); | ||
251 | } | ||
252 | |||
253 | if (unlikely(!numbytes)) | ||
254 | break; | ||
255 | c = *src++; | ||
256 | --numbytes; | ||
257 | if (unlikely(c == DLE_FLAG && | ||
258 | (cs->dle || | ||
259 | inbuf->inputstate & INS_DLE_command))) { | ||
260 | inbuf->inputstate |= INS_DLE_char; | ||
261 | break; | ||
262 | } | 289 | } |
263 | } | 290 | } |
291 | |||
264 | bcs->inputstate = inputstate; | 292 | bcs->inputstate = inputstate; |
265 | bcs->fcs = fcs; | 293 | bcs->fcs = fcs; |
266 | bcs->skb = skb; | 294 | return procbytes; |
267 | return startbytes - numbytes; | ||
268 | } | 295 | } |
269 | 296 | ||
270 | /* process a block of received bytes in transparent data mode | 297 | /* process a block of received bytes in transparent data mode |
298 | * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 != L2_HDLC) | ||
271 | * Invert bytes, undoing byte stuffing and watching for DLE escapes. | 299 | * Invert bytes, undoing byte stuffing and watching for DLE escapes. |
272 | * If DLE is encountered, return immediately to let the caller handle it. | 300 | * If DLE is encountered, return immediately to let the caller handle it. |
273 | * Return value: | 301 | * Return value: |
274 | * number of processed bytes | 302 | * number of processed bytes |
275 | * numbytes (all bytes processed) on error --FIXME | ||
276 | */ | 303 | */ |
277 | static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, | 304 | static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) |
278 | struct inbuf_t *inbuf) | ||
279 | { | 305 | { |
280 | struct cardstate *cs = inbuf->cs; | 306 | struct cardstate *cs = inbuf->cs; |
281 | struct bc_state *bcs = inbuf->bcs; | 307 | struct bc_state *bcs = cs->bcs; |
282 | int inputstate = bcs->inputstate; | 308 | int inputstate = bcs->inputstate; |
283 | struct sk_buff *skb = bcs->skb; | 309 | struct sk_buff *skb = bcs->skb; |
284 | int startbytes = numbytes; | 310 | unsigned char *src = inbuf->data + inbuf->head; |
311 | unsigned procbytes = 0; | ||
312 | unsigned char c; | ||
285 | 313 | ||
286 | for (;;) { | 314 | if (!skb) { |
287 | /* add character */ | 315 | /* skip this block */ |
288 | inputstate |= INS_have_data; | 316 | new_rcv_skb(bcs); |
317 | return numbytes; | ||
318 | } | ||
289 | 319 | ||
290 | if (likely(!(inputstate & INS_skip_frame))) { | 320 | while (procbytes < numbytes && skb->len < SBUFSIZE) { |
291 | if (unlikely(skb->len == SBUFSIZE)) { | 321 | c = *src++; |
292 | //FIXME just pass skb up and allocate a new one | 322 | procbytes++; |
293 | dev_warn(cs->dev, "received packet too long\n"); | 323 | |
294 | dev_kfree_skb_any(skb); | 324 | if (c == DLE_FLAG) { |
295 | skb = NULL; | 325 | if (inputstate & INS_DLE_char) { |
296 | inputstate |= INS_skip_frame; | 326 | /* quoted DLE: clear quote flag */ |
327 | inputstate &= ~INS_DLE_char; | ||
328 | } else if (cs->dle || (inputstate & INS_DLE_command)) { | ||
329 | /* DLE escape, pass up for handling */ | ||
330 | inputstate |= INS_DLE_char; | ||
297 | break; | 331 | break; |
298 | } | 332 | } |
299 | *__skb_put(skb, 1) = bitrev8(c); | ||
300 | } | 333 | } |
301 | 334 | ||
302 | if (unlikely(!numbytes)) | 335 | /* regular data byte: append to current skb */ |
303 | break; | 336 | inputstate |= INS_have_data; |
304 | c = *src++; | 337 | *__skb_put(skb, 1) = bitrev8(c); |
305 | --numbytes; | ||
306 | if (unlikely(c == DLE_FLAG && | ||
307 | (cs->dle || | ||
308 | inbuf->inputstate & INS_DLE_command))) { | ||
309 | inbuf->inputstate |= INS_DLE_char; | ||
310 | break; | ||
311 | } | ||
312 | } | 338 | } |
313 | 339 | ||
314 | /* pass data up */ | 340 | /* pass data up */ |
315 | if (likely(inputstate & INS_have_data)) { | 341 | if (inputstate & INS_have_data) { |
316 | if (likely(!(inputstate & INS_skip_frame))) { | 342 | gigaset_skb_rcvd(bcs, skb); |
317 | gigaset_rcv_skb(skb, cs, bcs); | 343 | inputstate &= ~INS_have_data; |
318 | } | 344 | new_rcv_skb(bcs); |
319 | inputstate &= ~(INS_have_data | INS_skip_frame); | 345 | } |
320 | if (unlikely(bcs->ignore)) { | 346 | |
321 | inputstate |= INS_skip_frame; | 347 | bcs->inputstate = inputstate; |
322 | skb = NULL; | 348 | return procbytes; |
323 | } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) | 349 | } |
324 | != NULL)) { | 350 | |
325 | skb_reserve(skb, HW_HDR_LEN); | 351 | /* process DLE escapes |
352 | * Called whenever a DLE sequence might be encountered in the input stream. | ||
353 | * Either processes the entire DLE sequence or, if that isn't possible, | ||
354 | * notes the fact that an initial DLE has been received in the INS_DLE_char | ||
355 | * inputstate flag and resumes processing of the sequence on the next call. | ||
356 | */ | ||
357 | static void handle_dle(struct inbuf_t *inbuf) | ||
358 | { | ||
359 | struct cardstate *cs = inbuf->cs; | ||
360 | |||
361 | if (cs->mstate == MS_LOCKED) | ||
362 | return; /* no DLE processing in lock mode */ | ||
363 | |||
364 | if (!(inbuf->inputstate & INS_DLE_char)) { | ||
365 | /* no DLE pending */ | ||
366 | if (inbuf->data[inbuf->head] == DLE_FLAG && | ||
367 | (cs->dle || inbuf->inputstate & INS_DLE_command)) { | ||
368 | /* start of DLE sequence */ | ||
369 | inbuf->head++; | ||
370 | if (inbuf->head == inbuf->tail || | ||
371 | inbuf->head == RBUFSIZE) { | ||
372 | /* end of buffer, save for later processing */ | ||
373 | inbuf->inputstate |= INS_DLE_char; | ||
374 | return; | ||
375 | } | ||
326 | } else { | 376 | } else { |
327 | dev_warn(cs->dev, "could not allocate new skb\n"); | 377 | /* regular data byte */ |
328 | inputstate |= INS_skip_frame; | 378 | return; |
329 | } | 379 | } |
330 | } | 380 | } |
331 | 381 | ||
332 | bcs->inputstate = inputstate; | 382 | /* consume pending DLE */ |
333 | bcs->skb = skb; | 383 | inbuf->inputstate &= ~INS_DLE_char; |
334 | return startbytes - numbytes; | 384 | |
385 | switch (inbuf->data[inbuf->head]) { | ||
386 | case 'X': /* begin of event message */ | ||
387 | if (inbuf->inputstate & INS_command) | ||
388 | dev_notice(cs->dev, | ||
389 | "received <DLE>X in command mode\n"); | ||
390 | inbuf->inputstate |= INS_command | INS_DLE_command; | ||
391 | inbuf->head++; /* byte consumed */ | ||
392 | break; | ||
393 | case '.': /* end of event message */ | ||
394 | if (!(inbuf->inputstate & INS_DLE_command)) | ||
395 | dev_notice(cs->dev, | ||
396 | "received <DLE>. without <DLE>X\n"); | ||
397 | inbuf->inputstate &= ~INS_DLE_command; | ||
398 | /* return to data mode if in DLE mode */ | ||
399 | if (cs->dle) | ||
400 | inbuf->inputstate &= ~INS_command; | ||
401 | inbuf->head++; /* byte consumed */ | ||
402 | break; | ||
403 | case DLE_FLAG: /* DLE in data stream */ | ||
404 | /* mark as quoted */ | ||
405 | inbuf->inputstate |= INS_DLE_char; | ||
406 | if (!(cs->dle || inbuf->inputstate & INS_DLE_command)) | ||
407 | dev_notice(cs->dev, | ||
408 | "received <DLE><DLE> not in DLE mode\n"); | ||
409 | break; /* quoted byte left in buffer */ | ||
410 | default: | ||
411 | dev_notice(cs->dev, "received <DLE><%02x>\n", | ||
412 | inbuf->data[inbuf->head]); | ||
413 | /* quoted byte left in buffer */ | ||
414 | } | ||
335 | } | 415 | } |
336 | 416 | ||
337 | /** | 417 | /** |
@@ -345,94 +425,39 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, | |||
345 | */ | 425 | */ |
346 | void gigaset_m10x_input(struct inbuf_t *inbuf) | 426 | void gigaset_m10x_input(struct inbuf_t *inbuf) |
347 | { | 427 | { |
348 | struct cardstate *cs; | 428 | struct cardstate *cs = inbuf->cs; |
349 | unsigned tail, head, numbytes; | 429 | unsigned numbytes, procbytes; |
350 | unsigned char *src, c; | ||
351 | int procbytes; | ||
352 | |||
353 | head = inbuf->head; | ||
354 | tail = inbuf->tail; | ||
355 | gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); | ||
356 | |||
357 | if (head != tail) { | ||
358 | cs = inbuf->cs; | ||
359 | src = inbuf->data + head; | ||
360 | numbytes = (head > tail ? RBUFSIZE : tail) - head; | ||
361 | gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); | ||
362 | 430 | ||
363 | while (numbytes) { | 431 | gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", inbuf->head, inbuf->tail); |
364 | if (cs->mstate == MS_LOCKED) { | ||
365 | procbytes = lock_loop(src, numbytes, inbuf); | ||
366 | src += procbytes; | ||
367 | numbytes -= procbytes; | ||
368 | } else { | ||
369 | c = *src++; | ||
370 | --numbytes; | ||
371 | if (c == DLE_FLAG && (cs->dle || | ||
372 | inbuf->inputstate & INS_DLE_command)) { | ||
373 | if (!(inbuf->inputstate & INS_DLE_char)) { | ||
374 | inbuf->inputstate |= INS_DLE_char; | ||
375 | goto nextbyte; | ||
376 | } | ||
377 | /* <DLE> <DLE> => <DLE> in data stream */ | ||
378 | inbuf->inputstate &= ~INS_DLE_char; | ||
379 | } | ||
380 | 432 | ||
381 | if (!(inbuf->inputstate & INS_DLE_char)) { | 433 | while (inbuf->head != inbuf->tail) { |
382 | 434 | /* check for DLE escape */ | |
383 | /* FIXME use function pointers? */ | 435 | handle_dle(inbuf); |
384 | if (inbuf->inputstate & INS_command) | ||
385 | procbytes = cmd_loop(c, src, numbytes, inbuf); | ||
386 | else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC) | ||
387 | procbytes = hdlc_loop(c, src, numbytes, inbuf); | ||
388 | else | ||
389 | procbytes = iraw_loop(c, src, numbytes, inbuf); | ||
390 | |||
391 | src += procbytes; | ||
392 | numbytes -= procbytes; | ||
393 | } else { /* DLE char */ | ||
394 | inbuf->inputstate &= ~INS_DLE_char; | ||
395 | switch (c) { | ||
396 | case 'X': /*begin of command*/ | ||
397 | if (inbuf->inputstate & INS_command) | ||
398 | dev_warn(cs->dev, | ||
399 | "received <DLE> 'X' in command mode\n"); | ||
400 | inbuf->inputstate |= | ||
401 | INS_command | INS_DLE_command; | ||
402 | break; | ||
403 | case '.': /*end of command*/ | ||
404 | if (!(inbuf->inputstate & INS_command)) | ||
405 | dev_warn(cs->dev, | ||
406 | "received <DLE> '.' in hdlc mode\n"); | ||
407 | inbuf->inputstate &= cs->dle ? | ||
408 | ~(INS_DLE_command|INS_command) | ||
409 | : ~INS_DLE_command; | ||
410 | break; | ||
411 | //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */ | ||
412 | default: | ||
413 | dev_err(cs->dev, | ||
414 | "received 0x10 0x%02x!\n", | ||
415 | (int) c); | ||
416 | /* FIXME: reset driver?? */ | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | nextbyte: | ||
421 | if (!numbytes) { | ||
422 | /* end of buffer, check for wrap */ | ||
423 | if (head > tail) { | ||
424 | head = 0; | ||
425 | src = inbuf->data; | ||
426 | numbytes = tail; | ||
427 | } else { | ||
428 | head = tail; | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | 436 | ||
434 | gig_dbg(DEBUG_INTR, "setting head to %u", head); | 437 | /* process a contiguous block of bytes */ |
435 | inbuf->head = head; | 438 | numbytes = (inbuf->head > inbuf->tail ? |
439 | RBUFSIZE : inbuf->tail) - inbuf->head; | ||
440 | gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); | ||
441 | /* | ||
442 | * numbytes may be 0 if handle_dle() ate the last byte. | ||
443 | * This does no harm, *_loop() will just return 0 immediately. | ||
444 | */ | ||
445 | |||
446 | if (cs->mstate == MS_LOCKED) | ||
447 | procbytes = lock_loop(numbytes, inbuf); | ||
448 | else if (inbuf->inputstate & INS_command) | ||
449 | procbytes = cmd_loop(numbytes, inbuf); | ||
450 | else if (cs->bcs->proto2 == L2_HDLC) | ||
451 | procbytes = hdlc_loop(numbytes, inbuf); | ||
452 | else | ||
453 | procbytes = iraw_loop(numbytes, inbuf); | ||
454 | inbuf->head += procbytes; | ||
455 | |||
456 | /* check for buffer wraparound */ | ||
457 | if (inbuf->head >= RBUFSIZE) | ||
458 | inbuf->head = 0; | ||
459 | |||
460 | gig_dbg(DEBUG_INTR, "head set to %u", inbuf->head); | ||
436 | } | 461 | } |
437 | } | 462 | } |
438 | EXPORT_SYMBOL_GPL(gigaset_m10x_input); | 463 | EXPORT_SYMBOL_GPL(gigaset_m10x_input); |
@@ -440,16 +465,16 @@ EXPORT_SYMBOL_GPL(gigaset_m10x_input); | |||
440 | 465 | ||
441 | /* == data output ========================================================== */ | 466 | /* == data output ========================================================== */ |
442 | 467 | ||
443 | /* Encoding of a PPP packet into an octet stuffed HDLC frame | 468 | /* |
444 | * with FCS, opening and closing flags. | 469 | * Encode a data packet into an octet stuffed HDLC frame with FCS, |
470 | * opening and closing flags, preserving headroom data. | ||
445 | * parameters: | 471 | * parameters: |
446 | * skb skb containing original packet (freed upon return) | 472 | * skb skb containing original packet (freed upon return) |
447 | * head number of headroom bytes to allocate in result skb | ||
448 | * tail number of tailroom bytes to allocate in result skb | ||
449 | * Return value: | 473 | * Return value: |
450 | * pointer to newly allocated skb containing the result frame | 474 | * pointer to newly allocated skb containing the result frame |
475 | * and the original link layer header, NULL on error | ||
451 | */ | 476 | */ |
452 | static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) | 477 | static struct sk_buff *HDLC_Encode(struct sk_buff *skb) |
453 | { | 478 | { |
454 | struct sk_buff *hdlc_skb; | 479 | struct sk_buff *hdlc_skb; |
455 | __u16 fcs; | 480 | __u16 fcs; |
@@ -471,16 +496,19 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) | |||
471 | 496 | ||
472 | /* size of new buffer: original size + number of stuffing bytes | 497 | /* size of new buffer: original size + number of stuffing bytes |
473 | * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes | 498 | * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes |
499 | * + room for link layer header | ||
474 | */ | 500 | */ |
475 | hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head); | 501 | hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + skb->mac_len); |
476 | if (!hdlc_skb) { | 502 | if (!hdlc_skb) { |
477 | dev_kfree_skb(skb); | 503 | dev_kfree_skb_any(skb); |
478 | return NULL; | 504 | return NULL; |
479 | } | 505 | } |
480 | skb_reserve(hdlc_skb, head); | ||
481 | 506 | ||
482 | /* Copy acknowledge request into new skb */ | 507 | /* Copy link layer header into new skb */ |
483 | memcpy(hdlc_skb->head, skb->head, 2); | 508 | skb_reset_mac_header(hdlc_skb); |
509 | skb_reserve(hdlc_skb, skb->mac_len); | ||
510 | memcpy(skb_mac_header(hdlc_skb), skb_mac_header(skb), skb->mac_len); | ||
511 | hdlc_skb->mac_len = skb->mac_len; | ||
484 | 512 | ||
485 | /* Add flag sequence in front of everything.. */ | 513 | /* Add flag sequence in front of everything.. */ |
486 | *(skb_put(hdlc_skb, 1)) = PPP_FLAG; | 514 | *(skb_put(hdlc_skb, 1)) = PPP_FLAG; |
@@ -511,33 +539,42 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) | |||
511 | 539 | ||
512 | *(skb_put(hdlc_skb, 1)) = PPP_FLAG; | 540 | *(skb_put(hdlc_skb, 1)) = PPP_FLAG; |
513 | 541 | ||
514 | dev_kfree_skb(skb); | 542 | dev_kfree_skb_any(skb); |
515 | return hdlc_skb; | 543 | return hdlc_skb; |
516 | } | 544 | } |
517 | 545 | ||
518 | /* Encoding of a raw packet into an octet stuffed bit inverted frame | 546 | /* |
547 | * Encode a data packet into an octet stuffed raw bit inverted frame, | ||
548 | * preserving headroom data. | ||
519 | * parameters: | 549 | * parameters: |
520 | * skb skb containing original packet (freed upon return) | 550 | * skb skb containing original packet (freed upon return) |
521 | * head number of headroom bytes to allocate in result skb | ||
522 | * tail number of tailroom bytes to allocate in result skb | ||
523 | * Return value: | 551 | * Return value: |
524 | * pointer to newly allocated skb containing the result frame | 552 | * pointer to newly allocated skb containing the result frame |
553 | * and the original link layer header, NULL on error | ||
525 | */ | 554 | */ |
526 | static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) | 555 | static struct sk_buff *iraw_encode(struct sk_buff *skb) |
527 | { | 556 | { |
528 | struct sk_buff *iraw_skb; | 557 | struct sk_buff *iraw_skb; |
529 | unsigned char c; | 558 | unsigned char c; |
530 | unsigned char *cp; | 559 | unsigned char *cp; |
531 | int len; | 560 | int len; |
532 | 561 | ||
533 | /* worst case: every byte must be stuffed */ | 562 | /* size of new buffer (worst case = every byte must be stuffed): |
534 | iraw_skb = dev_alloc_skb(2*skb->len + tail + head); | 563 | * 2 * original size + room for link layer header |
564 | */ | ||
565 | iraw_skb = dev_alloc_skb(2*skb->len + skb->mac_len); | ||
535 | if (!iraw_skb) { | 566 | if (!iraw_skb) { |
536 | dev_kfree_skb(skb); | 567 | dev_kfree_skb_any(skb); |
537 | return NULL; | 568 | return NULL; |
538 | } | 569 | } |
539 | skb_reserve(iraw_skb, head); | ||
540 | 570 | ||
571 | /* copy link layer header into new skb */ | ||
572 | skb_reset_mac_header(iraw_skb); | ||
573 | skb_reserve(iraw_skb, skb->mac_len); | ||
574 | memcpy(skb_mac_header(iraw_skb), skb_mac_header(skb), skb->mac_len); | ||
575 | iraw_skb->mac_len = skb->mac_len; | ||
576 | |||
577 | /* copy and stuff data */ | ||
541 | cp = skb->data; | 578 | cp = skb->data; |
542 | len = skb->len; | 579 | len = skb->len; |
543 | while (len--) { | 580 | while (len--) { |
@@ -546,7 +583,7 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) | |||
546 | *(skb_put(iraw_skb, 1)) = c; | 583 | *(skb_put(iraw_skb, 1)) = c; |
547 | *(skb_put(iraw_skb, 1)) = c; | 584 | *(skb_put(iraw_skb, 1)) = c; |
548 | } | 585 | } |
549 | dev_kfree_skb(skb); | 586 | dev_kfree_skb_any(skb); |
550 | return iraw_skb; | 587 | return iraw_skb; |
551 | } | 588 | } |
552 | 589 | ||
@@ -555,8 +592,10 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) | |||
555 | * @bcs: B channel descriptor structure. | 592 | * @bcs: B channel descriptor structure. |
556 | * @skb: data to send. | 593 | * @skb: data to send. |
557 | * | 594 | * |
558 | * Called by i4l.c to encode and queue an skb for sending, and start | 595 | * Called by LL to encode and queue an skb for sending, and start |
559 | * transmission if necessary. | 596 | * transmission if necessary. |
597 | * Once the payload data has been transmitted completely, gigaset_skb_sent() | ||
598 | * will be called with the skb's link layer header preserved. | ||
560 | * | 599 | * |
561 | * Return value: | 600 | * Return value: |
562 | * number of bytes accepted for sending (skb->len) if ok, | 601 | * number of bytes accepted for sending (skb->len) if ok, |
@@ -564,24 +603,25 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) | |||
564 | */ | 603 | */ |
565 | int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) | 604 | int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) |
566 | { | 605 | { |
606 | struct cardstate *cs = bcs->cs; | ||
567 | unsigned len = skb->len; | 607 | unsigned len = skb->len; |
568 | unsigned long flags; | 608 | unsigned long flags; |
569 | 609 | ||
570 | if (bcs->proto2 == ISDN_PROTO_L2_HDLC) | 610 | if (bcs->proto2 == L2_HDLC) |
571 | skb = HDLC_Encode(skb, HW_HDR_LEN, 0); | 611 | skb = HDLC_Encode(skb); |
572 | else | 612 | else |
573 | skb = iraw_encode(skb, HW_HDR_LEN, 0); | 613 | skb = iraw_encode(skb); |
574 | if (!skb) { | 614 | if (!skb) { |
575 | dev_err(bcs->cs->dev, | 615 | dev_err(cs->dev, |
576 | "unable to allocate memory for encoding!\n"); | 616 | "unable to allocate memory for encoding!\n"); |
577 | return -ENOMEM; | 617 | return -ENOMEM; |
578 | } | 618 | } |
579 | 619 | ||
580 | skb_queue_tail(&bcs->squeue, skb); | 620 | skb_queue_tail(&bcs->squeue, skb); |
581 | spin_lock_irqsave(&bcs->cs->lock, flags); | 621 | spin_lock_irqsave(&cs->lock, flags); |
582 | if (bcs->cs->connected) | 622 | if (cs->connected) |
583 | tasklet_schedule(&bcs->cs->write_tasklet); | 623 | tasklet_schedule(&cs->write_tasklet); |
584 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | 624 | spin_unlock_irqrestore(&cs->lock, flags); |
585 | 625 | ||
586 | return len; /* ok so far */ | 626 | return len; /* ok so far */ |
587 | } | 627 | } |