* add p cc
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / net / wan / x25_asy.c
blob49d041abc91e5272997e8f1ca057d8719eb78245
1 /*
2 * Things to sort out:
4 * o tbusy handling
5 * o allow users to set the parameters
6 * o sync/async switching ?
8 * Note: This does _not_ implement CCITT X.25 asynchronous framing
9 * recommendations. Its primarily for testing purposes. If you wanted
10 * to do CCITT then in theory all you need is to nick the HDLC async
11 * checksum routines from ppp.c
14 #include <linux/module.h>
16 #include <asm/system.h>
17 #include <asm/uaccess.h>
18 #include <asm/bitops.h>
19 #include <linux/string.h>
20 #include <linux/mm.h>
21 #include <linux/interrupt.h>
22 #include <linux/in.h>
23 #include <linux/tty.h>
24 #include <linux/errno.h>
25 #include <linux/netdevice.h>
26 #include <linux/etherdevice.h>
27 #include <linux/skbuff.h>
28 #include <linux/if_arp.h>
29 #include <linux/x25.h>
30 #include <linux/lapb.h>
31 #include <linux/init.h>
32 #include "x25_asy.h"
34 typedef struct x25_ctrl {
35 char if_name[8]; /* "xasy0\0" .. "xasy99999\0" */
36 struct x25_asy ctrl; /* X.25 things */
37 struct net_device dev; /* the device */
38 } x25_asy_ctrl_t;
40 static x25_asy_ctrl_t **x25_asy_ctrls = NULL;
42 int x25_asy_maxdev = SL_NRUNIT; /* Can be overridden with insmod! */
43 MODULE_PARM(x25_asy_maxdev, "i");
45 static struct tty_ldisc x25_ldisc;
47 static int x25_asy_esc(unsigned char *p, unsigned char *d, int len);
48 static void x25_asy_unesc(struct x25_asy *sl, unsigned char c);
50 /* Find a free X.25 channel, and link in this `tty' line. */
51 static inline struct x25_asy *x25_asy_alloc(void)
53 x25_asy_ctrl_t *slp = NULL;
54 int i;
56 if (x25_asy_ctrls == NULL)
57 return NULL; /* Master array missing ! */
59 for (i = 0; i < x25_asy_maxdev; i++)
61 slp = x25_asy_ctrls[i];
62 /* Not allocated ? */
63 if (slp == NULL)
64 break;
65 /* Not in use ? */
66 if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
67 break;
69 /* SLP is set.. */
71 /* Sorry, too many, all slots in use */
72 if (i >= x25_asy_maxdev)
73 return NULL;
75 /* If no channels are available, allocate one */
76 if (!slp &&
77 (x25_asy_ctrls[i] = (x25_asy_ctrl_t *)kmalloc(sizeof(x25_asy_ctrl_t),
78 GFP_KERNEL)) != NULL) {
79 slp = x25_asy_ctrls[i];
80 memset(slp, 0, sizeof(x25_asy_ctrl_t));
82 /* Initialize channel control data */
83 set_bit(SLF_INUSE, &slp->ctrl.flags);
84 slp->ctrl.tty = NULL;
85 sprintf(slp->if_name, "x25asy%d", i);
86 slp->dev.name = slp->if_name;
87 slp->dev.base_addr = i;
88 slp->dev.priv = (void*)&(slp->ctrl);
89 slp->dev.next = NULL;
90 slp->dev.init = x25_asy_init;
92 if (slp != NULL)
95 /* register device so that it can be ifconfig'ed */
96 /* x25_asy_init() will be called as a side-effect */
97 /* SIDE-EFFECT WARNING: x25_asy_init() CLEARS slp->ctrl ! */
99 if (register_netdev(&(slp->dev)) == 0)
101 /* (Re-)Set the INUSE bit. Very Important! */
102 set_bit(SLF_INUSE, &slp->ctrl.flags);
103 slp->ctrl.dev = &(slp->dev);
104 slp->dev.priv = (void*)&(slp->ctrl);
105 return (&(slp->ctrl));
107 else
109 clear_bit(SLF_INUSE,&(slp->ctrl.flags));
110 printk("x25_asy_alloc() - register_netdev() failure.\n");
113 return NULL;
117 /* Free an X.25 channel. */
119 static inline void x25_asy_free(struct x25_asy *sl)
121 /* Free all X.25 frame buffers. */
122 if (sl->rbuff) {
123 kfree(sl->rbuff);
125 sl->rbuff = NULL;
126 if (sl->xbuff) {
127 kfree(sl->xbuff);
129 sl->xbuff = NULL;
131 if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
132 printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
136 /* MTU has been changed by the IP layer. Unfortunately we are not told
137 about this, but we spot it ourselves and fix things up. We could be
138 in an upcall from the tty driver, or in an ip packet queue. */
140 static void x25_asy_changed_mtu(struct x25_asy *sl)
142 struct net_device *dev = sl->dev;
143 unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
144 int len;
145 unsigned long flags;
147 len = dev->mtu * 2;
149 xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
150 rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
152 if (xbuff == NULL || rbuff == NULL)
154 printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
155 sl->dev->name);
156 dev->mtu = sl->mtu;
157 if (xbuff != NULL)
158 kfree(xbuff);
159 if (rbuff != NULL)
160 kfree(rbuff);
161 return;
164 save_flags(flags);
165 cli();
167 oxbuff = sl->xbuff;
168 sl->xbuff = xbuff;
169 orbuff = sl->rbuff;
170 sl->rbuff = rbuff;
172 if (sl->xleft) {
173 if (sl->xleft <= len) {
174 memcpy(sl->xbuff, sl->xhead, sl->xleft);
175 } else {
176 sl->xleft = 0;
177 sl->tx_dropped++;
180 sl->xhead = sl->xbuff;
182 if (sl->rcount) {
183 if (sl->rcount <= len) {
184 memcpy(sl->rbuff, orbuff, sl->rcount);
185 } else {
186 sl->rcount = 0;
187 sl->rx_over_errors++;
188 set_bit(SLF_ERROR, &sl->flags);
191 sl->mtu = dev->mtu;
193 sl->buffsize = len;
195 restore_flags(flags);
197 if (oxbuff != NULL)
198 kfree(oxbuff);
199 if (orbuff != NULL)
200 kfree(orbuff);
204 /* Set the "sending" flag. This must be atomic, hence the ASM. */
206 static inline void x25_asy_lock(struct x25_asy *sl)
208 if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
209 printk("%s: trying to lock already locked device!\n", sl->dev->name);
213 /* Clear the "sending" flag. This must be atomic, hence the ASM. */
215 static inline void x25_asy_unlock(struct x25_asy *sl)
217 if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
218 printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
221 /* Send one completely decapsulated IP datagram to the IP layer. */
223 static void x25_asy_bump(struct x25_asy *sl)
225 struct sk_buff *skb;
226 int count;
227 int err;
229 count = sl->rcount;
230 sl->rx_bytes+=count;
232 skb = dev_alloc_skb(count+1);
233 if (skb == NULL)
235 printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
236 sl->rx_dropped++;
237 return;
239 skb_push(skb,1); /* LAPB internal control */
240 skb->dev = sl->dev;
241 memcpy(skb_put(skb,count), sl->rbuff, count);
242 skb->mac.raw=skb->data;
243 skb->protocol=htons(ETH_P_X25);
244 if((err=lapb_data_received(sl,skb))!=LAPB_OK)
246 kfree_skb(skb);
247 printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
249 else
251 netif_rx(skb);
252 sl->rx_packets++;
256 /* Encapsulate one IP datagram and stuff into a TTY queue. */
257 static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
259 unsigned char *p;
260 int actual, count;
263 if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */
265 x25_asy_changed_mtu(sl);
268 if (len > sl->mtu)
269 { /* Sigh, shouldn't occur BUT ... */
270 len = sl->mtu;
271 printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
272 sl->tx_dropped++;
273 x25_asy_unlock(sl);
274 return;
277 p = icp;
278 count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len);
280 /* Order of next two lines is *very* important.
281 * When we are sending a little amount of data,
282 * the transfer may be completed inside driver.write()
283 * routine, because it's running with interrupts enabled.
284 * In this case we *never* got WRITE_WAKEUP event,
285 * if we did not request it before write operation.
286 * 14 Oct 1994 Dmitry Gorodchanin.
288 sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
289 actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
290 sl->xleft = count - actual;
291 sl->xhead = sl->xbuff + actual;
292 /* VSV */
293 clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
297 * Called by the driver when there's room for more data. If we have
298 * more packets to send, we send them here.
300 static void x25_asy_write_wakeup(struct tty_struct *tty)
302 int actual;
303 struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
305 /* First make sure we're connected. */
306 if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
307 return;
309 if (sl->xleft <= 0)
311 /* Now serial buffer is almost free & we can start
312 * transmission of another packet */
313 sl->tx_packets++;
314 tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
315 x25_asy_unlock(sl);
316 mark_bh(NET_BH);
317 return;
320 actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);
321 sl->xleft -= actual;
322 sl->xhead += actual;
325 /* Encapsulate an IP datagram and kick it into a TTY queue. */
327 static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
329 struct x25_asy *sl = (struct x25_asy*)(dev->priv);
330 int err;
332 if (!dev->start)
334 printk("%s: xmit call when iface is down\n", dev->name);
335 return 1;
338 switch(skb->data[0])
340 case 0x00:break;
341 case 0x01: /* Connection request .. do nothing */
342 if((err=lapb_connect_request(sl))!=LAPB_OK)
343 printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
344 kfree_skb(skb);
345 return 0;
346 case 0x02: /* Disconnect request .. do nothing - hang up ?? */
347 if((err=lapb_disconnect_request(sl))!=LAPB_OK)
348 printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
349 default:
350 kfree_skb(skb);
351 return 0;
353 skb_pull(skb,1); /* Remove control byte */
355 * If we are busy already- too bad. We ought to be able
356 * to queue things at this point, to allow for a little
357 * frame buffer. Oh well...
358 * -----------------------------------------------------
359 * I hate queues in X.25 driver. May be it's efficient,
360 * but for me latency is more important. ;)
361 * So, no queues !
362 * 14 Oct 1994 Dmitry Gorodchanin.
364 if (dev->tbusy) {
365 /* May be we must check transmitter timeout here ?
366 * 14 Oct 1994 Dmitry Gorodchanin.
368 #ifdef SL_CHECK_TRANSMIT
369 if (jiffies - dev->trans_start < 20 * HZ) {
370 /* 20 sec timeout not reached */
371 return 1;
373 printk("%s: transmit timed out, %s?\n", dev->name,
374 (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
375 "bad line quality" : "driver error");
376 sl->xleft = 0;
377 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
378 x25_asy_unlock(sl);
379 #else
380 return 1;
381 #endif
384 if((err=lapb_data_request(sl,skb))!=LAPB_OK)
386 printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
387 kfree_skb(skb);
388 return 0;
390 return 0;
395 * LAPB interface boilerplate
399 * Called when I frame data arrives. We did the work above - throw it
400 * at the net layer.
403 static void x25_asy_data_indication(void *token, struct sk_buff *skb)
405 netif_rx(skb);
409 * Data has emerged from the LAPB protocol machine. We don't handle
410 * busy cases too well. Its tricky to see how to do this nicely -
411 * perhaps lapb should allow us to bounce this ?
414 static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
416 struct x25_asy *sl=token;
417 if(sl->dev->tbusy)
419 printk(KERN_ERR "x25_asy: tbusy drop\n");
420 kfree_skb(skb);
421 return;
423 /* We were not busy, so we are now... :-) */
424 if (skb != NULL)
426 x25_asy_lock(sl);
427 sl->tx_bytes+=skb->len;
428 x25_asy_encaps(sl, skb->data, skb->len);
429 dev_kfree_skb(skb);
434 * LAPB connection establish/down information.
437 static void x25_asy_connected(void *token, int reason)
439 struct x25_asy *sl = token;
440 struct sk_buff *skb;
441 unsigned char *ptr;
443 if ((skb = dev_alloc_skb(1)) == NULL) {
444 printk(KERN_ERR "lapbeth: out of memory\n");
445 return;
448 ptr = skb_put(skb, 1);
449 *ptr = 0x01;
451 skb->dev = sl->dev;
452 skb->protocol = htons(ETH_P_X25);
453 skb->mac.raw = skb->data;
454 skb->pkt_type = PACKET_HOST;
456 netif_rx(skb);
459 static void x25_asy_disconnected(void *token, int reason)
461 struct x25_asy *sl = token;
462 struct sk_buff *skb;
463 unsigned char *ptr;
465 if ((skb = dev_alloc_skb(1)) == NULL) {
466 printk(KERN_ERR "x25_asy: out of memory\n");
467 return;
470 ptr = skb_put(skb, 1);
471 *ptr = 0x02;
473 skb->dev = sl->dev;
474 skb->protocol = htons(ETH_P_X25);
475 skb->mac.raw = skb->data;
476 skb->pkt_type = PACKET_HOST;
478 netif_rx(skb);
482 /* Open the low-level part of the X.25 channel. Easy! */
484 static int x25_asy_open(struct net_device *dev)
486 struct lapb_register_struct x25_asy_callbacks;
487 struct x25_asy *sl = (struct x25_asy*)(dev->priv);
488 unsigned long len;
489 int err;
491 if (sl->tty == NULL)
492 return -ENODEV;
495 * Allocate the X.25 frame buffers:
497 * rbuff Receive buffer.
498 * xbuff Transmit buffer.
501 len = dev->mtu * 2;
503 sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
504 if (sl->rbuff == NULL) {
505 goto norbuff;
507 sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
508 if (sl->xbuff == NULL) {
509 goto noxbuff;
511 sl->mtu = dev->mtu;
512 sl->buffsize = len;
513 sl->rcount = 0;
514 sl->xleft = 0;
515 sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
517 dev->tbusy = 0;
518 /* dev->flags |= IFF_UP; */
519 dev->start = 1;
522 * Now attach LAPB
525 x25_asy_callbacks.connect_confirmation=x25_asy_connected;
526 x25_asy_callbacks.connect_indication=x25_asy_connected;
527 x25_asy_callbacks.disconnect_confirmation=x25_asy_disconnected;
528 x25_asy_callbacks.disconnect_indication=x25_asy_disconnected;
529 x25_asy_callbacks.data_indication=x25_asy_data_indication;
530 x25_asy_callbacks.data_transmit=x25_asy_data_transmit;
532 if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK)
533 return 0;
535 /* Cleanup */
536 kfree(sl->xbuff);
537 noxbuff:
538 kfree(sl->rbuff);
539 norbuff:
540 return -ENOMEM;
544 /* Close the low-level part of the X.25 channel. Easy! */
545 static int x25_asy_close(struct net_device *dev)
547 struct x25_asy *sl = (struct x25_asy*)(dev->priv);
548 int err;
550 if (sl->tty == NULL)
551 return -EBUSY;
553 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
554 dev->tbusy = 1;
555 dev->start = 0;
556 if((err=lapb_unregister(sl))!=LAPB_OK)
557 printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
559 /* dev->flags &= ~IFF_UP; */
560 return 0;
563 static int x25_asy_receive_room(struct tty_struct *tty)
565 return 65536; /* We can handle an infinite amount of data. :-) */
569 * Handle the 'receiver data ready' interrupt.
570 * This function is called by the 'tty_io' module in the kernel when
571 * a block of X.25 data has been received, which can now be decapsulated
572 * and sent on to some IP layer for further processing.
575 static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
577 struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
579 if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
580 return;
583 * Argh! mtu change time! - costs us the packet part received
584 * at the change
586 if (sl->mtu != sl->dev->mtu) {
588 x25_asy_changed_mtu(sl);
591 /* Read the characters out of the buffer */
592 while (count--) {
593 if (fp && *fp++) {
594 if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
595 sl->rx_errors++;
597 cp++;
598 continue;
600 x25_asy_unesc(sl, *cp++);
605 * Open the high-level part of the X.25 channel.
606 * This function is called by the TTY module when the
607 * X.25 line discipline is called for. Because we are
608 * sure the tty line exists, we only have to link it to
609 * a free X.25 channel...
612 static int x25_asy_open_tty(struct tty_struct *tty)
614 struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
615 int err;
617 /* First make sure we're not already connected. */
618 if (sl && sl->magic == X25_ASY_MAGIC) {
619 return -EEXIST;
622 /* OK. Find a free X.25 channel to use. */
623 if ((sl = x25_asy_alloc()) == NULL) {
624 return -ENFILE;
627 sl->tty = tty;
628 tty->disc_data = sl;
629 if (tty->driver.flush_buffer) {
630 tty->driver.flush_buffer(tty);
632 if (tty->ldisc.flush_buffer) {
633 tty->ldisc.flush_buffer(tty);
636 /* Restore default settings */
637 sl->dev->type = ARPHRD_X25;
639 /* Perform the low-level X.25 async init */
640 if ((err = x25_asy_open(sl->dev)))
641 return err;
643 MOD_INC_USE_COUNT;
645 /* Done. We have linked the TTY line to a channel. */
646 return sl->dev->base_addr;
651 * Close down an X.25 channel.
652 * This means flushing out any pending queues, and then restoring the
653 * TTY line discipline to what it was before it got hooked to X.25
654 * (which usually is TTY again).
656 static void x25_asy_close_tty(struct tty_struct *tty)
658 struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
660 /* First make sure we're connected. */
661 if (!sl || sl->magic != X25_ASY_MAGIC)
662 return;
664 if (sl->dev->flags & IFF_UP)
666 (void) dev_close(sl->dev);
669 tty->disc_data = 0;
670 sl->tty = NULL;
671 x25_asy_free(sl);
672 unregister_netdev(sl->dev);
673 MOD_DEC_USE_COUNT;
677 static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
679 static struct net_device_stats stats;
680 struct x25_asy *sl = (struct x25_asy*)(dev->priv);
682 memset(&stats, 0, sizeof(struct net_device_stats));
684 stats.rx_packets = sl->rx_packets;
685 stats.tx_packets = sl->tx_packets;
686 stats.rx_bytes = sl->rx_bytes;
687 stats.tx_bytes = sl->tx_bytes;
688 stats.rx_dropped = sl->rx_dropped;
689 stats.tx_dropped = sl->tx_dropped;
690 stats.tx_errors = sl->tx_errors;
691 stats.rx_errors = sl->rx_errors;
692 stats.rx_over_errors = sl->rx_over_errors;
693 return (&stats);
697 /************************************************************************
698 * STANDARD X.25 ENCAPSULATION *
699 ************************************************************************/
701 int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
703 unsigned char *ptr = d;
704 unsigned char c;
707 * Send an initial END character to flush out any
708 * data that may have accumulated in the receiver
709 * due to line noise.
712 *ptr++ = X25_END; /* Send 10111110 bit seq */
715 * For each byte in the packet, send the appropriate
716 * character sequence, according to the X.25 protocol.
719 while (len-- > 0)
721 switch(c = *s++)
723 case X25_END:
724 *ptr++ = X25_ESC;
725 *ptr++ = X25_ESCAPE(X25_END);
726 break;
727 case X25_ESC:
728 *ptr++ = X25_ESC;
729 *ptr++ = X25_ESCAPE(X25_ESC);
730 break;
731 default:
732 *ptr++ = c;
733 break;
736 *ptr++ = X25_END;
737 return (ptr - d);
740 static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
743 switch(s)
745 case X25_END:
746 if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
748 x25_asy_bump(sl);
750 clear_bit(SLF_ESCAPE, &sl->flags);
751 sl->rcount = 0;
752 return;
754 case X25_ESC:
755 set_bit(SLF_ESCAPE, &sl->flags);
756 return;
758 case X25_ESCAPE(X25_ESC):
759 case X25_ESCAPE(X25_END):
760 if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
761 s = X25_UNESCAPE(s);
762 break;
764 if (!test_bit(SLF_ERROR, &sl->flags))
766 if (sl->rcount < sl->buffsize)
768 sl->rbuff[sl->rcount++] = s;
769 return;
771 sl->rx_over_errors++;
772 set_bit(SLF_ERROR, &sl->flags);
777 /* Perform I/O control on an active X.25 channel. */
778 static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
780 struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
782 /* First make sure we're connected. */
783 if (!sl || sl->magic != X25_ASY_MAGIC) {
784 return -EINVAL;
787 switch(cmd)
789 case SIOCGIFNAME:
790 if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1))
791 return -EFAULT;
792 return 0;
794 case SIOCSIFHWADDR:
795 return -EINVAL;
797 /* Allow stty to read, but not set, the serial port */
798 case TCGETS:
799 case TCGETA:
800 return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
802 default:
803 return -ENOIOCTLCMD;
807 static int x25_asy_open_dev(struct net_device *dev)
809 struct x25_asy *sl = (struct x25_asy*)(dev->priv);
810 if(sl->tty==NULL)
811 return -ENODEV;
812 return 0;
815 /* Initialize X.25 control device -- register X.25 line discipline */
816 #ifdef MODULE
817 static int x25_asy_init_ctrl_dev(void)
818 #else /* !MODULE */
819 int __init x25_asy_init_ctrl_dev(struct net_device *dummy)
820 #endif /* !MODULE */
822 int status;
824 if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */
826 printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n",
827 x25_asy_maxdev );
828 x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL);
829 if (x25_asy_ctrls == NULL)
831 printk("X25 async: Can't allocate x25_asy_ctrls[] array! Uaargh! (-> No X.25 available)\n");
832 return -ENOMEM;
835 /* Clear the pointer array, we allocate devices when we need them */
836 memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */
838 /* Fill in our line protocol discipline, and register it */
839 memset(&x25_ldisc, 0, sizeof(x25_ldisc));
840 x25_ldisc.magic = TTY_LDISC_MAGIC;
841 x25_ldisc.name = "X.25";
842 x25_ldisc.flags = 0;
843 x25_ldisc.open = x25_asy_open_tty;
844 x25_ldisc.close = x25_asy_close_tty;
845 x25_ldisc.read = NULL;
846 x25_ldisc.write = NULL;
847 x25_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *,
848 unsigned int, unsigned long)) x25_asy_ioctl;
849 x25_ldisc.poll = NULL;
850 x25_ldisc.receive_buf = x25_asy_receive_buf;
851 x25_ldisc.receive_room = x25_asy_receive_room;
852 x25_ldisc.write_wakeup = x25_asy_write_wakeup;
853 if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0) {
854 printk("X.25 async: can't register line discipline (err = %d)\n", status);
857 #ifdef MODULE
858 return status;
859 #else
860 /* Return "not found", so that dev_init() will unlink
861 * the placeholder device entry for us.
863 return ENODEV;
864 #endif
868 /* Initialise the X.25 driver. Called by the device init code */
870 int x25_asy_init(struct net_device *dev)
872 struct x25_asy *sl = (struct x25_asy*)(dev->priv);
874 if (sl == NULL) /* Allocation failed ?? */
875 return -ENODEV;
877 /* Set up the control block. (And clear statistics) */
879 memset(sl, 0, sizeof (struct x25_asy));
880 sl->magic = X25_ASY_MAGIC;
881 sl->dev = dev;
884 * Finish setting up the DEVICE info.
887 dev->mtu = SL_MTU;
888 dev->hard_start_xmit = x25_asy_xmit;
889 dev->open = x25_asy_open_dev;
890 dev->stop = x25_asy_close;
891 dev->get_stats = x25_asy_get_stats;
892 dev->hard_header_len = 0;
893 dev->addr_len = 0;
894 dev->type = ARPHRD_X25;
895 dev->tx_queue_len = 10;
897 dev_init_buffers(dev);
899 /* New-style flags. */
900 dev->flags = IFF_NOARP;
902 return 0;
904 #ifdef MODULE
907 init_module(void)
909 return x25_asy_init_ctrl_dev();
912 void
913 cleanup_module(void)
915 int i;
917 if (x25_asy_ctrls != NULL)
919 for (i = 0; i < x25_asy_maxdev; i++)
921 if (x25_asy_ctrls[i])
924 * VSV = if dev->start==0, then device
925 * unregistered while close proc.
927 if (x25_asy_ctrls[i]->dev.start)
928 unregister_netdev(&(x25_asy_ctrls[i]->dev));
930 kfree(x25_asy_ctrls[i]);
931 x25_asy_ctrls[i] = NULL;
934 kfree(x25_asy_ctrls);
935 x25_asy_ctrls = NULL;
937 if ((i = tty_register_ldisc(N_X25, NULL)))
939 printk("X.25 async: can't unregister line discipline (err = %d)\n", i);
942 #endif /* MODULE */