1 /*****************************************************************************/
3 * auerisdn.c -- Auerswald PBX/System Telephone ISDN interface.
5 * Copyright (C) 2002 Wolfgang Mües (wolfgang@iksw-muees.de)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /*****************************************************************************/
23 #include <linux/isdnif.h>
24 #include <linux/netdevice.h>
25 #include <linux/sched.h>
27 #undef DEBUG /* include debug macros until it's done */
28 #include <linux/usb.h>
33 /*-------------------------------------------------------------------*/
34 /* ISDN support defines */
35 #define AUISDN_TEI 64 /* use a constant TEI */
37 /*-------------------------------------------------------------------*/
40 #define dump( desc, adr, len) \
43 printk (KERN_DEBUG); \
45 for (u = 0; u < len; u++) \
46 printk (" %02X", adr[u] & 0xFF); \
50 #define dump( desc, adr, len)
53 /*-------------------------------------------------------------------*/
54 /* Hisax Interface. */
56 /* The interface to hisax is long-lasting because hisax_unregister()
57 don't work well in Linux 2.4.x. So we have to hold each registered
58 hisax interface until driver removal. */
59 static struct auerhisax auerhisax_table[AUER_MAX_DEVICES];
62 /*-------------------------------------------------------------------*/
64 /* Callback to L2 for HISAX */
65 /* This callback can be called from 3 sources:
66 a) from hisax context (answer from a l2l1 function)
67 b) from interrupt context (a D channel paket arrived)
68 c) from kernel daemon context (probe/disconnecting)
70 static void auerisdn_d_l1l2(struct auerisdn *ip, int pr, void *arg)
73 struct auerhisax *ahp;
78 ahp->hisax_d_if.ifc.l1l2(&ahp->hisax_d_if.ifc, pr, arg);
80 dbg("auerisdn_d_l1l2 with ahp == NULL");
81 if (pr == (PH_DATA | INDICATION)) {
82 skb = (struct sk_buff *) arg;
84 skb_pull(skb, skb->len);
85 dev_kfree_skb_any(skb);
92 /* D-Channel sending completion function */
93 static void auerisdn_dcw_complete(struct urb *urb)
95 struct auerbuf *bp = (struct auerbuf *) urb->context;
96 struct auerswald *cp =
97 ((struct auerswald *) ((char *) (bp->list) -
99 long) (&((struct auerswald *) 0)->
102 dbg("auerisdn_dcw_complete with status %d", urb->status);
104 /* reuse the buffer */
105 auerbuf_releasebuf(bp);
107 /* Wake up all processes waiting for a buffer */
108 wake_up(&cp->bufferwait);
112 /* Translate non-ETSI ISDN messages from the device */
113 static void auerisdn_translate_incoming(struct auerswald *cp,
120 /* Translate incomming CONNECT -> CONNECT_ACK */
121 /* Format: 0 1 2 3 4 5 6 7 */
122 /* SAPI TEI TXSEQ RXSEQ PID=08 CREFLEN=01 CREF MSG=7 ...*/
123 /* CREF.7 == 0 -> Incoming Call */
125 /* Check for minimum length */
129 /* Check for a CONNECT, call originated from device */
130 if (((msg[6] & 0x80) == 0) && (msg[7] == 0x07)) {
131 dbg("false CONNECT from device found");
132 /* change into CONNECT_ACK */
135 /* Send a CONNECT_ACK back to the device */
137 /* get a new data buffer */
138 bp = auerbuf_getbuf(&cp->bufctl);
140 warn("no auerbuf free");
144 /* Form a CONNECT ACK */
146 cp->isdn.dchannelservice.id | AUH_DIRECT | AUH_UNSPLIT;
149 bp->bufp[3] = msg[6] | 0x80;
152 /* Set the transfer Parameters */
154 bp->dr->bRequestType = AUT_WREQ;
155 bp->dr->bRequest = AUV_WBLOCK;
156 bp->dr->wValue = cpu_to_le16(0);
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);
166 ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
168 auerisdn_dcw_complete(bp->urbp);
170 dbg("auerisdn_translate: Write OK");
172 /* Check for a DISCONNECT and change to RELEASE */
173 if (msg[7] == 0x45) {
174 dbg("DISCONNECT changed to RELEASE");
181 /* a D-channel paket arrived from the device */
182 static void auerisdn_dispatch_dc(struct auerscon *scp, struct auerbuf *bp)
185 struct auerhisax *ahp;
186 struct auerswald *cp =
187 ((struct auerswald *) ((char *) (scp) -
189 long) (&((struct auerswald *) 0)->isdn.
192 unsigned int l2_index;
194 unsigned char l2_header[10];
197 dump("D-Channel paket arrived:", bp->bufp, bp->len);
198 if (cp->disconnecting)
201 /* add a self-generated L2 message header */
203 l2_header[l2_index++] = 0x02; /* SAPI 0, C/R = 1 */
205 /* Parse the L3 message */
206 sp = bp->bufp + AUH_SIZE;
208 c = *sp++; /* Protocol discriminator */
210 warn("D channel paket is not ETSI");
213 c = *sp++; /* Call Reference length byte */
214 sp += c; /* Skip Call Reference */
216 /* translate charge IEs */
217 /* Format of Auerswald Header:
218 0x32 len=0x0B 0xFF 0xFF 0x73 len=0x07 0x27 */
219 /* Format of IE2_UNIT:
220 0x49 len=0x04 uu1 uu2 uu3 uu4 */
221 /* Translate into: (?? Bytes)
229 0x12 Invoke ID = 0x1234
232 0x01 Length of OPvalue
234 0x30 Universal Constructor Sequence
236 0x30 Universal Constructor Sequence
238 0xA1 Context Specific Constructor Recorded Units List
240 0x30 Universal Constructor Sequence
242 0x02 Universal Primitive Integer
243 0x?? len from IE2_UNIT
244 uu1 Recorded Units List
250 unsigned char *ucp = sp; // pointer to start of msg
251 int l = bp->len; // length until EOP
252 unsigned char alen; // length of auerswald msg
253 l -= (int) (ucp - bp->bufp);
254 // scan for Auerswald Header
255 for (; l >= 9; l--, ucp++) { // 9 = minimal length of auerswald msg
266 // Auerswald Header found. Is it units?
267 dbg("Auerswald msg header found");
269 if (ucp[7] == 0x49) {
271 unsigned char ul = ucp[8] + 1; // length of charge integer
272 unsigned char charge[32];
273 // Copy charge info into new buffer
274 unsigned char *xp = &ucp[8];
276 for (count = 0; count < ul; count++)
277 charge[count] = *xp++;
278 // Erase auerswald msg
281 for (; count; count--, xp++)
285 // make room for new message
288 for (; count; count--, xp--);
291 bp->len += (21 + ul);
314 // Insert charge units
316 for (count = 0; count < ul; count++)
317 *xp++ = charge[count];
318 dump("Rearranged message:", bp->bufp,
322 // we can't handle something else, erase it
323 int count = l - alen;
324 unsigned char *xp = ucp;
325 for (; count; count--, xp++)
329 dump("Shortened message:", bp->bufp,
336 c = *sp; /* Message type */
338 /* SETUP. Use an UI frame */
340 l2_header[l2_index++] = 0xFF; /* TEI 127 */
341 l2_header[l2_index++] = 0x03; /* UI control field */
342 skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index);
346 l2_header[l2_index++] = (AUISDN_TEI << 1) | 0x01; /* TEI byte */
347 skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index + 2);
354 spin_lock_irqsave(&ahp->seq_lock, flags);
355 l2_header[l2_index++] = ahp->txseq; /* transmitt sequence number */
356 l2_header[l2_index++] = ahp->rxseq; /* receive sequence number */
357 ahp->txseq += 2; /* next paket gets next number */
358 spin_unlock_irqrestore(&ahp->seq_lock, flags);
362 err("no memory - skipped");
365 sp = skb_put(skb, bp->len - AUH_SIZE + l2_index);
367 memcpy(sp, l2_header, l2_index);
368 memcpy(sp + l2_index, bp->bufp + AUH_SIZE, bp->len - AUH_SIZE);
369 /* Translate false messages */
370 auerisdn_translate_incoming(cp, sp, bp->len - AUH_SIZE + l2_index);
371 /* Send message to L2 */
372 auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION, skb);
375 /* D-channel is closed because the device is removed */
376 /* This is a no-op because ISDN close is handled different */
377 static void auerisdn_disconnect_dc(struct auerscon *scp)
382 /* confirmation helper function. */
383 static void auerisdn_d_confirmskb(struct auerswald *cp,
388 skb_pull(skb, skb->len);
389 dev_kfree_skb_any(skb);
392 /* confirm the sending of data */
393 dbg("Confirm PH_DATA");
394 auerisdn_d_l1l2(&cp->isdn, PH_DATA | CONFIRM, NULL);
397 /* D-channel transfer function L2->L1 */
398 static void auerisdn_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
400 struct auerhisax *ahp;
405 struct auerswald *cp;
407 unsigned int l2_index;
409 unsigned char l2_header[32];
412 dbg("hisax D-Channel l2l1 called");
414 /* Get reference to auerhisax struct */
416 ahp = hisax_d_if->priv;
419 if (cp && !cp->disconnecting) {
422 case PH_ACTIVATE | REQUEST: /* activation request */
423 dbg("Activation Request");
424 cp->isdn.dc_activated = 1;
425 /* send activation back to layer 2 */
426 auerisdn_d_l1l2(&cp->isdn,
427 PH_ACTIVATE | INDICATION, NULL);
429 case PH_DEACTIVATE | REQUEST: /* deactivation request */
430 dbg("Deactivation Request");
431 cp->isdn.dc_activated = 0;
432 /* send deactivation back to layer 2 */
433 auerisdn_d_l1l2(&cp->isdn,
434 PH_DEACTIVATE | INDICATION, NULL);
436 case PH_DATA | REQUEST: /* Transmit data request */
437 skb = (struct sk_buff *) arg;
441 dump("Data Request:", sp, len);
443 /* Parse the L2 header */
446 c = *sp++; /* SAPI */
447 l2_header[l2_index++] = c;
452 l2_header[l2_index++] = c;
456 c = *sp++; /* Control Field, Byte 1 */
463 spin_lock_irqsave(&ahp->seq_lock, flags);
464 ahp->rxseq = c + 2; /* store new sequence info */
465 spin_unlock_irqrestore(&ahp->seq_lock,
467 sp++; /* skip Control Field, Byte 2 */
469 /* Check for RELEASE command */
470 /* and change to RELEASE_COMPLETE */
475 /* check the frame type */
477 case 0x03: /* UI frame */
479 if (l2_header[0] == 0xFC) {
480 dbg("TEI Managment");
481 l2_header[0] = 0xFE; /* set C/R bit in answer */
482 l2_header[l2_index++] = c; /* Answer is UI frame */
485 c = *sp++; /* Managment ID */
489 l2_header[l2_index++] = c;
490 /* Read Reference Number */
493 l2_header[l2_index++] = *sp++;
497 l2_header[l2_index++] = *sp++;
501 c = *sp++; /* Message Type */
504 case 0x01: /* Identity Request */
505 dbg("Identity Request");
506 l2_header[l2_index++] = 0x02; /* Identity Assign */
507 l2_header[l2_index++] =
512 dbg("Unhandled TEI Managment %X", (int) c);
518 /* else send UI frame out */
520 case 0x01: /* RR frame */
521 case 0x05: /* RNR frame */
525 c = *sp++; /* Control Field, Byte 2 */
528 break; /* P/F = 1 in commands */
529 if (l2_header[0] & 0x02)
530 break; /* C/R = 0 from TE */
531 dbg("Send RR as answer");
532 l2_header[l2_index++] = 0x01; /* send an RR as Answer */
533 spin_lock_irqsave(&ahp->seq_lock, flags);
534 l2_header[l2_index++] = ahp->rxseq | 0x01;
535 spin_unlock_irqrestore(&ahp->seq_lock,
538 case 0x7F: /* SABME */
540 spin_lock_irqsave(&ahp->seq_lock, flags);
543 spin_unlock_irqrestore(&ahp->seq_lock,
545 l2_header[l2_index++] = 0x73; /* UA */
547 case 0x53: /* DISC */
550 l2_header[l2_index++] = 0x73; /* UA */
553 dbg("Unhandled L2 Message %X", (int) c);
559 /* we have to generate a local answer */
560 /* first, confirm old message, free old skb */
561 phd_answer:auerisdn_d_confirmskb(cp,
564 /* allocate a new skbuff */
565 skb = dev_alloc_skb(l2_index);
567 err("no memory for new skb");
570 dump("local answer to L2 is:", l2_header,
572 memcpy(skb_put(skb, l2_index), l2_header,
574 auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION,
578 /* we have to send the L3 message out */
580 goto phd_free; /* no message left */
582 /* get a new data buffer */
583 bp = auerbuf_getbuf(&cp->bufctl);
585 warn("no auerbuf free");
588 /* protect against too big write requests */
589 /* Should not happen */
590 if (len > cp->maxControlLength) {
591 err("too long D-channel paket truncated");
592 len = cp->maxControlLength;
596 memcpy(bp->bufp + AUH_SIZE, sp, len);
598 /* set the header byte */
600 cp->isdn.dchannelservice.
601 id | AUH_DIRECT | AUH_UNSPLIT;
603 /* Set the transfer Parameters */
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);
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);
619 auerchain_submit_urb(&cp->controlchain,
622 auerisdn_dcw_complete(bp->urbp);
624 dbg("auerisdn_dwrite: Write OK");
625 /* confirm message, free skb */
626 phd_free:auerisdn_d_confirmskb(cp,
631 warn("pr %#x\n", pr);
635 /* hisax interface is down */
637 case PH_ACTIVATE | REQUEST: /* activation request */
638 dbg("D channel PH_ACTIVATE | REQUEST with interface down");
639 /* don't answer this request! Endless... */
641 case PH_DEACTIVATE | REQUEST: /* deactivation request */
642 dbg("D channel PH_DEACTIVATE | REQUEST with interface down");
643 hisax_d_if->l1l2(hisax_d_if,
644 PH_DEACTIVATE | INDICATION, NULL);
646 case PH_DATA | REQUEST: /* Transmit data request */
647 dbg("D channel PH_DATA | REQUEST with interface down");
648 skb = (struct sk_buff *) arg;
649 /* free data buffer */
651 skb_pull(skb, skb->len);
652 dev_kfree_skb_any(skb);
654 /* send confirmation back to layer 2 */
655 hisax_d_if->l1l2(hisax_d_if, PH_DATA | CONFIRM,
659 warn("pr %#x\n", pr);
666 /* Completion function for D channel open */
667 static void auerisdn_dcopen_complete(struct urb *urbp)
669 struct auerbuf *bp = (struct auerbuf *) urbp->context;
670 struct auerswald *cp =
671 ((struct auerswald *) ((char *) (bp->list) -
673 long) (&((struct auerswald *) 0)->
675 dbg("auerisdn_dcopen_complete called");
677 auerbuf_releasebuf(bp);
679 /* Wake up all processes waiting for a buffer */
680 wake_up(&cp->bufferwait);
684 /* Open the D-channel once more */
685 static void auerisdn_dcopen(unsigned long data)
687 struct auerswald *cp = (struct auerswald *) data;
691 if (cp->disconnecting)
693 dbg("auerisdn_dcopen running");
695 /* get a buffer for the command */
696 bp = auerbuf_getbuf(&cp->bufctl);
697 /* if no buffer available: can't change the mode */
699 err("auerisdn_dcopen: no data buffer available");
703 /* fill the control message */
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);
714 /* submit the control msg */
715 ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
716 dbg("dcopen submitted");
718 bp->urbp->status = ret;
719 auerisdn_dcopen_complete(bp->urbp);
725 /* Initialize the isdn related items in struct auerswald */
726 void auerisdn_init_dev(struct auerswald *cp)
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);
744 /* Connect to the HISAX interface. Returns 0 if successfull */
745 int auerisdn_probe(struct auerswald *cp)
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);
753 unsigned int first_time;
756 /* First allocate resources, then register hisax interface */
758 /* Allocate RX buffers */
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");
770 /* Read out B-Channel output fifo size */
771 ucp = kmalloc(32, GFP_KERNEL);
773 err("Out of memory");
776 ret = usb_control_msg(cp->usbdev, /* pointer to device */
777 usb_rcvctrlpipe(cp->usbdev, 0), /* pipe to control endpoint */
778 AUV_GETINFO, /* USB message request value */
779 AUT_RREQ, /* USB message request type value */
780 0, /* USB message value */
781 AUDI_OUTFSIZE, /* USB message index value */
782 ucp, /* pointer to the receive buffer */
783 32, /* length of the buffer */
784 HZ * 2); /* time to wait for the message to complete before timing out */
787 err("can't read TX Fifo sizes for B1,B2");
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;
796 for (u = 0; u < AUISDN_BCHANNELS; u++) {
797 dbg("B%d buffer size is %d", u, cp->isdn.bc[u].ofsize);
800 /* get the B channel output INT size */
801 cp->isdn.intbo_endp = AU_IRQENDPBO;
802 ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_OUT | AU_IRQENDPBO);
804 /* Some devices have another endpoint number here ... */
805 cp->isdn.intbo_endp = AU_IRQENDPBO_2;
806 ep = usb_epnum_to_ep_desc(cp->usbdev,
807 USB_DIR_OUT | AU_IRQENDPBO_2);
809 err("can't get B channel OUT endpoint");
813 cp->isdn.outsize = ep->wMaxPacketSize;
814 cp->isdn.outInterval = ep->bInterval;
815 cp->isdn.usbdev = cp->usbdev;
817 /* allocate the urb and data buffer */
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");
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");
834 /* get the B channel input INT size */
835 ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_IN | AU_IRQENDPBI);
837 err("can't get B channel IN endpoint");
840 cp->isdn.insize = ep->wMaxPacketSize;
842 /* allocate the urb and data buffer */
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");
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");
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);
865 cp->isdn.intbi_urbp->status = 0; /* needed! */
866 ret = usb_submit_urb(cp->isdn.intbi_urbp);
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;
874 /* request the D-channel service now */
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;
883 /* Find a free hisax interface */
884 for (u = 0; u < AUER_MAX_DEVICES; u++) {
885 ahp = &auerhisax_table[u];
887 first_time = (u == 0);
891 /* no free interface found */
894 /* we found a free hisax interface */
896 /* Wait until ipppd timeout expired. The reason behind this ugly construct:
897 If we connect to a hisax device without waiting for ipppd we are not able
898 to make a new IP connection. */
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);
908 u = ahp->hisax_registered;
909 ahp->hisax_registered = 1;
912 /* now do the registration */
914 for (u = 0; u < AUISDN_BCHANNELS; u++) {
915 b_if[u] = &ahp->hisax_b_if[u];
918 (&ahp->hisax_d_if, b_if, "auerswald_usb",
920 err("hisax registration failed");
923 ahp->hisax_registered = 0;
926 dbg("hisax interface registered");
929 /* send a D channel L1 activation indication to hisax */
930 auerisdn_d_l1l2(&cp->isdn, PH_ACTIVATE | INDICATION, NULL);
931 cp->isdn.dc_activated = 1;
933 /* do another D channel activation for problematic devices */
934 cp->isdn.dcopen_timer.expires = jiffies + HZ;
936 add_timer(&cp->isdn.dcopen_timer);
941 /* The USB device was disconnected */
942 void auerisdn_disconnect(struct auerswald *cp)
944 struct auerhisax *ahp;
945 DECLARE_WAIT_QUEUE_HEAD(wqh);
949 unsigned int stop_bc;
951 dbg("auerisdn_disconnect called");
953 /* stop a running timer */
954 del_timer_sync(&cp->isdn.dcopen_timer);
956 /* first, stop the B channels */
957 stop_bc = auerisdn_b_disconnect(cp);
959 /* stop the D channels */
960 auerisdn_d_l1l2(&cp->isdn, PH_DEACTIVATE | INDICATION, NULL);
961 cp->isdn.dc_activated = 0;
962 dbg("D-Channel disconnected");
965 sleep_on_timeout(&wqh, HZ / 10);
967 /* Shut the connection to the hisax interface */
970 dbg("closing connection to hisax interface");
973 /* time of last closure */
975 /* if we kill a running connection ... */
976 ahp->last_close = jiffies;
981 /* Now free the memory */
982 if (cp->isdn.intbi_urbp) {
983 ret = usb_unlink_urb(cp->isdn.intbi_urbp);
985 dbg("B in: nonzero int unlink result received: %d",
987 usb_free_urb(cp->isdn.intbi_urbp);
988 cp->isdn.intbi_urbp = NULL;
990 kfree(cp->isdn.intbi_bufp);
991 cp->isdn.intbi_bufp = NULL;
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);
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;
1001 kfree(cp->isdn.intbo_bufp);
1002 cp->isdn.intbo_bufp = NULL;
1004 /* Remove the rx and tx buffers */
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;
1015 spin_unlock_irqrestore(&cp->isdn.bc[u].txskb_lock, flags);
1018 /* Remove the D-channel connection */
1019 auerswald_removeservice(cp, &cp->isdn.dchannelservice);
1023 /*-------------------------------------------------------------------*/
1024 /* Environment for long-lasting hisax interface */
1026 /* Wrapper for hisax B0 channel L2L1 */
1027 static void auerisdn_b0_l2l1_wrapper(struct hisax_if *ifc, int pr,
1030 auerisdn_b_l2l1(ifc, pr, arg, 0);
1033 /* Wrapper for hisax B1 channel L2L1 */
1034 static void auerisdn_b1_l2l1_wrapper(struct hisax_if *ifc, int pr,
1037 auerisdn_b_l2l1(ifc, pr, arg, 1);
1040 /* Init the global variables */
1041 void auerisdn_init(void)
1043 struct auerhisax *ahp;
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;
1059 /* Deinit the global variables */
1060 void auerisdn_cleanup(void)
1062 struct auerhisax *ahp;
1065 /* cleanup last allocated device first */
1066 for (i = AUER_MAX_DEVICES - 1; i >= 0; i--) {
1067 ahp = &auerhisax_table[i];
1069 err("hisax device %d open at cleanup", i);
1071 if (ahp->hisax_registered) {
1072 hisax_unregister(&ahp->hisax_d_if);
1073 dbg("hisax interface %d freed", i);