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#include <linux/sched.h>
26
27#undef DEBUG
28#include <linux/usb.h>
29
30#include "auerisdn.h"
31#include "auermain.h"
32
33
34
35#define AUISDN_TEI 64
36
37
38
39#ifdef DEBUG
40#define dump( desc, adr, len) \
41do { \
42 unsigned int u; \
43 printk (KERN_DEBUG); \
44 printk (desc); \
45 for (u = 0; u < len; u++) \
46 printk (" %02X", adr[u] & 0xFF); \
47 printk ("\n"); \
48} while (0)
49#else
50#define dump( desc, adr, len)
51#endif
52
53
54
55
56
57
58
59static struct auerhisax auerhisax_table[AUER_MAX_DEVICES];
60
61
62
63
64
65
66
67
68
69
70static void auerisdn_d_l1l2(struct auerisdn *ip, int pr, void *arg)
71{
72 struct sk_buff *skb;
73 struct auerhisax *ahp;
74
75
76 ahp = ip->ahp;
77 if (ahp) {
78 ahp->hisax_d_if.ifc.l1l2(&ahp->hisax_d_if.ifc, pr, arg);
79 } else {
80 dbg("auerisdn_d_l1l2 with ahp == NULL");
81 if (pr == (PH_DATA | INDICATION)) {
82 skb = (struct sk_buff *) arg;
83 if (skb) {
84 skb_pull(skb, skb->len);
85 dev_kfree_skb_any(skb);
86 }
87 }
88 }
89}
90
91
92
93static void auerisdn_dcw_complete(struct urb *urb)
94{
95 struct auerbuf *bp = (struct auerbuf *) urb->context;
96 struct auerswald *cp =
97 ((struct auerswald *) ((char *) (bp->list) -
98 (unsigned
99 long) (&((struct auerswald *) 0)->
100 bufctl)));
101
102 dbg("auerisdn_dcw_complete with status %d", urb->status);
103
104
105 auerbuf_releasebuf(bp);
106
107
108 wake_up(&cp->bufferwait);
109}
110
111
112
113static void auerisdn_translate_incoming(struct auerswald *cp,
114 unsigned char *msg,
115 unsigned int len)
116{
117 struct auerbuf *bp;
118 int ret;
119
120
121
122
123
124
125
126 if (len < 8)
127 return;
128
129
130 if (((msg[6] & 0x80) == 0) && (msg[7] == 0x07)) {
131 dbg("false CONNECT from device found");
132
133 msg[7] = 0x0F;
134
135
136
137
138 bp = auerbuf_getbuf(&cp->bufctl);
139 if (!bp) {
140 warn("no auerbuf free");
141 return;
142 }
143
144
145 bp->bufp[0] =
146 cp->isdn.dchannelservice.id | AUH_DIRECT | AUH_UNSPLIT;
147 bp->bufp[1] = 0x08;
148 bp->bufp[2] = 0x01;
149 bp->bufp[3] = msg[6] | 0x80;
150 bp->bufp[4] = 0x0F;
151
152
153 bp->len = 5;
154 bp->dr->bRequestType = AUT_WREQ;
155 bp->dr->bRequest = AUV_WBLOCK;
156 bp->dr->wValue = cpu_to_le16(0);
157 bp->dr->wIndex =
158 cpu_to_le16(cp->isdn.dchannelservice.
159 id | AUH_DIRECT | AUH_UNSPLIT);
160 bp->dr->wLength = cpu_to_le16(5);
161 FILL_CONTROL_URB(bp->urbp, cp->usbdev,
162 usb_sndctrlpipe(cp->usbdev, 0),
163 (unsigned char *) bp->dr, bp->bufp, 5,
164 auerisdn_dcw_complete, bp);
165
166 ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
167 if (ret)
168 auerisdn_dcw_complete(bp->urbp);
169 else
170 dbg("auerisdn_translate: Write OK");
171 }
172
173 if (msg[7] == 0x45) {
174 dbg("DISCONNECT changed to RELEASE");
175 msg[7] = 0x4D;
176 return;
177 }
178}
179
180
181
182static void auerisdn_dispatch_dc(struct auerscon *scp, struct auerbuf *bp)
183{
184 struct sk_buff *skb;
185 struct auerhisax *ahp;
186 struct auerswald *cp =
187 ((struct auerswald *) ((char *) (scp) -
188 (unsigned
189 long) (&((struct auerswald *) 0)->isdn.
190 dchannelservice)));
191 unsigned char *sp;
192 unsigned int l2_index;
193 unsigned char c;
194 unsigned char l2_header[10];
195 unsigned long flags;
196
197 dump("D-Channel paket arrived:", bp->bufp, bp->len);
198 if (cp->disconnecting)
199 return;
200
201
202 l2_index = 0;
203 l2_header[l2_index++] = 0x02;
204
205
206 sp = bp->bufp + AUH_SIZE;
207
208 c = *sp++;
209 if (c != 0x08) {
210 warn("D channel paket is not ETSI");
211 return;
212 }
213 c = *sp++;
214 sp += c;
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 {
250 unsigned char *ucp = sp;
251 int l = bp->len;
252 unsigned char alen;
253 l -= (int) (ucp - bp->bufp);
254
255 for (; l >= 9; l--, ucp++) {
256 if (ucp[0] != 0x32)
257 continue;
258 if (ucp[2] != 0xFF)
259 continue;
260 if (ucp[3] != 0xFF)
261 continue;
262 if (ucp[4] != 0x73)
263 continue;
264 if (ucp[6] != 0x27)
265 continue;
266
267 dbg("Auerswald msg header found");
268 alen = ucp[1] + 2;
269 if (ucp[7] == 0x49) {
270
271 unsigned char ul = ucp[8] + 1;
272 unsigned char charge[32];
273
274 unsigned char *xp = &ucp[8];
275 int count;
276 for (count = 0; count < ul; count++)
277 charge[count] = *xp++;
278
279 count = l - alen;
280 xp = ucp;
281 for (; count; count--, xp++)
282 xp[0] = xp[alen];
283 l -= alen;
284 bp->len -= alen;
285
286 count = l;
287 xp = &ucp[l - 1];
288 for (; count; count--, xp--);
289 xp[21 + ul] = xp[0];
290 l += (21 + ul);
291 bp->len += (21 + ul);
292
293 ucp[0] = 0x1C;
294 ucp[1] = 19 + ul;
295 ucp[2] = 0x91;
296 ucp[3] = 0xA1;
297 ucp[4] = 16 + ul;
298 ucp[5] = 0x02;
299 ucp[6] = 0x02;
300 ucp[7] = 0x12;
301 ucp[8] = 0x34;
302 ucp[9] = 0x02;
303 ucp[10] = 0x01;
304 ucp[11] = 0x24;
305 ucp[12] = 0x30;
306 ucp[13] = 7 + ul;
307 ucp[14] = 0x30;
308 ucp[15] = 5 + ul;
309 ucp[16] = 0xA1;
310 ucp[17] = 3 + ul;
311 ucp[18] = 0x30;
312 ucp[19] = 1 + ul;
313 ucp[20] = 0x02;
314
315 xp = &ucp[21];
316 for (count = 0; count < ul; count++)
317 *xp++ = charge[count];
318 dump("Rearranged message:", bp->bufp,
319 bp->len);
320 break;
321 } else {
322
323 int count = l - alen;
324 unsigned char *xp = ucp;
325 for (; count; count--, xp++)
326 xp[0] = xp[alen];
327 l -= alen;
328 bp->len -= alen;
329 dump("Shortened message:", bp->bufp,
330 bp->len);
331 }
332 }
333 }
334
335
336 c = *sp;
337 if (c == 0x05) {
338
339 dbg("SETUP");
340 l2_header[l2_index++] = 0xFF;
341 l2_header[l2_index++] = 0x03;
342 skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index);
343 } else {
344
345 dbg("I Frame");
346 l2_header[l2_index++] = (AUISDN_TEI << 1) | 0x01;
347 skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index + 2);
348 if (skb) {
349 ahp = cp->isdn.ahp;
350 if (!ahp) {
351 err("ahp == NULL");
352 return;
353 }
354 spin_lock_irqsave(&ahp->seq_lock, flags);
355 l2_header[l2_index++] = ahp->txseq;
356 l2_header[l2_index++] = ahp->rxseq;
357 ahp->txseq += 2;
358 spin_unlock_irqrestore(&ahp->seq_lock, flags);
359 }
360 }
361 if (!skb) {
362 err("no memory - skipped");
363 return;
364 }
365 sp = skb_put(skb, bp->len - AUH_SIZE + l2_index);
366
367 memcpy(sp, l2_header, l2_index);
368 memcpy(sp + l2_index, bp->bufp + AUH_SIZE, bp->len - AUH_SIZE);
369
370 auerisdn_translate_incoming(cp, sp, bp->len - AUH_SIZE + l2_index);
371
372 auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION, skb);
373}
374
375
376
377static void auerisdn_disconnect_dc(struct auerscon *scp)
378{
379}
380
381
382
383static void auerisdn_d_confirmskb(struct auerswald *cp,
384 struct sk_buff *skb)
385{
386
387 if (skb) {
388 skb_pull(skb, skb->len);
389 dev_kfree_skb_any(skb);
390 }
391
392
393 dbg("Confirm PH_DATA");
394 auerisdn_d_l1l2(&cp->isdn, PH_DATA | CONFIRM, NULL);
395}
396
397
398static void auerisdn_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
399{
400 struct auerhisax *ahp;
401 struct sk_buff *skb;
402 unsigned int len;
403 int ret;
404 struct auerbuf *bp;
405 struct auerswald *cp;
406 unsigned long flags;
407 unsigned int l2_index;
408 unsigned char c;
409 unsigned char l2_header[32];
410 unsigned char *sp;
411
412 dbg("hisax D-Channel l2l1 called");
413
414
415 cp = NULL;
416 ahp = hisax_d_if->priv;
417 if (ahp)
418 cp = ahp->cp;
419 if (cp && !cp->disconnecting) {
420
421 switch (pr) {
422 case PH_ACTIVATE | REQUEST:
423 dbg("Activation Request");
424 cp->isdn.dc_activated = 1;
425
426 auerisdn_d_l1l2(&cp->isdn,
427 PH_ACTIVATE | INDICATION, NULL);
428 break;
429 case PH_DEACTIVATE | REQUEST:
430 dbg("Deactivation Request");
431 cp->isdn.dc_activated = 0;
432
433 auerisdn_d_l1l2(&cp->isdn,
434 PH_DEACTIVATE | INDICATION, NULL);
435 break;
436 case PH_DATA | REQUEST:
437 skb = (struct sk_buff *) arg;
438 len = skb->len;
439 l2_index = 0;
440 sp = skb->data;
441 dump("Data Request:", sp, len);
442
443
444 if (!len)
445 goto phd_free;
446 c = *sp++;
447 l2_header[l2_index++] = c;
448 len--;
449 if (!len)
450 goto phd_free;
451 c = *sp++;
452 l2_header[l2_index++] = c;
453 len--;
454 if (!len)
455 goto phd_free;
456 c = *sp++;
457 len--;
458 if (!(c & 0x01)) {
459
460 dbg("I Frame");
461 if (!len)
462 goto phd_free;
463 spin_lock_irqsave(&ahp->seq_lock, flags);
464 ahp->rxseq = c + 2;
465 spin_unlock_irqrestore(&ahp->seq_lock,
466 flags);
467 sp++;
468 len--;
469
470
471 if (sp[3] == 0x4D)
472 sp[3] = 0x5A;
473 goto phd_send;
474 }
475
476 switch (c) {
477 case 0x03:
478 dbg("UI Frame");
479 if (l2_header[0] == 0xFC) {
480 dbg("TEI Managment");
481 l2_header[0] = 0xFE;
482 l2_header[l2_index++] = c;
483 if (!len)
484 break;
485 c = *sp++;
486 len--;
487 if (c != 0x0F)
488 break;
489 l2_header[l2_index++] = c;
490
491 if (!len)
492 break;
493 l2_header[l2_index++] = *sp++;
494 len--;
495 if (!len)
496 break;
497 l2_header[l2_index++] = *sp++;
498 len--;
499 if (!len)
500 break;
501 c = *sp++;
502 len--;
503 switch (c) {
504 case 0x01:
505 dbg("Identity Request");
506 l2_header[l2_index++] = 0x02;
507 l2_header[l2_index++] =
508 (AUISDN_TEI << 1) |
509 0x01;
510 goto phd_answer;
511 default:
512 dbg("Unhandled TEI Managment %X", (int) c);
513 break;
514 }
515
516 goto phd_free;
517 }
518
519 goto phd_send;
520 case 0x01:
521 case 0x05:
522 dbg("RR/RNR Frame");
523 if (!len)
524 break;
525 c = *sp++;
526 len--;
527 if (!(c & 0x01))
528 break;
529 if (l2_header[0] & 0x02)
530 break;
531 dbg("Send RR as answer");
532 l2_header[l2_index++] = 0x01;
533 spin_lock_irqsave(&ahp->seq_lock, flags);
534 l2_header[l2_index++] = ahp->rxseq | 0x01;
535 spin_unlock_irqrestore(&ahp->seq_lock,
536 flags);
537 goto phd_answer;
538 case 0x7F:
539 dbg("SABME");
540 spin_lock_irqsave(&ahp->seq_lock, flags);
541 ahp->txseq = 0;
542 ahp->rxseq = 0;
543 spin_unlock_irqrestore(&ahp->seq_lock,
544 flags);
545 l2_header[l2_index++] = 0x73;
546 goto phd_answer;
547 case 0x53:
548 dbg("DISC");
549
550 l2_header[l2_index++] = 0x73;
551 goto phd_answer;
552 default:
553 dbg("Unhandled L2 Message %X", (int) c);
554 break;
555 }
556
557 goto phd_free;
558
559
560
561 phd_answer:auerisdn_d_confirmskb(cp,
562 skb);
563
564
565 skb = dev_alloc_skb(l2_index);
566 if (!skb) {
567 err("no memory for new skb");
568 break;
569 }
570 dump("local answer to L2 is:", l2_header,
571 l2_index);
572 memcpy(skb_put(skb, l2_index), l2_header,
573 l2_index);
574 auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION,
575 skb);
576 break;
577
578
579 phd_send:if (!len)
580 goto phd_free;
581
582
583 bp = auerbuf_getbuf(&cp->bufctl);
584 if (!bp) {
585 warn("no auerbuf free");
586 goto phd_free;
587 }
588
589
590 if (len > cp->maxControlLength) {
591 err("too long D-channel paket truncated");
592 len = cp->maxControlLength;
593 }
594
595
596 memcpy(bp->bufp + AUH_SIZE, sp, len);
597
598
599 *(bp->bufp) =
600 cp->isdn.dchannelservice.
601 id | AUH_DIRECT | AUH_UNSPLIT;
602
603
604 bp->len = len + AUH_SIZE;
605 bp->dr->bRequestType = AUT_WREQ;
606 bp->dr->bRequest = AUV_WBLOCK;
607 bp->dr->wValue = cpu_to_le16(0);
608 bp->dr->wIndex =
609 cpu_to_le16(cp->isdn.dchannelservice.
610 id | AUH_DIRECT | AUH_UNSPLIT);
611 bp->dr->wLength = cpu_to_le16(len + AUH_SIZE);
612 FILL_CONTROL_URB(bp->urbp, cp->usbdev,
613 usb_sndctrlpipe(cp->usbdev, 0),
614 (unsigned char *) bp->dr,
615 bp->bufp, len + AUH_SIZE,
616 auerisdn_dcw_complete, bp);
617
618 ret =
619 auerchain_submit_urb(&cp->controlchain,
620 bp->urbp);
621 if (ret)
622 auerisdn_dcw_complete(bp->urbp);
623 else
624 dbg("auerisdn_dwrite: Write OK");
625
626 phd_free:auerisdn_d_confirmskb(cp,
627 skb);
628 break;
629
630 default:
631 warn("pr %#x\n", pr);
632 break;
633 }
634 } else {
635
636 switch (pr) {
637 case PH_ACTIVATE | REQUEST:
638 dbg("D channel PH_ACTIVATE | REQUEST with interface down");
639
640 break;
641 case PH_DEACTIVATE | REQUEST:
642 dbg("D channel PH_DEACTIVATE | REQUEST with interface down");
643 hisax_d_if->l1l2(hisax_d_if,
644 PH_DEACTIVATE | INDICATION, NULL);
645 break;
646 case PH_DATA | REQUEST:
647 dbg("D channel PH_DATA | REQUEST with interface down");
648 skb = (struct sk_buff *) arg;
649
650 if (skb) {
651 skb_pull(skb, skb->len);
652 dev_kfree_skb_any(skb);
653 }
654
655 hisax_d_if->l1l2(hisax_d_if, PH_DATA | CONFIRM,
656 NULL);
657 break;
658 default:
659 warn("pr %#x\n", pr);
660 break;
661 }
662 }
663}
664
665
666
667static void auerisdn_dcopen_complete(struct urb *urbp)
668{
669 struct auerbuf *bp = (struct auerbuf *) urbp->context;
670 struct auerswald *cp =
671 ((struct auerswald *) ((char *) (bp->list) -
672 (unsigned
673 long) (&((struct auerswald *) 0)->
674 bufctl)));
675 dbg("auerisdn_dcopen_complete called");
676
677 auerbuf_releasebuf(bp);
678
679
680 wake_up(&cp->bufferwait);
681}
682
683
684
685static void auerisdn_dcopen(unsigned long data)
686{
687 struct auerswald *cp = (struct auerswald *) data;
688 struct auerbuf *bp;
689 int ret;
690
691 if (cp->disconnecting)
692 return;
693 dbg("auerisdn_dcopen running");
694
695
696 bp = auerbuf_getbuf(&cp->bufctl);
697
698 if (!bp) {
699 err("auerisdn_dcopen: no data buffer available");
700 return;
701 }
702
703
704 bp->dr->bRequestType = AUT_WREQ;
705 bp->dr->bRequest = AUV_CHANNELCTL;
706 bp->dr->wValue = cpu_to_le16(1);
707 bp->dr->wIndex = cpu_to_le16(0);
708 bp->dr->wLength = cpu_to_le16(0);
709 FILL_CONTROL_URB(bp->urbp, cp->usbdev,
710 usb_sndctrlpipe(cp->usbdev, 0),
711 (unsigned char *) bp->dr, bp->bufp, 0,
712 (usb_complete_t) auerisdn_dcopen_complete, bp);
713
714
715 ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
716 dbg("dcopen submitted");
717 if (ret) {
718 bp->urbp->status = ret;
719 auerisdn_dcopen_complete(bp->urbp);
720 }
721 return;
722}
723
724
725
726void auerisdn_init_dev(struct auerswald *cp)
727{
728 unsigned int u;
729 cp->isdn.dchannelservice.id = AUH_UNASSIGNED;
730 cp->isdn.dchannelservice.dispatch = auerisdn_dispatch_dc;
731 cp->isdn.dchannelservice.disconnect = auerisdn_disconnect_dc;
732 init_timer(&cp->isdn.dcopen_timer);
733 cp->isdn.dcopen_timer.data = (unsigned long) cp;
734 cp->isdn.dcopen_timer.function = auerisdn_dcopen;
735 for (u = 0; u < AUISDN_BCHANNELS; u++) {
736 cp->isdn.bc[u].cp = cp;
737 cp->isdn.bc[u].mode = L1_MODE_NULL;
738 cp->isdn.bc[u].channel = u;
739 spin_lock_init(&cp->isdn.bc[u].txskb_lock);
740 }
741}
742
743
744
745int auerisdn_probe(struct auerswald *cp)
746{
747 struct hisax_b_if *b_if[AUISDN_BCHANNELS];
748 struct usb_endpoint_descriptor *ep;
749 struct auerhisax *ahp;
750 DECLARE_WAIT_QUEUE_HEAD(wqh);
751 unsigned int u;
752 unsigned char *ucp;
753 unsigned int first_time;
754 int ret;
755
756
757
758
759 for (u = 0; u < AUISDN_BCHANNELS; u++) {
760 if (!cp->isdn.bc[u].rxbuf) {
761 cp->isdn.bc[u].rxbuf =
762 (char *) kmalloc(AUISDN_RXSIZE, GFP_KERNEL);
763 if (!cp->isdn.bc[u].rxbuf) {
764 err("can't allocate buffer for B channel RX data");
765 return -1;
766 }
767 }
768 }
769
770
771 ucp = kmalloc(32, GFP_KERNEL);
772 if (!ucp) {
773 err("Out of memory");
774 return -3;
775 }
776 ret = usb_control_msg(cp->usbdev,
777 usb_rcvctrlpipe(cp->usbdev, 0),
778 AUV_GETINFO,
779 AUT_RREQ,
780 0,
781 AUDI_OUTFSIZE,
782 ucp,
783 32,
784 HZ * 2);
785 if (ret < 4) {
786 kfree(ucp);
787 err("can't read TX Fifo sizes for B1,B2");
788 return -4;
789 }
790 for (u = 0; u < AUISDN_BCHANNELS; u++) {
791 ret = le16_to_cpup(ucp + u * 2);
792 cp->isdn.bc[u].ofsize = ret;
793 cp->isdn.bc[u].txfree = ret;
794 }
795 kfree(ucp);
796 for (u = 0; u < AUISDN_BCHANNELS; u++) {
797 dbg("B%d buffer size is %d", u, cp->isdn.bc[u].ofsize);
798 }
799
800
801 cp->isdn.intbo_endp = AU_IRQENDPBO;
802 ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_OUT | AU_IRQENDPBO);
803 if (!ep) {
804
805 cp->isdn.intbo_endp = AU_IRQENDPBO_2;
806 ep = usb_epnum_to_ep_desc(cp->usbdev,
807 USB_DIR_OUT | AU_IRQENDPBO_2);
808 if (!ep) {
809 err("can't get B channel OUT endpoint");
810 return -5;
811 }
812 }
813 cp->isdn.outsize = ep->wMaxPacketSize;
814 cp->isdn.outInterval = ep->bInterval;
815 cp->isdn.usbdev = cp->usbdev;
816
817
818 if (!cp->isdn.intbo_urbp) {
819 cp->isdn.intbo_urbp = usb_alloc_urb(0);
820 if (!cp->isdn.intbo_urbp) {
821 err("can't allocate urb for B channel output endpoint");
822 return -6;
823 }
824 }
825 if (!cp->isdn.intbo_bufp) {
826 cp->isdn.intbo_bufp =
827 (char *) kmalloc(cp->isdn.outsize, GFP_KERNEL);
828 if (!cp->isdn.intbo_bufp) {
829 err("can't allocate buffer for B channel output endpoint");
830 return -7;
831 }
832 }
833
834
835 ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_IN | AU_IRQENDPBI);
836 if (!ep) {
837 err("can't get B channel IN endpoint");
838 return -8;
839 }
840 cp->isdn.insize = ep->wMaxPacketSize;
841
842
843 if (!cp->isdn.intbi_urbp) {
844 cp->isdn.intbi_urbp = usb_alloc_urb(0);
845 if (!cp->isdn.intbi_urbp) {
846 err("can't allocate urb for B channel input endpoint");
847 return -9;
848 }
849 }
850 if (!cp->isdn.intbi_bufp) {
851 cp->isdn.intbi_bufp =
852 (char *) kmalloc(cp->isdn.insize, GFP_KERNEL);
853 if (!cp->isdn.intbi_bufp) {
854 err("can't allocate buffer for B channel input endpoint");
855 return -10;
856 }
857 }
858
859
860 FILL_INT_URB(cp->isdn.intbi_urbp, cp->usbdev,
861 usb_rcvintpipe(cp->usbdev, AU_IRQENDPBI),
862 cp->isdn.intbi_bufp, cp->isdn.insize,
863 auerisdn_intbi_complete, cp, ep->bInterval);
864
865 cp->isdn.intbi_urbp->status = 0;
866 ret = usb_submit_urb(cp->isdn.intbi_urbp);
867 if (ret < 0) {
868 err("activation of B channel input int failed %d", ret);
869 usb_free_urb(cp->isdn.intbi_urbp);
870 cp->isdn.intbi_urbp = NULL;
871 return -11;
872 }
873
874
875 dbg("Requesting D channel now");
876 cp->isdn.dchannelservice.id = AUH_DCHANNEL;
877 if (auerswald_addservice(cp, &cp->isdn.dchannelservice)) {
878 err("can not open D-channel");
879 cp->isdn.dchannelservice.id = AUH_UNASSIGNED;
880 return -2;
881 }
882
883
884 for (u = 0; u < AUER_MAX_DEVICES; u++) {
885 ahp = &auerhisax_table[u];
886 if (!ahp->cp) {
887 first_time = (u == 0);
888 goto ahp_found;
889 }
890 }
891
892 return -12;
893
894
895 ahp_found:
896
897
898
899 if (ahp->last_close) {
900 unsigned long timeout = jiffies - ahp->last_close;
901 if (timeout < AUISDN_IPTIMEOUT) {
902 info("waiting for ipppd to timeout");
903 sleep_on_timeout(&wqh, AUISDN_IPTIMEOUT - timeout);
904 }
905 }
906
907 cp->isdn.ahp = ahp;
908 u = ahp->hisax_registered;
909 ahp->hisax_registered = 1;
910 ahp->cp = cp;
911
912
913 if (!u) {
914 for (u = 0; u < AUISDN_BCHANNELS; u++) {
915 b_if[u] = &ahp->hisax_b_if[u];
916 }
917 if (hisax_register
918 (&ahp->hisax_d_if, b_if, "auerswald_usb",
919 ISDN_PTYPE_EURO)) {
920 err("hisax registration failed");
921 ahp->cp = NULL;
922 cp->isdn.ahp = NULL;
923 ahp->hisax_registered = 0;
924 return -13;
925 }
926 dbg("hisax interface registered");
927 }
928
929
930 auerisdn_d_l1l2(&cp->isdn, PH_ACTIVATE | INDICATION, NULL);
931 cp->isdn.dc_activated = 1;
932
933
934 cp->isdn.dcopen_timer.expires = jiffies + HZ;
935 dbg("add timer");
936 add_timer(&cp->isdn.dcopen_timer);
937
938 return 0;
939}
940
941
942void auerisdn_disconnect(struct auerswald *cp)
943{
944 struct auerhisax *ahp;
945 DECLARE_WAIT_QUEUE_HEAD(wqh);
946 unsigned long flags;
947 unsigned int u;
948 int ret;
949 unsigned int stop_bc;
950
951 dbg("auerisdn_disconnect called");
952
953
954 del_timer_sync(&cp->isdn.dcopen_timer);
955
956
957 stop_bc = auerisdn_b_disconnect(cp);
958
959
960 auerisdn_d_l1l2(&cp->isdn, PH_DEACTIVATE | INDICATION, NULL);
961 cp->isdn.dc_activated = 0;
962 dbg("D-Channel disconnected");
963
964
965 sleep_on_timeout(&wqh, HZ / 10);
966
967
968 ahp = cp->isdn.ahp;
969 if (ahp) {
970 dbg("closing connection to hisax interface");
971 ahp->cp = NULL;
972 cp->isdn.ahp = NULL;
973
974 if (stop_bc)
975
976 ahp->last_close = jiffies;
977 else
978 ahp->last_close = 0;
979 }
980
981
982 if (cp->isdn.intbi_urbp) {
983 ret = usb_unlink_urb(cp->isdn.intbi_urbp);
984 if (ret)
985 dbg("B in: nonzero int unlink result received: %d",
986 ret);
987 usb_free_urb(cp->isdn.intbi_urbp);
988 cp->isdn.intbi_urbp = NULL;
989 }
990 kfree(cp->isdn.intbi_bufp);
991 cp->isdn.intbi_bufp = NULL;
992
993 if (cp->isdn.intbo_urbp) {
994 cp->isdn.intbo_urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
995 ret = usb_unlink_urb(cp->isdn.intbo_urbp);
996 if (ret)
997 dbg("B out: nonzero int unlink result received: %d", ret);
998 usb_free_urb(cp->isdn.intbo_urbp);
999 cp->isdn.intbo_urbp = NULL;
1000 }
1001 kfree(cp->isdn.intbo_bufp);
1002 cp->isdn.intbo_bufp = NULL;
1003
1004
1005 for (u = 0; u < AUISDN_BCHANNELS; u++) {
1006 kfree(cp->isdn.bc[u].rxbuf);
1007 cp->isdn.bc[u].rxbuf = NULL;
1008 spin_lock_irqsave(&cp->isdn.bc[u].txskb_lock, flags);
1009 if (cp->isdn.bc[u].txskb) {
1010 skb_pull(cp->isdn.bc[u].txskb,
1011 cp->isdn.bc[u].txskb->len);
1012 dev_kfree_skb_any(cp->isdn.bc[u].txskb);
1013 cp->isdn.bc[u].txskb = NULL;
1014 }
1015 spin_unlock_irqrestore(&cp->isdn.bc[u].txskb_lock, flags);
1016 }
1017
1018
1019 auerswald_removeservice(cp, &cp->isdn.dchannelservice);
1020}
1021
1022
1023
1024
1025
1026
1027static void auerisdn_b0_l2l1_wrapper(struct hisax_if *ifc, int pr,
1028 void *arg)
1029{
1030 auerisdn_b_l2l1(ifc, pr, arg, 0);
1031}
1032
1033
1034static void auerisdn_b1_l2l1_wrapper(struct hisax_if *ifc, int pr,
1035 void *arg)
1036{
1037 auerisdn_b_l2l1(ifc, pr, arg, 1);
1038}
1039
1040
1041void auerisdn_init(void)
1042{
1043 struct auerhisax *ahp;
1044 unsigned int u;
1045
1046 memset(&auerhisax_table, 0, sizeof(auerhisax_table));
1047 for (u = 0; u < AUER_MAX_DEVICES; u++) {
1048 ahp = &auerhisax_table[u];
1049 spin_lock_init(&ahp->seq_lock);
1050 ahp->hisax_d_if.ifc.priv = ahp;
1051 ahp->hisax_d_if.ifc.l2l1 = auerisdn_d_l2l1;
1052 ahp->hisax_b_if[0].ifc.priv = ahp;
1053 ahp->hisax_b_if[0].ifc.l2l1 = auerisdn_b0_l2l1_wrapper;
1054 ahp->hisax_b_if[1].ifc.priv = ahp;
1055 ahp->hisax_b_if[1].ifc.l2l1 = auerisdn_b1_l2l1_wrapper;
1056 }
1057}
1058
1059
1060void auerisdn_cleanup(void)
1061{
1062 struct auerhisax *ahp;
1063 int i;
1064
1065
1066 for (i = AUER_MAX_DEVICES - 1; i >= 0; i--) {
1067 ahp = &auerhisax_table[i];
1068 if (ahp->cp) {
1069 err("hisax device %d open at cleanup", i);
1070 }
1071 if (ahp->hisax_registered) {
1072 hisax_unregister(&ahp->hisax_d_if);
1073 dbg("hisax interface %d freed", i);
1074 }
1075 }
1076}
1077