WAN: Port COSA driver to generic HDLC.
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
This commit is contained in:
Родитель
0bee8db8f6
Коммит
aca257530f
|
@ -37,7 +37,7 @@ config HOSTESS_SV11
|
||||||
# The COSA/SRP driver has not been tested as non-modular yet.
|
# The COSA/SRP driver has not been tested as non-modular yet.
|
||||||
config COSA
|
config COSA
|
||||||
tristate "COSA/SRP sync serial boards support"
|
tristate "COSA/SRP sync serial boards support"
|
||||||
depends on ISA && m && ISA_DMA_API
|
depends on ISA && m && ISA_DMA_API && HDLC
|
||||||
---help---
|
---help---
|
||||||
Driver for COSA and SRP synchronous serial boards.
|
Driver for COSA and SRP synchronous serial boards.
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ pc300-objs := $(pc300-y)
|
||||||
|
|
||||||
obj-$(CONFIG_HOSTESS_SV11) += z85230.o syncppp.o hostess_sv11.o
|
obj-$(CONFIG_HOSTESS_SV11) += z85230.o syncppp.o hostess_sv11.o
|
||||||
obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o
|
obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o
|
||||||
obj-$(CONFIG_COSA) += syncppp.o cosa.o
|
obj-$(CONFIG_COSA) += cosa.o
|
||||||
obj-$(CONFIG_FARSYNC) += farsync.o
|
obj-$(CONFIG_FARSYNC) += farsync.o
|
||||||
obj-$(CONFIG_DSCC4) += dscc4.o
|
obj-$(CONFIG_DSCC4) += dscc4.o
|
||||||
obj-$(CONFIG_LANMEDIA) += syncppp.o
|
obj-$(CONFIG_LANMEDIA) += syncppp.o
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
|
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
|
||||||
|
* Generic HDLC port Copyright (C) 2008 Krzysztof Halasa <khc@pm.waw.pl>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -54,7 +55,7 @@
|
||||||
*
|
*
|
||||||
* The Linux driver (unlike the present *BSD drivers :-) can work even
|
* The Linux driver (unlike the present *BSD drivers :-) can work even
|
||||||
* for the COSA and SRP in one computer and allows each channel to work
|
* for the COSA and SRP in one computer and allows each channel to work
|
||||||
* in one of the three modes (character device, Cisco HDLC, Sync PPP).
|
* in one of the two modes (character or network device).
|
||||||
*
|
*
|
||||||
* AUTHOR
|
* AUTHOR
|
||||||
*
|
*
|
||||||
|
@ -72,12 +73,6 @@
|
||||||
* The Comtrol Hostess SV11 driver by Alan Cox
|
* The Comtrol Hostess SV11 driver by Alan Cox
|
||||||
* The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox
|
* The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* 5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
|
|
||||||
* fixed a deadlock in cosa_sppp_open
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ---------- Headers, macros, data structures ---------- */
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -86,6 +81,7 @@
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/hdlc.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
@ -93,14 +89,12 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
|
|
||||||
#undef COSA_SLOW_IO /* for testing purposes only */
|
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/dma.h>
|
#include <asm/dma.h>
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
|
||||||
#include <net/syncppp.h>
|
#undef COSA_SLOW_IO /* for testing purposes only */
|
||||||
|
|
||||||
#include "cosa.h"
|
#include "cosa.h"
|
||||||
|
|
||||||
/* Maximum length of the identification string. */
|
/* Maximum length of the identification string. */
|
||||||
|
@ -112,7 +106,6 @@
|
||||||
/* Per-channel data structure */
|
/* Per-channel data structure */
|
||||||
|
|
||||||
struct channel_data {
|
struct channel_data {
|
||||||
void *if_ptr; /* General purpose pointer (used by SPPP) */
|
|
||||||
int usage; /* Usage count; >0 for chrdev, -1 for netdev */
|
int usage; /* Usage count; >0 for chrdev, -1 for netdev */
|
||||||
int num; /* Number of the channel */
|
int num; /* Number of the channel */
|
||||||
struct cosa_data *cosa; /* Pointer to the per-card structure */
|
struct cosa_data *cosa; /* Pointer to the per-card structure */
|
||||||
|
@ -136,10 +129,9 @@ struct channel_data {
|
||||||
wait_queue_head_t txwaitq, rxwaitq;
|
wait_queue_head_t txwaitq, rxwaitq;
|
||||||
int tx_status, rx_status;
|
int tx_status, rx_status;
|
||||||
|
|
||||||
/* SPPP/HDLC device parts */
|
/* generic HDLC device parts */
|
||||||
struct ppp_device pppdev;
|
struct net_device *netdev;
|
||||||
struct sk_buff *rx_skb, *tx_skb;
|
struct sk_buff *rx_skb, *tx_skb;
|
||||||
struct net_device_stats stats;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* cosa->firmware_status bits */
|
/* cosa->firmware_status bits */
|
||||||
|
@ -281,21 +273,19 @@ static int cosa_start_tx(struct channel_data *channel, char *buf, int size);
|
||||||
static void cosa_kick(struct cosa_data *cosa);
|
static void cosa_kick(struct cosa_data *cosa);
|
||||||
static int cosa_dma_able(struct channel_data *chan, char *buf, int data);
|
static int cosa_dma_able(struct channel_data *chan, char *buf, int data);
|
||||||
|
|
||||||
/* SPPP/HDLC stuff */
|
/* Network device stuff */
|
||||||
static void sppp_channel_init(struct channel_data *chan);
|
static int cosa_net_attach(struct net_device *dev, unsigned short encoding,
|
||||||
static void sppp_channel_delete(struct channel_data *chan);
|
unsigned short parity);
|
||||||
static int cosa_sppp_open(struct net_device *d);
|
static int cosa_net_open(struct net_device *d);
|
||||||
static int cosa_sppp_close(struct net_device *d);
|
static int cosa_net_close(struct net_device *d);
|
||||||
static void cosa_sppp_timeout(struct net_device *d);
|
static void cosa_net_timeout(struct net_device *d);
|
||||||
static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d);
|
static int cosa_net_tx(struct sk_buff *skb, struct net_device *d);
|
||||||
static char *sppp_setup_rx(struct channel_data *channel, int size);
|
static char *cosa_net_setup_rx(struct channel_data *channel, int size);
|
||||||
static int sppp_rx_done(struct channel_data *channel);
|
static int cosa_net_rx_done(struct channel_data *channel);
|
||||||
static int sppp_tx_done(struct channel_data *channel, int size);
|
static int cosa_net_tx_done(struct channel_data *channel, int size);
|
||||||
static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||||
static struct net_device_stats *cosa_net_stats(struct net_device *dev);
|
|
||||||
|
|
||||||
/* Character device */
|
/* Character device */
|
||||||
static void chardev_channel_init(struct channel_data *chan);
|
|
||||||
static char *chrdev_setup_rx(struct channel_data *channel, int size);
|
static char *chrdev_setup_rx(struct channel_data *channel, int size);
|
||||||
static int chrdev_rx_done(struct channel_data *channel);
|
static int chrdev_rx_done(struct channel_data *channel);
|
||||||
static int chrdev_tx_done(struct channel_data *channel, int size);
|
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);
|
||||||
static void debug_status_out(struct cosa_data *cosa, int status);
|
static void debug_status_out(struct cosa_data *cosa, int status);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline struct channel_data* dev_to_chan(struct net_device *dev)
|
||||||
|
{
|
||||||
|
return (struct channel_data *)dev_to_hdlc(dev)->priv;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- Initialization stuff ---------- */
|
/* ---------- Initialization stuff ---------- */
|
||||||
|
|
||||||
static int __init cosa_init(void)
|
static int __init cosa_init(void)
|
||||||
{
|
{
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
|
|
||||||
#endif
|
|
||||||
if (cosa_major > 0) {
|
if (cosa_major > 0) {
|
||||||
if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
|
if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
|
||||||
printk(KERN_WARNING "cosa: unable to get major %d\n",
|
printk(KERN_WARNING "cosa: unable to get major %d\n",
|
||||||
|
@ -402,7 +392,7 @@ static int __init cosa_init(void)
|
||||||
}
|
}
|
||||||
err = 0;
|
err = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_chrdev:
|
out_chrdev:
|
||||||
unregister_chrdev(cosa_major, "cosa");
|
unregister_chrdev(cosa_major, "cosa");
|
||||||
out:
|
out:
|
||||||
|
@ -414,43 +404,29 @@ static void __exit cosa_exit(void)
|
||||||
{
|
{
|
||||||
struct cosa_data *cosa;
|
struct cosa_data *cosa;
|
||||||
int i;
|
int i;
|
||||||
printk(KERN_INFO "Unloading the cosa module\n");
|
|
||||||
|
|
||||||
for (i=0; i<nr_cards; i++)
|
for (i = 0; i < nr_cards; i++)
|
||||||
device_destroy(cosa_class, MKDEV(cosa_major, i));
|
device_destroy(cosa_class, MKDEV(cosa_major, i));
|
||||||
class_destroy(cosa_class);
|
class_destroy(cosa_class);
|
||||||
for (cosa=cosa_cards; nr_cards--; cosa++) {
|
|
||||||
|
for (cosa = cosa_cards; nr_cards--; cosa++) {
|
||||||
/* Clean up the per-channel data */
|
/* Clean up the per-channel data */
|
||||||
for (i=0; i<cosa->nchannels; i++) {
|
for (i = 0; i < cosa->nchannels; i++) {
|
||||||
/* Chardev driver has no alloc'd per-channel data */
|
/* Chardev driver has no alloc'd per-channel data */
|
||||||
sppp_channel_delete(cosa->chan+i);
|
unregister_hdlc_device(cosa->chan[i].netdev);
|
||||||
|
free_netdev(cosa->chan[i].netdev);
|
||||||
}
|
}
|
||||||
/* Clean up the per-card data */
|
/* Clean up the per-card data */
|
||||||
kfree(cosa->chan);
|
kfree(cosa->chan);
|
||||||
kfree(cosa->bouncebuf);
|
kfree(cosa->bouncebuf);
|
||||||
free_irq(cosa->irq, cosa);
|
free_irq(cosa->irq, cosa);
|
||||||
free_dma(cosa->dma);
|
free_dma(cosa->dma);
|
||||||
release_region(cosa->datareg,is_8bit(cosa)?2:4);
|
release_region(cosa->datareg, is_8bit(cosa) ? 2 : 4);
|
||||||
}
|
}
|
||||||
unregister_chrdev(cosa_major, "cosa");
|
unregister_chrdev(cosa_major, "cosa");
|
||||||
}
|
}
|
||||||
module_exit(cosa_exit);
|
module_exit(cosa_exit);
|
||||||
|
|
||||||
/*
|
|
||||||
* This function should register all the net devices needed for the
|
|
||||||
* single channel.
|
|
||||||
*/
|
|
||||||
static __inline__ void channel_init(struct channel_data *chan)
|
|
||||||
{
|
|
||||||
sprintf(chan->name, "cosa%dc%d", chan->cosa->num, chan->num);
|
|
||||||
|
|
||||||
/* Initialize the chardev data structures */
|
|
||||||
chardev_channel_init(chan);
|
|
||||||
|
|
||||||
/* Register the sppp interface */
|
|
||||||
sppp_channel_init(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cosa_probe(int base, int irq, int dma)
|
static int cosa_probe(int base, int irq, int dma)
|
||||||
{
|
{
|
||||||
struct cosa_data *cosa = cosa_cards+nr_cards;
|
struct cosa_data *cosa = cosa_cards+nr_cards;
|
||||||
|
@ -576,13 +552,43 @@ static int cosa_probe(int base, int irq, int dma)
|
||||||
/* Initialize the per-channel data */
|
/* Initialize the per-channel data */
|
||||||
cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL);
|
cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL);
|
||||||
if (!cosa->chan) {
|
if (!cosa->chan) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_out3;
|
goto err_out3;
|
||||||
}
|
}
|
||||||
for (i=0; i<cosa->nchannels; i++) {
|
|
||||||
cosa->chan[i].cosa = cosa;
|
for (i = 0; i < cosa->nchannels; i++) {
|
||||||
cosa->chan[i].num = i;
|
struct channel_data *chan = &cosa->chan[i];
|
||||||
channel_init(cosa->chan+i);
|
|
||||||
|
chan->cosa = cosa;
|
||||||
|
chan->num = i;
|
||||||
|
sprintf(chan->name, "cosa%dc%d", chan->cosa->num, i);
|
||||||
|
|
||||||
|
/* Initialize the chardev data structures */
|
||||||
|
mutex_init(&chan->rlock);
|
||||||
|
init_MUTEX(&chan->wsem);
|
||||||
|
|
||||||
|
/* Register the network interface */
|
||||||
|
if (!(chan->netdev = alloc_hdlcdev(chan))) {
|
||||||
|
printk(KERN_WARNING "%s: alloc_hdlcdev failed.\n",
|
||||||
|
chan->name);
|
||||||
|
goto err_hdlcdev;
|
||||||
|
}
|
||||||
|
dev_to_hdlc(chan->netdev)->attach = cosa_net_attach;
|
||||||
|
dev_to_hdlc(chan->netdev)->xmit = cosa_net_tx;
|
||||||
|
chan->netdev->open = cosa_net_open;
|
||||||
|
chan->netdev->stop = cosa_net_close;
|
||||||
|
chan->netdev->do_ioctl = cosa_net_ioctl;
|
||||||
|
chan->netdev->tx_timeout = cosa_net_timeout;
|
||||||
|
chan->netdev->watchdog_timeo = TX_TIMEOUT;
|
||||||
|
chan->netdev->base_addr = chan->cosa->datareg;
|
||||||
|
chan->netdev->irq = chan->cosa->irq;
|
||||||
|
chan->netdev->dma = chan->cosa->dma;
|
||||||
|
if (register_hdlc_device(chan->netdev)) {
|
||||||
|
printk(KERN_WARNING "%s: register_hdlc_device()"
|
||||||
|
" failed.\n", chan->netdev->name);
|
||||||
|
free_netdev(chan->netdev);
|
||||||
|
goto err_hdlcdev;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n",
|
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)
|
||||||
cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels);
|
cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels);
|
||||||
|
|
||||||
return nr_cards++;
|
return nr_cards++;
|
||||||
|
|
||||||
|
err_hdlcdev:
|
||||||
|
while (i-- > 0) {
|
||||||
|
unregister_hdlc_device(cosa->chan[i].netdev);
|
||||||
|
free_netdev(cosa->chan[i].netdev);
|
||||||
|
}
|
||||||
|
kfree(cosa->chan);
|
||||||
err_out3:
|
err_out3:
|
||||||
kfree(cosa->bouncebuf);
|
kfree(cosa->bouncebuf);
|
||||||
err_out2:
|
err_out2:
|
||||||
free_dma(cosa->dma);
|
free_dma(cosa->dma);
|
||||||
err_out1:
|
err_out1:
|
||||||
free_irq(cosa->irq, cosa);
|
free_irq(cosa->irq, cosa);
|
||||||
err_out:
|
err_out:
|
||||||
release_region(cosa->datareg,is_8bit(cosa)?2:4);
|
release_region(cosa->datareg,is_8bit(cosa)?2:4);
|
||||||
printk(KERN_NOTICE "cosa%d: allocating resources failed\n",
|
printk(KERN_NOTICE "cosa%d: allocating resources failed\n",
|
||||||
cosa->num);
|
cosa->num);
|
||||||
|
@ -604,54 +617,19 @@ err_out:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*---------- SPPP/HDLC netdevice ---------- */
|
/*---------- network device ---------- */
|
||||||
|
|
||||||
static void cosa_setup(struct net_device *d)
|
static int cosa_net_attach(struct net_device *dev, unsigned short encoding,
|
||||||
|
unsigned short parity)
|
||||||
{
|
{
|
||||||
d->open = cosa_sppp_open;
|
if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT)
|
||||||
d->stop = cosa_sppp_close;
|
return 0;
|
||||||
d->hard_start_xmit = cosa_sppp_tx;
|
return -EINVAL;
|
||||||
d->do_ioctl = cosa_sppp_ioctl;
|
|
||||||
d->get_stats = cosa_net_stats;
|
|
||||||
d->tx_timeout = cosa_sppp_timeout;
|
|
||||||
d->watchdog_timeo = TX_TIMEOUT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sppp_channel_init(struct channel_data *chan)
|
static int cosa_net_open(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct net_device *d;
|
struct channel_data *chan = dev_to_chan(dev);
|
||||||
chan->if_ptr = &chan->pppdev;
|
|
||||||
d = alloc_netdev(0, chan->name, cosa_setup);
|
|
||||||
if (!d) {
|
|
||||||
printk(KERN_WARNING "%s: alloc_netdev failed.\n", chan->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
chan->pppdev.dev = d;
|
|
||||||
d->base_addr = chan->cosa->datareg;
|
|
||||||
d->irq = chan->cosa->irq;
|
|
||||||
d->dma = chan->cosa->dma;
|
|
||||||
d->ml_priv = chan;
|
|
||||||
sppp_attach(&chan->pppdev);
|
|
||||||
if (register_netdev(d)) {
|
|
||||||
printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
|
|
||||||
sppp_detach(d);
|
|
||||||
free_netdev(d);
|
|
||||||
chan->pppdev.dev = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sppp_channel_delete(struct channel_data *chan)
|
|
||||||
{
|
|
||||||
unregister_netdev(chan->pppdev.dev);
|
|
||||||
sppp_detach(chan->pppdev.dev);
|
|
||||||
free_netdev(chan->pppdev.dev);
|
|
||||||
chan->pppdev.dev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cosa_sppp_open(struct net_device *d)
|
|
||||||
{
|
|
||||||
struct channel_data *chan = d->ml_priv;
|
|
||||||
int err;
|
int err;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -662,36 +640,35 @@ static int cosa_sppp_open(struct net_device *d)
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(&chan->cosa->lock, flags);
|
spin_lock_irqsave(&chan->cosa->lock, flags);
|
||||||
if (chan->usage != 0) {
|
if (chan->usage != 0) {
|
||||||
printk(KERN_WARNING "%s: sppp_open called with usage count %d\n",
|
printk(KERN_WARNING "%s: cosa_net_open called with usage count"
|
||||||
chan->name, chan->usage);
|
" %d\n", chan->name, chan->usage);
|
||||||
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
chan->setup_rx = sppp_setup_rx;
|
chan->setup_rx = cosa_net_setup_rx;
|
||||||
chan->tx_done = sppp_tx_done;
|
chan->tx_done = cosa_net_tx_done;
|
||||||
chan->rx_done = sppp_rx_done;
|
chan->rx_done = cosa_net_rx_done;
|
||||||
chan->usage=-1;
|
chan->usage = -1;
|
||||||
chan->cosa->usage++;
|
chan->cosa->usage++;
|
||||||
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
||||||
|
|
||||||
err = sppp_open(d);
|
err = hdlc_open(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
spin_lock_irqsave(&chan->cosa->lock, flags);
|
spin_lock_irqsave(&chan->cosa->lock, flags);
|
||||||
chan->usage=0;
|
chan->usage = 0;
|
||||||
chan->cosa->usage--;
|
chan->cosa->usage--;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
netif_start_queue(d);
|
netif_start_queue(dev);
|
||||||
cosa_enable_rx(chan);
|
cosa_enable_rx(chan);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
|
static int cosa_net_tx(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct channel_data *chan = dev->ml_priv;
|
struct channel_data *chan = dev_to_chan(dev);
|
||||||
|
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
|
|
||||||
|
@ -700,16 +677,16 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cosa_sppp_timeout(struct net_device *dev)
|
static void cosa_net_timeout(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct channel_data *chan = dev->ml_priv;
|
struct channel_data *chan = dev_to_chan(dev);
|
||||||
|
|
||||||
if (test_bit(RXBIT, &chan->cosa->rxtx)) {
|
if (test_bit(RXBIT, &chan->cosa->rxtx)) {
|
||||||
chan->stats.rx_errors++;
|
chan->netdev->stats.rx_errors++;
|
||||||
chan->stats.rx_missed_errors++;
|
chan->netdev->stats.rx_missed_errors++;
|
||||||
} else {
|
} else {
|
||||||
chan->stats.tx_errors++;
|
chan->netdev->stats.tx_errors++;
|
||||||
chan->stats.tx_aborted_errors++;
|
chan->netdev->stats.tx_aborted_errors++;
|
||||||
}
|
}
|
||||||
cosa_kick(chan->cosa);
|
cosa_kick(chan->cosa);
|
||||||
if (chan->tx_skb) {
|
if (chan->tx_skb) {
|
||||||
|
@ -719,13 +696,13 @@ static void cosa_sppp_timeout(struct net_device *dev)
|
||||||
netif_wake_queue(dev);
|
netif_wake_queue(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cosa_sppp_close(struct net_device *d)
|
static int cosa_net_close(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct channel_data *chan = d->ml_priv;
|
struct channel_data *chan = dev_to_chan(dev);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
netif_stop_queue(d);
|
netif_stop_queue(dev);
|
||||||
sppp_close(d);
|
hdlc_close(dev);
|
||||||
cosa_disable_rx(chan);
|
cosa_disable_rx(chan);
|
||||||
spin_lock_irqsave(&chan->cosa->lock, flags);
|
spin_lock_irqsave(&chan->cosa->lock, flags);
|
||||||
if (chan->rx_skb) {
|
if (chan->rx_skb) {
|
||||||
|
@ -736,13 +713,13 @@ static int cosa_sppp_close(struct net_device *d)
|
||||||
kfree_skb(chan->tx_skb);
|
kfree_skb(chan->tx_skb);
|
||||||
chan->tx_skb = NULL;
|
chan->tx_skb = NULL;
|
||||||
}
|
}
|
||||||
chan->usage=0;
|
chan->usage = 0;
|
||||||
chan->cosa->usage--;
|
chan->cosa->usage--;
|
||||||
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
spin_unlock_irqrestore(&chan->cosa->lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *sppp_setup_rx(struct channel_data *chan, int size)
|
static char *cosa_net_setup_rx(struct channel_data *chan, int size)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We can safely fall back to non-dma-able memory, because we have
|
* 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)
|
||||||
if (chan->rx_skb == NULL) {
|
if (chan->rx_skb == NULL) {
|
||||||
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n",
|
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n",
|
||||||
chan->name);
|
chan->name);
|
||||||
chan->stats.rx_dropped++;
|
chan->netdev->stats.rx_dropped++;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
chan->pppdev.dev->trans_start = jiffies;
|
chan->netdev->trans_start = jiffies;
|
||||||
return skb_put(chan->rx_skb, size);
|
return skb_put(chan->rx_skb, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sppp_rx_done(struct channel_data *chan)
|
static int cosa_net_rx_done(struct channel_data *chan)
|
||||||
{
|
{
|
||||||
if (!chan->rx_skb) {
|
if (!chan->rx_skb) {
|
||||||
printk(KERN_WARNING "%s: rx_done with empty skb!\n",
|
printk(KERN_WARNING "%s: rx_done with empty skb!\n",
|
||||||
chan->name);
|
chan->name);
|
||||||
chan->stats.rx_errors++;
|
chan->netdev->stats.rx_errors++;
|
||||||
chan->stats.rx_frame_errors++;
|
chan->netdev->stats.rx_frame_errors++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
chan->rx_skb->protocol = htons(ETH_P_WAN_PPP);
|
chan->rx_skb->protocol = hdlc_type_trans(chan->rx_skb, chan->netdev);
|
||||||
chan->rx_skb->dev = chan->pppdev.dev;
|
chan->rx_skb->dev = chan->netdev;
|
||||||
skb_reset_mac_header(chan->rx_skb);
|
skb_reset_mac_header(chan->rx_skb);
|
||||||
chan->stats.rx_packets++;
|
chan->netdev->stats.rx_packets++;
|
||||||
chan->stats.rx_bytes += chan->cosa->rxsize;
|
chan->netdev->stats.rx_bytes += chan->cosa->rxsize;
|
||||||
netif_rx(chan->rx_skb);
|
netif_rx(chan->rx_skb);
|
||||||
chan->rx_skb = NULL;
|
chan->rx_skb = NULL;
|
||||||
chan->pppdev.dev->last_rx = jiffies;
|
chan->netdev->last_rx = jiffies;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
static int sppp_tx_done(struct channel_data *chan, int size)
|
static int cosa_net_tx_done(struct channel_data *chan, int size)
|
||||||
{
|
{
|
||||||
if (!chan->tx_skb) {
|
if (!chan->tx_skb) {
|
||||||
printk(KERN_WARNING "%s: tx_done with empty skb!\n",
|
printk(KERN_WARNING "%s: tx_done with empty skb!\n",
|
||||||
chan->name);
|
chan->name);
|
||||||
chan->stats.tx_errors++;
|
chan->netdev->stats.tx_errors++;
|
||||||
chan->stats.tx_aborted_errors++;
|
chan->netdev->stats.tx_aborted_errors++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
dev_kfree_skb_irq(chan->tx_skb);
|
dev_kfree_skb_irq(chan->tx_skb);
|
||||||
chan->tx_skb = NULL;
|
chan->tx_skb = NULL;
|
||||||
chan->stats.tx_packets++;
|
chan->netdev->stats.tx_packets++;
|
||||||
chan->stats.tx_bytes += size;
|
chan->netdev->stats.tx_bytes += size;
|
||||||
netif_wake_queue(chan->pppdev.dev);
|
netif_wake_queue(chan->netdev);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct net_device_stats *cosa_net_stats(struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct channel_data *chan = dev->ml_priv;
|
|
||||||
return &chan->stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*---------- Character device ---------- */
|
/*---------- Character device ---------- */
|
||||||
|
|
||||||
static void chardev_channel_init(struct channel_data *chan)
|
|
||||||
{
|
|
||||||
mutex_init(&chan->rlock);
|
|
||||||
init_MUTEX(&chan->wsem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t cosa_read(struct file *file,
|
static ssize_t cosa_read(struct file *file,
|
||||||
char __user *buf, size_t count, loff_t *ppos)
|
char __user *buf, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
|
@ -1223,16 +1187,15 @@ static int cosa_ioctl_common(struct cosa_data *cosa,
|
||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr,
|
static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
int cmd)
|
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
struct channel_data *chan = dev->ml_priv;
|
struct channel_data *chan = dev_to_chan(dev);
|
||||||
rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data);
|
rv = cosa_ioctl_common(chan->cosa, chan, cmd,
|
||||||
if (rv == -ENOIOCTLCMD) {
|
(unsigned long)ifr->ifr_data);
|
||||||
return sppp_do_ioctl(dev, ifr, cmd);
|
if (rv != -ENOIOCTLCMD)
|
||||||
}
|
return rv;
|
||||||
return rv;
|
return hdlc_ioctl(dev, ifr, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
|
static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче