diff options
author | Krzysztof Hałasa <khc@pm.waw.pl> | 2008-07-01 17:40:29 -0400 |
---|---|---|
committer | Krzysztof Hałasa <khc@pm.waw.pl> | 2008-07-23 17:05:55 -0400 |
commit | aca257530f7d681b953961090ad729c32aa5ad62 (patch) | |
tree | d15cf621ce45dfb6a77a1c402301139437fed572 /drivers/net/wan/cosa.c | |
parent | 0bee8db8f63b099412fdbce5b55b01d9f177951d (diff) |
WAN: Port COSA driver to generic HDLC.
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
Diffstat (limited to 'drivers/net/wan/cosa.c')
-rw-r--r-- | drivers/net/wan/cosa.c | 293 |
1 files changed, 128 insertions, 165 deletions
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 5827324e9d9f..e38b7acc52db 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz> | 4 | * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz> |
5 | * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa <khc@pm.waw.pl> | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -54,7 +55,7 @@ | |||
54 | * | 55 | * |
55 | * The Linux driver (unlike the present *BSD drivers :-) can work even | 56 | * The Linux driver (unlike the present *BSD drivers :-) can work even |
56 | * for the COSA and SRP in one computer and allows each channel to work | 57 | * for the COSA and SRP in one computer and allows each channel to work |
57 | * in one of the three modes (character device, Cisco HDLC, Sync PPP). | 58 | * in one of the two modes (character or network device). |
58 | * | 59 | * |
59 | * AUTHOR | 60 | * AUTHOR |
60 | * | 61 | * |
@@ -72,12 +73,6 @@ | |||
72 | * The Comtrol Hostess SV11 driver by Alan Cox | 73 | * The Comtrol Hostess SV11 driver by Alan Cox |
73 | * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox | 74 | * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox |
74 | */ | 75 | */ |
75 | /* | ||
76 | * 5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br> | ||
77 | * fixed a deadlock in cosa_sppp_open | ||
78 | */ | ||
79 | |||
80 | /* ---------- Headers, macros, data structures ---------- */ | ||
81 | 76 | ||
82 | #include <linux/module.h> | 77 | #include <linux/module.h> |
83 | #include <linux/kernel.h> | 78 | #include <linux/kernel.h> |
@@ -86,6 +81,7 @@ | |||
86 | #include <linux/fs.h> | 81 | #include <linux/fs.h> |
87 | #include <linux/interrupt.h> | 82 | #include <linux/interrupt.h> |
88 | #include <linux/delay.h> | 83 | #include <linux/delay.h> |
84 | #include <linux/hdlc.h> | ||
89 | #include <linux/errno.h> | 85 | #include <linux/errno.h> |
90 | #include <linux/ioport.h> | 86 | #include <linux/ioport.h> |
91 | #include <linux/netdevice.h> | 87 | #include <linux/netdevice.h> |
@@ -93,14 +89,12 @@ | |||
93 | #include <linux/mutex.h> | 89 | #include <linux/mutex.h> |
94 | #include <linux/device.h> | 90 | #include <linux/device.h> |
95 | #include <linux/smp_lock.h> | 91 | #include <linux/smp_lock.h> |
96 | |||
97 | #undef COSA_SLOW_IO /* for testing purposes only */ | ||
98 | |||
99 | #include <asm/io.h> | 92 | #include <asm/io.h> |
100 | #include <asm/dma.h> | 93 | #include <asm/dma.h> |
101 | #include <asm/byteorder.h> | 94 | #include <asm/byteorder.h> |
102 | 95 | ||
103 | #include <net/syncppp.h> | 96 | #undef COSA_SLOW_IO /* for testing purposes only */ |
97 | |||
104 | #include "cosa.h" | 98 | #include "cosa.h" |
105 | 99 | ||
106 | /* Maximum length of the identification string. */ | 100 | /* Maximum length of the identification string. */ |
@@ -112,7 +106,6 @@ | |||
112 | /* Per-channel data structure */ | 106 | /* Per-channel data structure */ |
113 | 107 | ||
114 | struct channel_data { | 108 | struct channel_data { |
115 | void *if_ptr; /* General purpose pointer (used by SPPP) */ | ||
116 | int usage; /* Usage count; >0 for chrdev, -1 for netdev */ | 109 | int usage; /* Usage count; >0 for chrdev, -1 for netdev */ |
117 | int num; /* Number of the channel */ | 110 | int num; /* Number of the channel */ |
118 | struct cosa_data *cosa; /* Pointer to the per-card structure */ | 111 | struct cosa_data *cosa; /* Pointer to the per-card structure */ |
@@ -136,10 +129,9 @@ struct channel_data { | |||
136 | wait_queue_head_t txwaitq, rxwaitq; | 129 | wait_queue_head_t txwaitq, rxwaitq; |
137 | int tx_status, rx_status; | 130 | int tx_status, rx_status; |
138 | 131 | ||
139 | /* SPPP/HDLC device parts */ | 132 | /* generic HDLC device parts */ |
140 | struct ppp_device pppdev; | 133 | struct net_device *netdev; |
141 | struct sk_buff *rx_skb, *tx_skb; | 134 | struct sk_buff *rx_skb, *tx_skb; |
142 | struct net_device_stats stats; | ||
143 | }; | 135 | }; |
144 | 136 | ||
145 | /* cosa->firmware_status bits */ | 137 | /* cosa->firmware_status bits */ |
@@ -281,21 +273,19 @@ static int cosa_start_tx(struct channel_data *channel, char *buf, int size); | |||
281 | static void cosa_kick(struct cosa_data *cosa); | 273 | static void cosa_kick(struct cosa_data *cosa); |
282 | static int cosa_dma_able(struct channel_data *chan, char *buf, int data); | 274 | static int cosa_dma_able(struct channel_data *chan, char *buf, int data); |
283 | 275 | ||
284 | /* SPPP/HDLC stuff */ | 276 | /* Network device stuff */ |
285 | static void sppp_channel_init(struct channel_data *chan); | 277 | static int cosa_net_attach(struct net_device *dev, unsigned short encoding, |
286 | static void sppp_channel_delete(struct channel_data *chan); | 278 | unsigned short parity); |
287 | static int cosa_sppp_open(struct net_device *d); | 279 | static int cosa_net_open(struct net_device *d); |
288 | static int cosa_sppp_close(struct net_device *d); | 280 | static int cosa_net_close(struct net_device *d); |
289 | static void cosa_sppp_timeout(struct net_device *d); | 281 | static void cosa_net_timeout(struct net_device *d); |
290 | static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d); | 282 | static int cosa_net_tx(struct sk_buff *skb, struct net_device *d); |
291 | static char *sppp_setup_rx(struct channel_data *channel, int size); | 283 | static char *cosa_net_setup_rx(struct channel_data *channel, int size); |
292 | static int sppp_rx_done(struct channel_data *channel); | 284 | static int cosa_net_rx_done(struct channel_data *channel); |
293 | static int sppp_tx_done(struct channel_data *channel, int size); | 285 | static int cosa_net_tx_done(struct channel_data *channel, int size); |
294 | static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | 286 | static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); |
295 | static struct net_device_stats *cosa_net_stats(struct net_device *dev); | ||
296 | 287 | ||
297 | /* Character device */ | 288 | /* Character device */ |
298 | static void chardev_channel_init(struct channel_data *chan); | ||
299 | static char *chrdev_setup_rx(struct channel_data *channel, int size); | 289 | static char *chrdev_setup_rx(struct channel_data *channel, int size); |
300 | static int chrdev_rx_done(struct channel_data *channel); | 290 | static int chrdev_rx_done(struct channel_data *channel); |
301 | static int chrdev_tx_done(struct channel_data *channel, int size); | 291 | static int chrdev_tx_done(struct channel_data *channel, int size); |
@@ -357,17 +347,17 @@ static void debug_status_in(struct cosa_data *cosa, int status); | |||
357 | static void debug_status_out(struct cosa_data *cosa, int status); | 347 | static void debug_status_out(struct cosa_data *cosa, int status); |
358 | #endif | 348 | #endif |
359 | 349 | ||
360 | 350 | static inline struct channel_data* dev_to_chan(struct net_device *dev) | |
351 | { | ||
352 | return (struct channel_data *)dev_to_hdlc(dev)->priv; | ||
353 | } | ||
354 | |||
361 | /* ---------- Initialization stuff ---------- */ | 355 | /* ---------- Initialization stuff ---------- */ |
362 | 356 | ||
363 | static int __init cosa_init(void) | 357 | static int __init cosa_init(void) |
364 | { | 358 | { |
365 | int i, err = 0; | 359 | int i, err = 0; |
366 | 360 | ||
367 | printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n"); | ||
368 | #ifdef CONFIG_SMP | ||
369 | printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); | ||
370 | #endif | ||
371 | if (cosa_major > 0) { | 361 | if (cosa_major > 0) { |
372 | if (register_chrdev(cosa_major, "cosa", &cosa_fops)) { | 362 | if (register_chrdev(cosa_major, "cosa", &cosa_fops)) { |
373 | printk(KERN_WARNING "cosa: unable to get major %d\n", | 363 | printk(KERN_WARNING "cosa: unable to get major %d\n", |
@@ -402,7 +392,7 @@ static int __init cosa_init(void) | |||
402 | } | 392 | } |
403 | err = 0; | 393 | err = 0; |
404 | goto out; | 394 | goto out; |
405 | 395 | ||
406 | out_chrdev: | 396 | out_chrdev: |
407 | unregister_chrdev(cosa_major, "cosa"); | 397 | unregister_chrdev(cosa_major, "cosa"); |
408 | out: | 398 | out: |
@@ -414,43 +404,29 @@ static void __exit cosa_exit(void) | |||
414 | { | 404 | { |
415 | struct cosa_data *cosa; | 405 | struct cosa_data *cosa; |
416 | int i; | 406 | int i; |
417 | printk(KERN_INFO "Unloading the cosa module\n"); | ||
418 | 407 | ||
419 | for (i=0; i<nr_cards; i++) | 408 | for (i = 0; i < nr_cards; i++) |
420 | device_destroy(cosa_class, MKDEV(cosa_major, i)); | 409 | device_destroy(cosa_class, MKDEV(cosa_major, i)); |
421 | class_destroy(cosa_class); | 410 | class_destroy(cosa_class); |
422 | for (cosa=cosa_cards; nr_cards--; cosa++) { | 411 | |
412 | for (cosa = cosa_cards; nr_cards--; cosa++) { | ||
423 | /* Clean up the per-channel data */ | 413 | /* Clean up the per-channel data */ |
424 | for (i=0; i<cosa->nchannels; i++) { | 414 | for (i = 0; i < cosa->nchannels; i++) { |
425 | /* Chardev driver has no alloc'd per-channel data */ | 415 | /* Chardev driver has no alloc'd per-channel data */ |
426 | sppp_channel_delete(cosa->chan+i); | 416 | unregister_hdlc_device(cosa->chan[i].netdev); |
417 | free_netdev(cosa->chan[i].netdev); | ||
427 | } | 418 | } |
428 | /* Clean up the per-card data */ | 419 | /* Clean up the per-card data */ |
429 | kfree(cosa->chan); | 420 | kfree(cosa->chan); |
430 | kfree(cosa->bouncebuf); | 421 | kfree(cosa->bouncebuf); |
431 | free_irq(cosa->irq, cosa); | 422 | free_irq(cosa->irq, cosa); |
432 | free_dma(cosa->dma); | 423 | free_dma(cosa->dma); |
433 | release_region(cosa->datareg,is_8bit(cosa)?2:4); | 424 | release_region(cosa->datareg, is_8bit(cosa) ? 2 : 4); |
434 | } | 425 | } |
435 | unregister_chrdev(cosa_major, "cosa"); | 426 | unregister_chrdev(cosa_major, "cosa"); |
436 | } | 427 | } |
437 | module_exit(cosa_exit); | 428 | module_exit(cosa_exit); |
438 | 429 | ||
439 | /* | ||
440 | * This function should register all the net devices needed for the | ||
441 | * single channel. | ||
442 | */ | ||
443 | static __inline__ void channel_init(struct channel_data *chan) | ||
444 | { | ||
445 | sprintf(chan->name, "cosa%dc%d", chan->cosa->num, chan->num); | ||
446 | |||
447 | /* Initialize the chardev data structures */ | ||
448 | chardev_channel_init(chan); | ||
449 | |||
450 | /* Register the sppp interface */ | ||
451 | sppp_channel_init(chan); | ||
452 | } | ||
453 | |||
454 | static int cosa_probe(int base, int irq, int dma) | 430 | static int cosa_probe(int base, int irq, int dma) |
455 | { | 431 | { |
456 | struct cosa_data *cosa = cosa_cards+nr_cards; | 432 | struct cosa_data *cosa = cosa_cards+nr_cards; |
@@ -576,13 +552,43 @@ static int cosa_probe(int base, int irq, int dma) | |||
576 | /* Initialize the per-channel data */ | 552 | /* Initialize the per-channel data */ |
577 | cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL); | 553 | cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL); |
578 | if (!cosa->chan) { | 554 | if (!cosa->chan) { |
579 | err = -ENOMEM; | 555 | err = -ENOMEM; |
580 | goto err_out3; | 556 | goto err_out3; |
581 | } | 557 | } |
582 | for (i=0; i<cosa->nchannels; i++) { | 558 | |
583 | cosa->chan[i].cosa = cosa; | 559 | for (i = 0; i < cosa->nchannels; i++) { |
584 | cosa->chan[i].num = i; | 560 | struct channel_data *chan = &cosa->chan[i]; |
585 | channel_init(cosa->chan+i); | 561 | |
562 | chan->cosa = cosa; | ||
563 | chan->num = i; | ||
564 | sprintf(chan->name, "cosa%dc%d", chan->cosa->num, i); | ||
565 | |||
566 | /* Initialize the chardev data structures */ | ||
567 | mutex_init(&chan->rlock); | ||
568 | init_MUTEX(&chan->wsem); | ||
569 | |||
570 | /* Register the network interface */ | ||
571 | if (!(chan->netdev = alloc_hdlcdev(chan))) { | ||
572 | printk(KERN_WARNING "%s: alloc_hdlcdev failed.\n", | ||
573 | chan->name); | ||
574 | goto err_hdlcdev; | ||
575 | } | ||
576 | dev_to_hdlc(chan->netdev)->attach = cosa_net_attach; | ||
577 | dev_to_hdlc(chan->netdev)->xmit = cosa_net_tx; | ||
578 | chan->netdev->open = cosa_net_open; | ||
579 | chan->netdev->stop = cosa_net_close; | ||
580 | chan->netdev->do_ioctl = cosa_net_ioctl; | ||
581 | chan->netdev->tx_timeout = cosa_net_timeout; | ||
582 | chan->netdev->watchdog_timeo = TX_TIMEOUT; | ||
583 | chan->netdev->base_addr = chan->cosa->datareg; | ||
584 | chan->netdev->irq = chan->cosa->irq; | ||
585 | chan->netdev->dma = chan->cosa->dma; | ||
586 | if (register_hdlc_device(chan->netdev)) { | ||
587 | printk(KERN_WARNING "%s: register_hdlc_device()" | ||
588 | " failed.\n", chan->netdev->name); | ||
589 | free_netdev(chan->netdev); | ||
590 | goto err_hdlcdev; | ||
591 | } | ||
586 | } | 592 | } |
587 | 593 | ||
588 | printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n", | 594 | printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n", |
@@ -590,13 +596,20 @@ static int cosa_probe(int base, int irq, int dma) | |||
590 | cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels); | 596 | cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels); |
591 | 597 | ||
592 | return nr_cards++; | 598 | return nr_cards++; |
599 | |||
600 | err_hdlcdev: | ||
601 | while (i-- > 0) { | ||
602 | unregister_hdlc_device(cosa->chan[i].netdev); | ||
603 | free_netdev(cosa->chan[i].netdev); | ||
604 | } | ||
605 | kfree(cosa->chan); | ||
593 | err_out3: | 606 | err_out3: |
594 | kfree(cosa->bouncebuf); | 607 | kfree(cosa->bouncebuf); |
595 | err_out2: | 608 | err_out2: |
596 | free_dma(cosa->dma); | 609 | free_dma(cosa->dma); |
597 | err_out1: | 610 | err_out1: |
598 | free_irq(cosa->irq, cosa); | 611 | free_irq(cosa->irq, cosa); |
599 | err_out: | 612 | err_out: |
600 | release_region(cosa->datareg,is_8bit(cosa)?2:4); | 613 | release_region(cosa->datareg,is_8bit(cosa)?2:4); |
601 | printk(KERN_NOTICE "cosa%d: allocating resources failed\n", | 614 | printk(KERN_NOTICE "cosa%d: allocating resources failed\n", |
602 | cosa->num); | 615 | cosa->num); |
@@ -604,54 +617,19 @@ err_out: | |||
604 | } | 617 | } |
605 | 618 | ||
606 | 619 | ||
607 | /*---------- SPPP/HDLC netdevice ---------- */ | 620 | /*---------- network device ---------- */ |
608 | 621 | ||
609 | static void cosa_setup(struct net_device *d) | 622 | static int cosa_net_attach(struct net_device *dev, unsigned short encoding, |
623 | unsigned short parity) | ||
610 | { | 624 | { |
611 | d->open = cosa_sppp_open; | 625 | if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT) |
612 | d->stop = cosa_sppp_close; | 626 | return 0; |
613 | d->hard_start_xmit = cosa_sppp_tx; | 627 | return -EINVAL; |
614 | d->do_ioctl = cosa_sppp_ioctl; | ||
615 | d->get_stats = cosa_net_stats; | ||
616 | d->tx_timeout = cosa_sppp_timeout; | ||
617 | d->watchdog_timeo = TX_TIMEOUT; | ||
618 | } | ||
619 | |||
620 | static void sppp_channel_init(struct channel_data *chan) | ||
621 | { | ||
622 | struct net_device *d; | ||
623 | chan->if_ptr = &chan->pppdev; | ||
624 | d = alloc_netdev(0, chan->name, cosa_setup); | ||
625 | if (!d) { | ||
626 | printk(KERN_WARNING "%s: alloc_netdev failed.\n", chan->name); | ||
627 | return; | ||
628 | } | ||
629 | chan->pppdev.dev = d; | ||
630 | d->base_addr = chan->cosa->datareg; | ||
631 | d->irq = chan->cosa->irq; | ||
632 | d->dma = chan->cosa->dma; | ||
633 | d->ml_priv = chan; | ||
634 | sppp_attach(&chan->pppdev); | ||
635 | if (register_netdev(d)) { | ||
636 | printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); | ||
637 | sppp_detach(d); | ||
638 | free_netdev(d); | ||
639 | chan->pppdev.dev = NULL; | ||
640 | return; | ||
641 | } | ||
642 | } | ||
643 | |||
644 | static void sppp_channel_delete(struct channel_data *chan) | ||
645 | { | ||
646 | unregister_netdev(chan->pppdev.dev); | ||
647 | sppp_detach(chan->pppdev.dev); | ||
648 | free_netdev(chan->pppdev.dev); | ||
649 | chan->pppdev.dev = NULL; | ||
650 | } | 628 | } |
651 | 629 | ||
652 | static int cosa_sppp_open(struct net_device *d) | 630 | static int cosa_net_open(struct net_device *dev) |
653 | { | 631 | { |
654 | struct channel_data *chan = d->ml_priv; | 632 | struct channel_data *chan = dev_to_chan(dev); |
655 | int err; | 633 | int err; |
656 | unsigned long flags; | 634 | unsigned long flags; |
657 | 635 | ||
@@ -662,36 +640,35 @@ static int cosa_sppp_open(struct net_device *d) | |||
662 | } | 640 | } |
663 | spin_lock_irqsave(&chan->cosa->lock, flags); | 641 | spin_lock_irqsave(&chan->cosa->lock, flags); |
664 | if (chan->usage != 0) { | 642 | if (chan->usage != 0) { |
665 | printk(KERN_WARNING "%s: sppp_open called with usage count %d\n", | 643 | printk(KERN_WARNING "%s: cosa_net_open called with usage count" |
666 | chan->name, chan->usage); | 644 | " %d\n", chan->name, chan->usage); |
667 | spin_unlock_irqrestore(&chan->cosa->lock, flags); | 645 | spin_unlock_irqrestore(&chan->cosa->lock, flags); |
668 | return -EBUSY; | 646 | return -EBUSY; |
669 | } | 647 | } |
670 | chan->setup_rx = sppp_setup_rx; | 648 | chan->setup_rx = cosa_net_setup_rx; |
671 | chan->tx_done = sppp_tx_done; | 649 | chan->tx_done = cosa_net_tx_done; |
672 | chan->rx_done = sppp_rx_done; | 650 | chan->rx_done = cosa_net_rx_done; |
673 | chan->usage=-1; | 651 | chan->usage = -1; |
674 | chan->cosa->usage++; | 652 | chan->cosa->usage++; |
675 | spin_unlock_irqrestore(&chan->cosa->lock, flags); | 653 | spin_unlock_irqrestore(&chan->cosa->lock, flags); |
676 | 654 | ||
677 | err = sppp_open(d); | 655 | err = hdlc_open(dev); |
678 | if (err) { | 656 | if (err) { |
679 | spin_lock_irqsave(&chan->cosa->lock, flags); | 657 | spin_lock_irqsave(&chan->cosa->lock, flags); |
680 | chan->usage=0; | 658 | chan->usage = 0; |
681 | chan->cosa->usage--; | 659 | chan->cosa->usage--; |
682 | |||
683 | spin_unlock_irqrestore(&chan->cosa->lock, flags); | 660 | spin_unlock_irqrestore(&chan->cosa->lock, flags); |
684 | return err; | 661 | return err; |
685 | } | 662 | } |
686 | 663 | ||
687 | netif_start_queue(d); | 664 | netif_start_queue(dev); |
688 | cosa_enable_rx(chan); | 665 | cosa_enable_rx(chan); |
689 | return 0; | 666 | return 0; |
690 | } | 667 | } |
691 | 668 | ||
692 | static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) | 669 | static int cosa_net_tx(struct sk_buff *skb, struct net_device *dev) |
693 | { | 670 | { |
694 | struct channel_data *chan = dev->ml_priv; | 671 | struct channel_data *chan = dev_to_chan(dev); |
695 | 672 | ||
696 | netif_stop_queue(dev); | 673 | netif_stop_queue(dev); |
697 | 674 | ||
@@ -700,16 +677,16 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) | |||
700 | return 0; | 677 | return 0; |
701 | } | 678 | } |
702 | 679 | ||
703 | static void cosa_sppp_timeout(struct net_device *dev) | 680 | static void cosa_net_timeout(struct net_device *dev) |
704 | { | 681 | { |
705 | struct channel_data *chan = dev->ml_priv; | 682 | struct channel_data *chan = dev_to_chan(dev); |
706 | 683 | ||
707 | if (test_bit(RXBIT, &chan->cosa->rxtx)) { | 684 | if (test_bit(RXBIT, &chan->cosa->rxtx)) { |
708 | chan->stats.rx_errors++; | 685 | chan->netdev->stats.rx_errors++; |
709 | chan->stats.rx_missed_errors++; | 686 | chan->netdev->stats.rx_missed_errors++; |
710 | } else { | 687 | } else { |
711 | chan->stats.tx_errors++; | 688 | chan->netdev->stats.tx_errors++; |
712 | chan->stats.tx_aborted_errors++; | 689 | chan->netdev->stats.tx_aborted_errors++; |
713 | } | 690 | } |
714 | cosa_kick(chan->cosa); | 691 | cosa_kick(chan->cosa); |
715 | if (chan->tx_skb) { | 692 | if (chan->tx_skb) { |
@@ -719,13 +696,13 @@ static void cosa_sppp_timeout(struct net_device *dev) | |||
719 | netif_wake_queue(dev); | 696 | netif_wake_queue(dev); |
720 | } | 697 | } |
721 | 698 | ||
722 | static int cosa_sppp_close(struct net_device *d) | 699 | static int cosa_net_close(struct net_device *dev) |
723 | { | 700 | { |
724 | struct channel_data *chan = d->ml_priv; | 701 | struct channel_data *chan = dev_to_chan(dev); |
725 | unsigned long flags; | 702 | unsigned long flags; |
726 | 703 | ||
727 | netif_stop_queue(d); | 704 | netif_stop_queue(dev); |
728 | sppp_close(d); | 705 | hdlc_close(dev); |
729 | cosa_disable_rx(chan); | 706 | cosa_disable_rx(chan); |
730 | spin_lock_irqsave(&chan->cosa->lock, flags); | 707 | spin_lock_irqsave(&chan->cosa->lock, flags); |
731 | if (chan->rx_skb) { | 708 | if (chan->rx_skb) { |
@@ -736,13 +713,13 @@ static int cosa_sppp_close(struct net_device *d) | |||
736 | kfree_skb(chan->tx_skb); | 713 | kfree_skb(chan->tx_skb); |
737 | chan->tx_skb = NULL; | 714 | chan->tx_skb = NULL; |
738 | } | 715 | } |
739 | chan->usage=0; | 716 | chan->usage = 0; |
740 | chan->cosa->usage--; | 717 | chan->cosa->usage--; |
741 | spin_unlock_irqrestore(&chan->cosa->lock, flags); | 718 | spin_unlock_irqrestore(&chan->cosa->lock, flags); |
742 | return 0; | 719 | return 0; |
743 | } | 720 | } |
744 | 721 | ||
745 | static char *sppp_setup_rx(struct channel_data *chan, int size) | 722 | static char *cosa_net_setup_rx(struct channel_data *chan, int size) |
746 | { | 723 | { |
747 | /* | 724 | /* |
748 | * We can safely fall back to non-dma-able memory, because we have | 725 | * We can safely fall back to non-dma-able memory, because we have |
@@ -754,66 +731,53 @@ static char *sppp_setup_rx(struct channel_data *chan, int size) | |||
754 | if (chan->rx_skb == NULL) { | 731 | if (chan->rx_skb == NULL) { |
755 | printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n", | 732 | printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n", |
756 | chan->name); | 733 | chan->name); |
757 | chan->stats.rx_dropped++; | 734 | chan->netdev->stats.rx_dropped++; |
758 | return NULL; | 735 | return NULL; |
759 | } | 736 | } |
760 | chan->pppdev.dev->trans_start = jiffies; | 737 | chan->netdev->trans_start = jiffies; |
761 | return skb_put(chan->rx_skb, size); | 738 | return skb_put(chan->rx_skb, size); |
762 | } | 739 | } |
763 | 740 | ||
764 | static int sppp_rx_done(struct channel_data *chan) | 741 | static int cosa_net_rx_done(struct channel_data *chan) |
765 | { | 742 | { |
766 | if (!chan->rx_skb) { | 743 | if (!chan->rx_skb) { |
767 | printk(KERN_WARNING "%s: rx_done with empty skb!\n", | 744 | printk(KERN_WARNING "%s: rx_done with empty skb!\n", |
768 | chan->name); | 745 | chan->name); |
769 | chan->stats.rx_errors++; | 746 | chan->netdev->stats.rx_errors++; |
770 | chan->stats.rx_frame_errors++; | 747 | chan->netdev->stats.rx_frame_errors++; |
771 | return 0; | 748 | return 0; |
772 | } | 749 | } |
773 | chan->rx_skb->protocol = htons(ETH_P_WAN_PPP); | 750 | chan->rx_skb->protocol = hdlc_type_trans(chan->rx_skb, chan->netdev); |
774 | chan->rx_skb->dev = chan->pppdev.dev; | 751 | chan->rx_skb->dev = chan->netdev; |
775 | skb_reset_mac_header(chan->rx_skb); | 752 | skb_reset_mac_header(chan->rx_skb); |
776 | chan->stats.rx_packets++; | 753 | chan->netdev->stats.rx_packets++; |
777 | chan->stats.rx_bytes += chan->cosa->rxsize; | 754 | chan->netdev->stats.rx_bytes += chan->cosa->rxsize; |
778 | netif_rx(chan->rx_skb); | 755 | netif_rx(chan->rx_skb); |
779 | chan->rx_skb = NULL; | 756 | chan->rx_skb = NULL; |
780 | chan->pppdev.dev->last_rx = jiffies; | 757 | chan->netdev->last_rx = jiffies; |
781 | return 0; | 758 | return 0; |
782 | } | 759 | } |
783 | 760 | ||
784 | /* ARGSUSED */ | 761 | /* ARGSUSED */ |
785 | static int sppp_tx_done(struct channel_data *chan, int size) | 762 | static int cosa_net_tx_done(struct channel_data *chan, int size) |
786 | { | 763 | { |
787 | if (!chan->tx_skb) { | 764 | if (!chan->tx_skb) { |
788 | printk(KERN_WARNING "%s: tx_done with empty skb!\n", | 765 | printk(KERN_WARNING "%s: tx_done with empty skb!\n", |
789 | chan->name); | 766 | chan->name); |
790 | chan->stats.tx_errors++; | 767 | chan->netdev->stats.tx_errors++; |
791 | chan->stats.tx_aborted_errors++; | 768 | chan->netdev->stats.tx_aborted_errors++; |
792 | return 1; | 769 | return 1; |
793 | } | 770 | } |
794 | dev_kfree_skb_irq(chan->tx_skb); | 771 | dev_kfree_skb_irq(chan->tx_skb); |
795 | chan->tx_skb = NULL; | 772 | chan->tx_skb = NULL; |
796 | chan->stats.tx_packets++; | 773 | chan->netdev->stats.tx_packets++; |
797 | chan->stats.tx_bytes += size; | 774 | chan->netdev->stats.tx_bytes += size; |
798 | netif_wake_queue(chan->pppdev.dev); | 775 | netif_wake_queue(chan->netdev); |
799 | return 1; | 776 | return 1; |
800 | } | 777 | } |
801 | 778 | ||
802 | static struct net_device_stats *cosa_net_stats(struct net_device *dev) | ||
803 | { | ||
804 | struct channel_data *chan = dev->ml_priv; | ||
805 | return &chan->stats; | ||
806 | } | ||
807 | |||
808 | |||
809 | /*---------- Character device ---------- */ | 779 | /*---------- Character device ---------- */ |
810 | 780 | ||
811 | static void chardev_channel_init(struct channel_data *chan) | ||
812 | { | ||
813 | mutex_init(&chan->rlock); | ||
814 | init_MUTEX(&chan->wsem); | ||
815 | } | ||
816 | |||
817 | static ssize_t cosa_read(struct file *file, | 781 | static ssize_t cosa_read(struct file *file, |
818 | char __user *buf, size_t count, loff_t *ppos) | 782 | char __user *buf, size_t count, loff_t *ppos) |
819 | { | 783 | { |
@@ -1223,16 +1187,15 @@ static int cosa_ioctl_common(struct cosa_data *cosa, | |||
1223 | return -ENOIOCTLCMD; | 1187 | return -ENOIOCTLCMD; |
1224 | } | 1188 | } |
1225 | 1189 | ||
1226 | static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, | 1190 | static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
1227 | int cmd) | ||
1228 | { | 1191 | { |
1229 | int rv; | 1192 | int rv; |
1230 | struct channel_data *chan = dev->ml_priv; | 1193 | struct channel_data *chan = dev_to_chan(dev); |
1231 | rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data); | 1194 | rv = cosa_ioctl_common(chan->cosa, chan, cmd, |
1232 | if (rv == -ENOIOCTLCMD) { | 1195 | (unsigned long)ifr->ifr_data); |
1233 | return sppp_do_ioctl(dev, ifr, cmd); | 1196 | if (rv != -ENOIOCTLCMD) |
1234 | } | 1197 | return rv; |
1235 | return rv; | 1198 | return hdlc_ioctl(dev, ifr, cmd); |
1236 | } | 1199 | } |
1237 | 1200 | ||
1238 | static int cosa_chardev_ioctl(struct inode *inode, struct file *file, | 1201 | static int cosa_chardev_ioctl(struct inode *inode, struct file *file, |