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