1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/isdnif.h>
24#include <linux/netdevice.h>
25
26#undef DEBUG
27#include <linux/usb.h>
28
29#include "auerisdn.h"
30#include "auermain.h"
31
32
33
34#define AUISDN_BC_1MS 8
35#define AUISDN_BC_INC 4
36#define AUISDN_BCDATATHRESHOLD 48
37#define AUISDN_TOGGLETIME 6
38
39
40
41#ifdef DEBUG
42#define dump( desc, adr, len) \
43do { \
44 unsigned int u; \
45 printk (KERN_DEBUG); \
46 printk (desc); \
47 for (u = 0; u < len; u++) \
48 printk (" %02X", adr[u] & 0xFF); \
49 printk ("\n"); \
50} while (0)
51#else
52#define dump( desc, adr, len)
53#endif
54
55
56
57
58
59
60
61
62
63void auerisdn_b_l1l2(struct auerisdnbc *bc, int pr, void *arg)
64{
65 struct auerhisax *ahp;
66 struct sk_buff *skb;
67
68
69 ahp = bc->cp->isdn.ahp;
70 if (ahp) {
71 ahp->hisax_b_if[bc->channel].ifc.l1l2(&ahp->
72 hisax_b_if[bc->
73 channel].
74 ifc, pr, arg);
75 } else {
76 dbg("auerisdn_b_l1l2 called without ahp");
77 if (pr == (PH_DATA | INDICATION)) {
78 skb = (struct sk_buff *) arg;
79 if (skb) {
80 skb_pull(skb, skb->len);
81 dev_kfree_skb_any(skb);
82 }
83 }
84 }
85}
86
87
88
89static void auerisdn_bintbo_newdata(struct auerisdn *ip)
90{
91 unsigned long flags;
92 struct urb *urbp = ip->intbo_urbp;
93 struct auerisdnbc *bc = &ip->bc[0];
94 struct sk_buff *skb;
95 unsigned char *ucp;
96 int buf_size;
97 int len;
98 int bytes_sent;
99 int i;
100
101
102
103 if (ip->bc[1].mode != L1_MODE_NULL) {
104
105 if (bc->mode != L1_MODE_NULL) {
106
107 if (ip->intbo_toggletimer) {
108
109 ip->intbo_toggletimer--;
110 i = ip->intbo_index ^ 1;
111 } else {
112
113 i = bc->txfree - ip->bc[1].txfree;
114 if (i < -AUISDN_BCDATATHRESHOLD)
115 i = 1;
116 else if (i > AUISDN_BCDATATHRESHOLD)
117 i = 0;
118 else
119 i = ip->intbo_index ^ 1;
120 if (i == ip->intbo_index)
121 ip->intbo_toggletimer =
122 AUISDN_TOGGLETIME;
123 }
124 bc = &ip->bc[i];
125 ip->intbo_index = i;
126 } else {
127 bc = &ip->bc[1];
128 }
129 }
130 dbg("INTBO: Fill B%d with %d Bytes, %d Bytes free",
131 bc->channel + 1, urbp->transfer_buffer_length - AUH_SIZE,
132 bc->txfree);
133
134
135 ucp = ip->intbo_bufp;
136 *ucp++ = AUH_B1CHANNEL + bc->channel;
137 buf_size = urbp->transfer_buffer_length - AUH_SIZE;
138 len = 0;
139 while (len < buf_size) {
140 spin_lock_irqsave(&bc->txskb_lock, flags);
141 if ((skb = bc->txskb)) {
142
143 if (bc->mode == L1_MODE_TRANS) {
144 bytes_sent = buf_size - len;
145 if (skb->len < bytes_sent)
146 bytes_sent = skb->len;
147 {
148 register unsigned char *src =
149 skb->data;
150 unsigned int count;
151 for (count = 0; count < bytes_sent;
152 count++)
153 *ucp++ =
154 isdnhdlc_bit_rev_tab
155 [*src++];
156 }
157 len += bytes_sent;
158 bc->lastbyte = skb->data[bytes_sent - 1];
159 } else {
160 int bs =
161 isdnhdlc_encode(&bc->outp_hdlc_state,
162 skb->data, skb->len,
163 &bytes_sent,
164 ucp, buf_size - len);
165
166 len += bs;
167 ucp += bs;
168 }
169 skb_pull(skb, bytes_sent);
170
171 if (!skb->len) {
172
173 bc->txskb = NULL;
174 spin_unlock_irqrestore(&bc->txskb_lock,
175 flags);
176 auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,
177 (void *) skb->truesize);
178 dev_kfree_skb_any(skb);
179 continue;
180 }
181 } else {
182 if (bc->mode == L1_MODE_TRANS) {
183 memset(ucp, bc->lastbyte, buf_size - len);
184 ucp += buf_size - len;
185 len = buf_size;
186
187 } else {
188
189 int bs =
190 isdnhdlc_encode(&bc->outp_hdlc_state,
191 NULL, 0, &bytes_sent,
192 ucp, buf_size - len);
193
194 len += bs;
195 ucp += bs;
196 }
197 }
198 spin_unlock_irqrestore(&bc->txskb_lock, flags);
199 }
200
201}
202
203
204
205static void auerisdn_bintbo_complete(struct urb *urbp)
206{
207 struct auerisdn *ip = urbp->context;
208
209
210 if ((urbp->status == -ENOENT) || (urbp->status == -ECONNRESET)) {
211
212 if (ip->intbo_state == INTBOS_CHANGE) {
213 dbg("state => RESTART");
214 ip->intbo_state = INTBOS_RESTART;
215 } else {
216
217 dbg("INTBO stopped");
218 ip->intbo_state = INTBOS_IDLE;
219 }
220
221 return;
222 }
223
224
225 if (urbp->status) {
226 warn("auerisdn_bintbo_complete: status = %d",
227 urbp->status);
228 return;
229 }
230
231
232 if (ip->intbo_state == INTBOS_CHANGE) {
233 dbg("state == INTBOS_CHANGE, no new data");
234 return;
235 }
236
237
238 auerisdn_bintbo_newdata(ip);
239}
240
241
242
243static void auerisdn_bintbo_setup(struct auerisdn *ip, unsigned int len)
244{
245 ip->intbo_state = INTBOS_IDLE;
246 FILL_INT_URB(ip->intbo_urbp, ip->usbdev,
247 usb_sndintpipe(ip->usbdev, ip->intbo_endp),
248 ip->intbo_bufp, len, auerisdn_bintbo_complete, ip,
249 ip->outInterval);
250 ip->intbo_urbp->transfer_flags |= USB_ASYNC_UNLINK;
251 ip->intbo_urbp->status = 0;
252}
253
254
255static void auerisdn_bintbo_restart(struct auerisdn *ip)
256{
257 struct urb *urbp = ip->intbo_urbp;
258 int status;
259
260
261
262
263 auerisdn_bintbo_setup(ip, ip->paketsize + AUH_SIZE);
264
265
266 auerisdn_bintbo_newdata(ip);
267
268
269 ip->intbo_state = INTBOS_RUNNING;
270 status = usb_submit_urb(urbp);
271 if (status < 0) {
272 err("can't submit INT OUT urb, status = %d", status);
273 urbp->status = status;
274 urbp->complete(urbp);
275 }
276}
277
278
279static void auerisdn_bchange(struct auerisdn *ip, unsigned int paketsize)
280{
281
282 dbg("txfree[0] = %d, txfree[1] = %d, old size = %d, new size = %d",
283 ip->bc[0].txfree, ip->bc[1].txfree, ip->paketsize, paketsize);
284 ip->paketsize = paketsize;
285
286 if (paketsize == 0) {
287
288 dbg("stop unlinking INT out urb");
289 ip->intbo_state = INTBOS_IDLE;
290 usb_unlink_urb(ip->intbo_urbp);
291 return;
292 }
293 if (ip->intbo_state != INTBOS_IDLE) {
294
295 ip->intbo_state = INTBOS_CHANGE;
296 usb_unlink_urb(ip->intbo_urbp);
297 } else {
298
299 auerisdn_bintbo_restart(ip);
300 }
301}
302
303
304
305static void auerisdn_bserv(struct auerisdn *ip)
306{
307 struct auerisdnbc *bc;
308 unsigned int u;
309 unsigned int paketsize;
310
311
312 if (ip->intbo_state == INTBOS_RESTART) {
313
314 auerisdn_bintbo_restart(ip);
315 return;
316 }
317
318 if (ip->intbo_state == INTBOS_CHANGE)
319 return;
320
321
322 paketsize = 0;
323 for (u = 0; u < AUISDN_BCHANNELS; u++) {
324 bc = &ip->bc[u];
325 if (bc->mode != L1_MODE_NULL) {
326 unsigned int bpp = AUISDN_BC_1MS * ip->outInterval;
327 if (bc->txfree < bpp) {
328 bc->txsize = bpp - AUISDN_BC_INC;
329 paketsize += bpp - AUISDN_BC_INC;
330 } else if (bc->txfree < bpp * 2) {
331 paketsize += bc->txsize;
332 } else if (bc->txfree < bpp * 4) {
333 bc->txsize = bpp;
334 paketsize += bpp;
335 } else if (bc->txfree > bc->ofsize / 2) {
336 bc->txsize = bpp + AUISDN_BC_INC;
337 paketsize += bpp + AUISDN_BC_INC;
338 } else {
339 paketsize += bc->txsize;
340 }
341 }
342 }
343
344
345 if (paketsize != ip->paketsize)
346 auerisdn_bchange(ip, paketsize);
347}
348
349
350static void auerisdn_bconf(struct auerisdnbc *bc)
351{
352 unsigned long flags;
353 struct sk_buff *skb;
354
355 if (bc->mode == L1_MODE_NULL) {
356 auerisdn_b_l1l2(bc, PH_DEACTIVATE | INDICATION, NULL);
357
358 spin_lock_irqsave(&bc->txskb_lock, flags);
359 skb = bc->txskb;
360 bc->txskb = NULL;
361 spin_unlock_irqrestore(&bc->txskb_lock, flags);
362 if (skb) {
363 skb_pull(skb, skb->len);
364 auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,
365 (void *) skb->truesize);
366 dev_kfree_skb_any(skb);
367 }
368 } else {
369 auerisdn_b_l1l2(bc, PH_ACTIVATE | INDICATION, NULL);
370 }
371}
372
373
374static void auerisdn_bmode_complete(struct urb *urb)
375{
376 struct auerswald *cp;
377 struct auerbuf *bp = (struct auerbuf *) urb->context;
378 struct auerisdnbc *bc;
379 int channel;
380
381 dbg("auerisdn_bmode_complete called");
382 cp = ((struct auerswald *) ((char *) (bp->list) -
383 (unsigned
384 long) (&((struct auerswald *) 0)->
385 bufctl)));
386
387
388 channel = le16_to_cpu(bp->dr->wIndex);
389 channel -= AUH_B1CHANNEL;
390 if (channel < 0)
391 goto rel;
392 if (channel >= AUISDN_BCHANNELS)
393 goto rel;
394 bc = &cp->isdn.bc[channel];
395
396
397 if (urb->status) {
398 err("complete with non-zero status: %d", urb->status);
399 } else {
400 bc->mode = *bp->bufp;
401 }
402
403 auerisdn_bconf(bc);
404
405
406 rel:auerbuf_releasebuf(bp);
407
408
409 wake_up(&cp->bufferwait);
410}
411
412
413static void auerisdn_bmode(struct auerisdnbc *bc, unsigned int mode)
414{
415 struct auerswald *cp = bc->cp;
416 struct auerbuf *bp;
417 int ret;
418
419
420 if (cp->disconnecting) {
421 mode = L1_MODE_NULL;
422
423
424 } else if (bc->mode != mode) {
425 if ((mode != L1_MODE_NULL) && (mode != L1_MODE_TRANS)) {
426
427 dbg("rcv init");
428 isdnhdlc_rcv_init(&bc->inp_hdlc_state, 0);
429
430 dbg("out init");
431 isdnhdlc_out_init(&bc->outp_hdlc_state, 0, 0);
432 }
433
434 if (mode == L1_MODE_NULL)
435 bc->mode = mode;
436 if ((bc->mode == L1_MODE_NULL) || (mode == L1_MODE_NULL)) {
437
438
439
440 bp = auerbuf_getbuf(&cp->bufctl);
441
442 if (!bp) {
443 err("auerisdn_bmode: no data buffer available");
444 return;
445 }
446
447
448 bp->dr->bRequestType = AUT_WREQ;
449 bp->dr->bRequest = AUV_CHANNELCTL;
450 if (mode != L1_MODE_NULL)
451 bp->dr->wValue = cpu_to_le16(1);
452 else
453 bp->dr->wValue = cpu_to_le16(0);
454 bp->dr->wIndex =
455 cpu_to_le16(AUH_B1CHANNEL + bc->channel);
456 bp->dr->wLength = cpu_to_le16(0);
457 *bp->bufp = mode;
458 FILL_CONTROL_URB(bp->urbp, cp->usbdev,
459 usb_sndctrlpipe(cp->usbdev, 0),
460 (unsigned char *) bp->dr,
461 bp->bufp, 0,
462 (usb_complete_t)
463 auerisdn_bmode_complete, bp);
464
465
466 ret =
467 auerchain_submit_urb(&cp->controlchain,
468 bp->urbp);
469 if (ret) {
470 bp->urbp->status = ret;
471 auerisdn_bmode_complete(bp->urbp);
472 }
473 return;
474 }
475 }
476
477 bc->mode = mode;
478
479
480 auerisdn_bconf(bc);
481}
482
483
484void auerisdn_b_l2l1(struct hisax_if *ifc, int pr, void *arg,
485 unsigned int channel)
486{
487 struct auerhisax *ahp;
488 struct auerisdnbc *bc;
489 struct auerswald *cp;
490 struct sk_buff *skb;
491 unsigned long flags;
492 int mode;
493
494 cp = NULL;
495 ahp = (struct auerhisax *) ifc->priv;
496 if (ahp)
497 cp = ahp->cp;
498 if (cp && !cp->disconnecting) {
499
500 bc = &cp->isdn.bc[channel];
501 switch (pr) {
502 case PH_ACTIVATE | REQUEST:
503 mode = (int) arg;
504 dbg("B%d, PH_ACTIVATE_REQUEST Mode = %d",
505 bc->channel + 1, mode);
506 auerisdn_bmode(bc, mode);
507 break;
508 case PH_DEACTIVATE | REQUEST:
509 dbg("B%d, PH_DEACTIVATE_REQUEST", bc->channel + 1);
510 auerisdn_bmode(bc, L1_MODE_NULL);
511 break;
512 case PH_DATA | REQUEST:
513 skb = (struct sk_buff *) arg;
514 spin_lock_irqsave(&bc->txskb_lock, flags);
515 if (bc->txskb) {
516 err("Overflow in B channel TX");
517 skb_pull(skb, skb->len);
518 dev_kfree_skb_any(skb);
519 } else {
520 if (cp->disconnecting
521 || (bc->mode == L1_MODE_NULL)) {
522 skb_pull(skb, skb->len);
523 spin_unlock_irqrestore(&bc->
524 txskb_lock,
525 flags);
526 auerisdn_b_l1l2(bc,
527 PH_DATA | CONFIRM,
528 (void *) skb->
529 truesize);
530 dev_kfree_skb_any(skb);
531 goto next;
532 } else
533 bc->txskb = skb;
534 }
535 spin_unlock_irqrestore(&bc->txskb_lock, flags);
536 next:break;
537 default:
538 warn("pr %#x\n", pr);
539 break;
540 }
541 } else {
542
543 switch (pr) {
544 case PH_ACTIVATE | REQUEST:
545 dbg("B channel: PH_ACTIVATE | REQUEST with interface down");
546
547 break;
548 case PH_DEACTIVATE | REQUEST:
549 dbg("B channel: PH_DEACTIVATE | REQUEST with interface down");
550 ifc->l1l2(ifc, PH_DEACTIVATE | INDICATION, NULL);
551 break;
552 case PH_DATA | REQUEST:
553 dbg("B channel: PH_DATA | REQUEST with interface down");
554 skb = (struct sk_buff *) arg;
555
556 if (skb) {
557 skb_pull(skb, skb->len);
558 dev_kfree_skb_any(skb);
559 }
560
561 ifc->l1l2(ifc, PH_DATA | CONFIRM, NULL);
562 break;
563 default:
564 warn("pr %#x\n", pr);
565 break;
566 }
567 }
568}
569
570
571void auerisdn_intbi_complete(struct urb *urb)
572{
573 unsigned int bytecount;
574 unsigned char *ucp;
575 int channel;
576 unsigned int syncbit;
577 unsigned int syncdata;
578 struct auerisdnbc *bc;
579 struct sk_buff *skb;
580 int count;
581 int status;
582 struct auerswald *cp = (struct auerswald *) urb->context;
583
584 if (urb->status != 0) {
585 dbg("nonzero URB status = %d", urb->status);
586 return;
587 }
588 if (cp->disconnecting)
589 return;
590
591
592 bytecount = urb->actual_length;
593 ucp = cp->isdn.intbi_bufp;
594 if (!bytecount)
595 return;
596 channel = *ucp & AUH_TYPEMASK;
597 syncbit = *ucp & AUH_SYNC;
598 ucp++;
599 bytecount--;
600 channel -= AUH_B1CHANNEL;
601 if (channel < 0)
602 return;
603 if (channel >= AUISDN_BCHANNELS)
604 return;
605 bc = &cp->isdn.bc[channel];
606 if (!bytecount)
607 return;
608
609 bc->txfree = ((255 - *ucp++) * bc->ofsize) / 256;
610
611 bytecount--;
612
613
614 if (syncbit) {
615 if (!bytecount)
616 goto int_tx;
617 syncdata = *ucp++;
618 dbg("Sync data = %d", syncdata);
619 bytecount--;
620 }
621
622 if (!bytecount)
623 goto int_tx;
624
625
626
627 while (bytecount > 0) {
628 if (bc->mode == L1_MODE_NULL) {
629
630 status = 0;
631 bytecount = 0;
632 } else if (bc->mode == L1_MODE_TRANS) {
633 {
634 register unsigned char *dest = bc->rxbuf;
635 status = bytecount;
636 for (; bytecount; bytecount--)
637 *dest++ =
638 isdnhdlc_bit_rev_tab[*ucp++];
639 }
640
641 } else {
642 status = isdnhdlc_decode(&bc->inp_hdlc_state, ucp,
643 bytecount, &count,
644 bc->rxbuf, AUISDN_RXSIZE);
645 ucp += count;
646 bytecount -= count;
647 }
648 if (status > 0) {
649
650 if (!(skb = dev_alloc_skb(status))) {
651 warn("receive out of memory");
652 break;
653 }
654 memcpy(skb_put(skb, status), bc->rxbuf, status);
655
656 auerisdn_b_l1l2(bc, PH_DATA | INDICATION, skb);
657
658 } else if (status == -HDLC_CRC_ERROR) {
659 dbg("CRC error");
660 } else if (status == -HDLC_FRAMING_ERROR) {
661 dbg("framing error");
662 } else if (status == -HDLC_LENGTH_ERROR) {
663 dbg("length error");
664 }
665 }
666
667 int_tx:
668 auerisdn_bserv(&cp->isdn);
669}
670
671
672
673unsigned int auerisdn_b_disconnect(struct auerswald *cp)
674{
675 unsigned int u;
676 struct auerisdnbc *bc;
677 unsigned int result = 0;
678
679
680 for (u = 0; u < AUISDN_BCHANNELS; u++) {
681 bc = &cp->isdn.bc[u];
682 if (bc->mode != L1_MODE_NULL) {
683 auerisdn_bmode(bc, L1_MODE_NULL);
684 result = 1;
685 }
686 }
687
688 return result;
689}
690