diff options
Diffstat (limited to 'drivers/isdn/gigaset/asyncdata.c')
-rw-r--r-- | drivers/isdn/gigaset/asyncdata.c | 573 |
1 files changed, 307 insertions, 266 deletions
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 256fc4809c81..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,288 +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 | int startbytes = numbytes; | 162 | unsigned char *src = inbuf->data + inbuf->head; |
163 | unsigned procbytes = 0; | ||
164 | unsigned char c; | ||
123 | 165 | ||
124 | if (unlikely(inputstate & INS_byte_stuff)) { | 166 | if (inputstate & INS_byte_stuff) { |
167 | if (!numbytes) | ||
168 | return 0; | ||
125 | inputstate &= ~INS_byte_stuff; | 169 | inputstate &= ~INS_byte_stuff; |
126 | goto byte_stuff; | 170 | goto byte_stuff; |
127 | } | 171 | } |
128 | for (;;) { | 172 | |
129 | if (unlikely(c == PPP_ESCAPE)) { | 173 | while (procbytes < numbytes) { |
130 | if (unlikely(!numbytes)) { | 174 | c = *src++; |
131 | 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; | ||
132 | break; | 183 | break; |
133 | } | 184 | } |
134 | c = *src++; | 185 | } |
135 | --numbytes; | 186 | |
136 | if (unlikely(c == DLE_FLAG && | 187 | if (c == PPP_ESCAPE) { |
137 | (cs->dle || | 188 | /* byte stuffing indicator: pull in next byte */ |
138 | inbuf->inputstate & INS_DLE_command))) { | 189 | if (procbytes >= numbytes) { |
139 | inbuf->inputstate |= INS_DLE_char; | 190 | /* end of buffer, save for later processing */ |
140 | inputstate |= INS_byte_stuff; | 191 | inputstate |= INS_byte_stuff; |
141 | break; | 192 | break; |
142 | } | 193 | } |
143 | 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 | } | ||
144 | c ^= PPP_TRANS; | 209 | c ^= PPP_TRANS; |
145 | if (unlikely(!muststuff(c))) | ||
146 | gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); | ||
147 | } else if (unlikely(c == PPP_FLAG)) { | ||
148 | if (unlikely(inputstate & INS_skip_frame)) { | ||
149 | #ifdef CONFIG_GIGASET_DEBUG | 210 | #ifdef CONFIG_GIGASET_DEBUG |
150 | if (!(inputstate & INS_have_data)) { /* 7E 7E */ | 211 | if (!muststuff(c)) |
151 | ++bcs->emptycount; | 212 | gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); |
152 | } else | ||
153 | gig_dbg(DEBUG_HDLC, | ||
154 | "7e----------------------------"); | ||
155 | #endif | ||
156 | |||
157 | /* end of frame */ | ||
158 | gigaset_isdn_rcv_err(bcs); | ||
159 | dev_kfree_skb_any(skb); | ||
160 | } else if (!(inputstate & INS_have_data)) { /* 7E 7E */ | ||
161 | #ifdef CONFIG_GIGASET_DEBUG | ||
162 | ++bcs->emptycount; | ||
163 | #endif | 213 | #endif |
164 | break; | 214 | } else if (c == PPP_FLAG) { |
165 | } else { | 215 | /* end of frame: process content if any */ |
216 | if (inputstate & INS_have_data) { | ||
166 | gig_dbg(DEBUG_HDLC, | 217 | gig_dbg(DEBUG_HDLC, |
167 | "7e----------------------------"); | 218 | "7e----------------------------"); |
168 | 219 | ||
169 | /* end of frame */ | 220 | /* check and pass received frame */ |
170 | if (unlikely(fcs != PPP_GOODFCS)) { | 221 | if (!skb) { |
222 | /* skipped frame */ | ||
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 */ | ||
171 | dev_err(cs->dev, | 233 | dev_err(cs->dev, |
172 | "Checksum failed, %u bytes corrupted!\n", | 234 | "Checksum failed, %u bytes corrupted!\n", |
173 | skb->len); | 235 | skb->len); |
174 | gigaset_isdn_rcv_err(bcs); | 236 | gigaset_isdn_rcv_err(bcs); |
175 | dev_kfree_skb_any(skb); | 237 | dev_kfree_skb_any(skb); |
176 | } else if (likely(skb->len > 2)) { | 238 | } else { |
239 | /* good frame */ | ||
177 | __skb_trim(skb, skb->len - 2); | 240 | __skb_trim(skb, skb->len - 2); |
178 | gigaset_skb_rcvd(bcs, skb); | 241 | gigaset_skb_rcvd(bcs, skb); |
179 | } else { | ||
180 | if (skb->len) { | ||
181 | dev_err(cs->dev, | ||
182 | "invalid packet size (%d)\n", skb->len); | ||
183 | gigaset_isdn_rcv_err(bcs); | ||
184 | } | ||
185 | dev_kfree_skb_any(skb); | ||
186 | } | 242 | } |
187 | } | ||
188 | 243 | ||
189 | fcs = PPP_INITFCS; | 244 | /* prepare reception of next frame */ |
190 | inputstate &= ~(INS_have_data | INS_skip_frame); | 245 | inputstate &= ~INS_have_data; |
191 | if (unlikely(bcs->ignore)) { | 246 | new_rcv_skb(bcs); |
192 | inputstate |= INS_skip_frame; | 247 | skb = bcs->skb; |
193 | skb = NULL; | ||
194 | } else { | 248 | } else { |
195 | skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); | 249 | /* empty frame (7E 7E) */ |
196 | if (skb != NULL) { | 250 | #ifdef CONFIG_GIGASET_DEBUG |
197 | skb_reserve(skb, cs->hw_hdr_len); | 251 | ++bcs->emptycount; |
198 | } else { | 252 | #endif |
199 | dev_warn(cs->dev, | 253 | if (!skb) { |
200 | "could not allocate new skb\n"); | 254 | /* skipped (?) */ |
201 | inputstate |= INS_skip_frame; | 255 | gigaset_isdn_rcv_err(bcs); |
256 | new_rcv_skb(bcs); | ||
257 | skb = bcs->skb; | ||
202 | } | 258 | } |
203 | } | 259 | } |
204 | 260 | ||
205 | break; | 261 | fcs = PPP_INITFCS; |
206 | } else if (unlikely(muststuff(c))) { | 262 | continue; |
263 | #ifdef CONFIG_GIGASET_DEBUG | ||
264 | } else if (muststuff(c)) { | ||
207 | /* Should not happen. Possible after ZDLE=1<CR><LF>. */ | 265 | /* Should not happen. Possible after ZDLE=1<CR><LF>. */ |
208 | gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); | 266 | gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); |
267 | #endif | ||
209 | } | 268 | } |
210 | 269 | ||
211 | /* add character */ | 270 | /* regular data byte, append to skb */ |
212 | |||
213 | #ifdef CONFIG_GIGASET_DEBUG | 271 | #ifdef CONFIG_GIGASET_DEBUG |
214 | if (unlikely(!(inputstate & INS_have_data))) { | 272 | if (!(inputstate & INS_have_data)) { |
215 | gig_dbg(DEBUG_HDLC, "7e (%d x) ================", | 273 | gig_dbg(DEBUG_HDLC, "7e (%d x) ================", |
216 | bcs->emptycount); | 274 | bcs->emptycount); |
217 | bcs->emptycount = 0; | 275 | bcs->emptycount = 0; |
218 | } | 276 | } |
219 | #endif | 277 | #endif |
220 | |||
221 | inputstate |= INS_have_data; | 278 | inputstate |= INS_have_data; |
222 | 279 | if (skb) { | |
223 | if (likely(!(inputstate & INS_skip_frame))) { | 280 | if (skb->len == SBUFSIZE) { |
224 | if (unlikely(skb->len == SBUFSIZE)) { | ||
225 | dev_warn(cs->dev, "received packet too long\n"); | 281 | dev_warn(cs->dev, "received packet too long\n"); |
226 | dev_kfree_skb_any(skb); | 282 | dev_kfree_skb_any(skb); |
227 | skb = NULL; | 283 | /* skip remainder of packet */ |
228 | inputstate |= INS_skip_frame; | 284 | bcs->skb = skb = NULL; |
229 | break; | 285 | } else { |
286 | *__skb_put(skb, 1) = c; | ||
287 | fcs = crc_ccitt_byte(fcs, c); | ||
230 | } | 288 | } |
231 | *__skb_put(skb, 1) = c; | ||
232 | fcs = crc_ccitt_byte(fcs, c); | ||
233 | } | ||
234 | |||
235 | if (unlikely(!numbytes)) | ||
236 | break; | ||
237 | c = *src++; | ||
238 | --numbytes; | ||
239 | if (unlikely(c == DLE_FLAG && | ||
240 | (cs->dle || | ||
241 | inbuf->inputstate & INS_DLE_command))) { | ||
242 | inbuf->inputstate |= INS_DLE_char; | ||
243 | break; | ||
244 | } | 289 | } |
245 | } | 290 | } |
291 | |||
246 | bcs->inputstate = inputstate; | 292 | bcs->inputstate = inputstate; |
247 | bcs->fcs = fcs; | 293 | bcs->fcs = fcs; |
248 | bcs->skb = skb; | 294 | return procbytes; |
249 | return startbytes - numbytes; | ||
250 | } | 295 | } |
251 | 296 | ||
252 | /* 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) | ||
253 | * Invert bytes, undoing byte stuffing and watching for DLE escapes. | 299 | * Invert bytes, undoing byte stuffing and watching for DLE escapes. |
254 | * 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. |
255 | * Return value: | 301 | * Return value: |
256 | * number of processed bytes | 302 | * number of processed bytes |
257 | * numbytes (all bytes processed) on error --FIXME | ||
258 | */ | 303 | */ |
259 | static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, | 304 | static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) |
260 | struct inbuf_t *inbuf) | ||
261 | { | 305 | { |
262 | struct cardstate *cs = inbuf->cs; | 306 | struct cardstate *cs = inbuf->cs; |
263 | struct bc_state *bcs = inbuf->bcs; | 307 | struct bc_state *bcs = cs->bcs; |
264 | int inputstate = bcs->inputstate; | 308 | int inputstate = bcs->inputstate; |
265 | struct sk_buff *skb = bcs->skb; | 309 | struct sk_buff *skb = bcs->skb; |
266 | int startbytes = numbytes; | 310 | unsigned char *src = inbuf->data + inbuf->head; |
311 | unsigned procbytes = 0; | ||
312 | unsigned char c; | ||
267 | 313 | ||
268 | for (;;) { | 314 | if (!skb) { |
269 | /* add character */ | 315 | /* skip this block */ |
270 | inputstate |= INS_have_data; | 316 | new_rcv_skb(bcs); |
317 | return numbytes; | ||
318 | } | ||
271 | 319 | ||
272 | if (likely(!(inputstate & INS_skip_frame))) { | 320 | while (procbytes < numbytes && skb->len < SBUFSIZE) { |
273 | if (unlikely(skb->len == SBUFSIZE)) { | 321 | c = *src++; |
274 | //FIXME just pass skb up and allocate a new one | 322 | procbytes++; |
275 | dev_warn(cs->dev, "received packet too long\n"); | 323 | |
276 | dev_kfree_skb_any(skb); | 324 | if (c == DLE_FLAG) { |
277 | skb = NULL; | 325 | if (inputstate & INS_DLE_char) { |
278 | 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; | ||
279 | break; | 331 | break; |
280 | } | 332 | } |
281 | *__skb_put(skb, 1) = bitrev8(c); | ||
282 | } | 333 | } |
283 | 334 | ||
284 | if (unlikely(!numbytes)) | 335 | /* regular data byte: append to current skb */ |
285 | break; | 336 | inputstate |= INS_have_data; |
286 | c = *src++; | 337 | *__skb_put(skb, 1) = bitrev8(c); |
287 | --numbytes; | ||
288 | if (unlikely(c == DLE_FLAG && | ||
289 | (cs->dle || | ||
290 | inbuf->inputstate & INS_DLE_command))) { | ||
291 | inbuf->inputstate |= INS_DLE_char; | ||
292 | break; | ||
293 | } | ||
294 | } | 338 | } |
295 | 339 | ||
296 | /* pass data up */ | 340 | /* pass data up */ |
297 | if (likely(inputstate & INS_have_data)) { | 341 | if (inputstate & INS_have_data) { |
298 | if (likely(!(inputstate & INS_skip_frame))) { | 342 | gigaset_skb_rcvd(bcs, skb); |
299 | gigaset_skb_rcvd(bcs, skb); | 343 | inputstate &= ~INS_have_data; |
300 | } | 344 | new_rcv_skb(bcs); |
301 | inputstate &= ~(INS_have_data | INS_skip_frame); | 345 | } |
302 | if (unlikely(bcs->ignore)) { | 346 | |
303 | inputstate |= INS_skip_frame; | 347 | bcs->inputstate = inputstate; |
304 | skb = NULL; | 348 | return procbytes; |
305 | } else { | 349 | } |
306 | skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); | 350 | |
307 | if (skb != NULL) { | 351 | /* process DLE escapes |
308 | skb_reserve(skb, cs->hw_hdr_len); | 352 | * Called whenever a DLE sequence might be encountered in the input stream. |
309 | } else { | 353 | * Either processes the entire DLE sequence or, if that isn't possible, |
310 | dev_warn(cs->dev, | 354 | * notes the fact that an initial DLE has been received in the INS_DLE_char |
311 | "could not allocate new skb\n"); | 355 | * inputstate flag and resumes processing of the sequence on the next call. |
312 | inputstate |= INS_skip_frame; | 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; | ||
313 | } | 375 | } |
376 | } else { | ||
377 | /* regular data byte */ | ||
378 | return; | ||
314 | } | 379 | } |
315 | } | 380 | } |
316 | 381 | ||
317 | bcs->inputstate = inputstate; | 382 | /* consume pending DLE */ |
318 | bcs->skb = skb; | 383 | inbuf->inputstate &= ~INS_DLE_char; |
319 | 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 | } | ||
320 | } | 415 | } |
321 | 416 | ||
322 | /** | 417 | /** |
@@ -330,94 +425,39 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, | |||
330 | */ | 425 | */ |
331 | void gigaset_m10x_input(struct inbuf_t *inbuf) | 426 | void gigaset_m10x_input(struct inbuf_t *inbuf) |
332 | { | 427 | { |
333 | struct cardstate *cs; | 428 | struct cardstate *cs = inbuf->cs; |
334 | unsigned tail, head, numbytes; | 429 | unsigned numbytes, procbytes; |
335 | unsigned char *src, c; | ||
336 | int procbytes; | ||
337 | |||
338 | head = inbuf->head; | ||
339 | tail = inbuf->tail; | ||
340 | gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); | ||
341 | |||
342 | if (head != tail) { | ||
343 | cs = inbuf->cs; | ||
344 | src = inbuf->data + head; | ||
345 | numbytes = (head > tail ? RBUFSIZE : tail) - head; | ||
346 | gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); | ||
347 | 430 | ||
348 | while (numbytes) { | 431 | gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", inbuf->head, inbuf->tail); |
349 | if (cs->mstate == MS_LOCKED) { | ||
350 | procbytes = lock_loop(src, numbytes, inbuf); | ||
351 | src += procbytes; | ||
352 | numbytes -= procbytes; | ||
353 | } else { | ||
354 | c = *src++; | ||
355 | --numbytes; | ||
356 | if (c == DLE_FLAG && (cs->dle || | ||
357 | inbuf->inputstate & INS_DLE_command)) { | ||
358 | if (!(inbuf->inputstate & INS_DLE_char)) { | ||
359 | inbuf->inputstate |= INS_DLE_char; | ||
360 | goto nextbyte; | ||
361 | } | ||
362 | /* <DLE> <DLE> => <DLE> in data stream */ | ||
363 | inbuf->inputstate &= ~INS_DLE_char; | ||
364 | } | ||
365 | 432 | ||
366 | if (!(inbuf->inputstate & INS_DLE_char)) { | 433 | while (inbuf->head != inbuf->tail) { |
367 | 434 | /* check for DLE escape */ | |
368 | /* FIXME use function pointers? */ | 435 | handle_dle(inbuf); |
369 | if (inbuf->inputstate & INS_command) | ||
370 | procbytes = cmd_loop(c, src, numbytes, inbuf); | ||
371 | else if (inbuf->bcs->proto2 == L2_HDLC) | ||
372 | procbytes = hdlc_loop(c, src, numbytes, inbuf); | ||
373 | else | ||
374 | procbytes = iraw_loop(c, src, numbytes, inbuf); | ||
375 | |||
376 | src += procbytes; | ||
377 | numbytes -= procbytes; | ||
378 | } else { /* DLE char */ | ||
379 | inbuf->inputstate &= ~INS_DLE_char; | ||
380 | switch (c) { | ||
381 | case 'X': /*begin of command*/ | ||
382 | if (inbuf->inputstate & INS_command) | ||
383 | dev_warn(cs->dev, | ||
384 | "received <DLE> 'X' in command mode\n"); | ||
385 | inbuf->inputstate |= | ||
386 | INS_command | INS_DLE_command; | ||
387 | break; | ||
388 | case '.': /*end of command*/ | ||
389 | if (!(inbuf->inputstate & INS_command)) | ||
390 | dev_warn(cs->dev, | ||
391 | "received <DLE> '.' in hdlc mode\n"); | ||
392 | inbuf->inputstate &= cs->dle ? | ||
393 | ~(INS_DLE_command|INS_command) | ||
394 | : ~INS_DLE_command; | ||
395 | break; | ||
396 | //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */ | ||
397 | default: | ||
398 | dev_err(cs->dev, | ||
399 | "received 0x10 0x%02x!\n", | ||
400 | (int) c); | ||
401 | /* FIXME: reset driver?? */ | ||
402 | } | ||
403 | } | ||
404 | } | ||
405 | nextbyte: | ||
406 | if (!numbytes) { | ||
407 | /* end of buffer, check for wrap */ | ||
408 | if (head > tail) { | ||
409 | head = 0; | ||
410 | src = inbuf->data; | ||
411 | numbytes = tail; | ||
412 | } else { | ||
413 | head = tail; | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | 436 | ||
419 | gig_dbg(DEBUG_INTR, "setting head to %u", head); | 437 | /* process a contiguous block of bytes */ |
420 | 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); | ||
421 | } | 461 | } |
422 | } | 462 | } |
423 | EXPORT_SYMBOL_GPL(gigaset_m10x_input); | 463 | EXPORT_SYMBOL_GPL(gigaset_m10x_input); |
@@ -563,6 +603,7 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb) | |||
563 | */ | 603 | */ |
564 | 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) |
565 | { | 605 | { |
606 | struct cardstate *cs = bcs->cs; | ||
566 | unsigned len = skb->len; | 607 | unsigned len = skb->len; |
567 | unsigned long flags; | 608 | unsigned long flags; |
568 | 609 | ||
@@ -571,16 +612,16 @@ int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) | |||
571 | else | 612 | else |
572 | skb = iraw_encode(skb); | 613 | skb = iraw_encode(skb); |
573 | if (!skb) { | 614 | if (!skb) { |
574 | dev_err(bcs->cs->dev, | 615 | dev_err(cs->dev, |
575 | "unable to allocate memory for encoding!\n"); | 616 | "unable to allocate memory for encoding!\n"); |
576 | return -ENOMEM; | 617 | return -ENOMEM; |
577 | } | 618 | } |
578 | 619 | ||
579 | skb_queue_tail(&bcs->squeue, skb); | 620 | skb_queue_tail(&bcs->squeue, skb); |
580 | spin_lock_irqsave(&bcs->cs->lock, flags); | 621 | spin_lock_irqsave(&cs->lock, flags); |
581 | if (bcs->cs->connected) | 622 | if (cs->connected) |
582 | tasklet_schedule(&bcs->cs->write_tasklet); | 623 | tasklet_schedule(&cs->write_tasklet); |
583 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | 624 | spin_unlock_irqrestore(&cs->lock, flags); |
584 | 625 | ||
585 | return len; /* ok so far */ | 626 | return len; /* ok so far */ |
586 | } | 627 | } |