Commit 314635e1 authored by Krzysztof Halasa's avatar Krzysztof Halasa Committed by Linus Torvalds

[PATCH] HDLC update

This updates generic HDLC from 1.14 to 1.15.

 - fix a kernel panic caused by a recent change to unregister_netdevice()
   (struct net_device * can't be kfreed before rtnl_unlock())
 - adds carrier_* support - hw drivers report DCD status and higher level
   protocols use that info, and do netif_carrier_{on,off}() according to
   DCD and (Cisco and FR) link management status.
 - moves Frame-Relay constants etc. from include/linux/hdlc.h to hdlc_fr.c.
   They are internal FR things and are not needed in the global header.
 - protocol hooks are slighty changed to allow zeroing (memset).
 - removes CONFIG_HDLC_DEBUG_* variables. Users tend to make very wrong
   use of them. Now setting them requires changing .c #define. Anyway they
   are development-only things.
 - misc style corrections etc.
parent 9c8b55a9
...@@ -401,37 +401,6 @@ config FARSYNC ...@@ -401,37 +401,6 @@ config FARSYNC
should add "alias hdlcX farsync" to /etc/modules.conf for each should add "alias hdlcX farsync" to /etc/modules.conf for each
interface, where X is 0, 1, 2, ... interface, where X is 0, 1, 2, ...
config HDLC_DEBUG_PKT
bool "Debug received/transmitted packets"
depends on HDLC
help
This option is for developers only - do NOT use on production
systems.
config HDLC_DEBUG_HARD_HEADER
bool "Debug hard_header routines"
depends on HDLC
help
This option is for developers only - do NOT use on production
systems.
config HDLC_DEBUG_ECN
bool "Debug FECN/BECN conditions"
depends on HDLC
help
This option is for developers only - do NOT use on production
systems.
config HDLC_DEBUG_RINGS
bool "Debug RX/TX packet rings"
depends on HDLC
help
If you answer Y here you will be able to get a diagnostic dump of
port's TX and RX packet rings, using "sethdlc hdlcX private"
command. It does not affect normal operations.
If unsure, say Y here.
config DLCI config DLCI
tristate "Frame relay DLCI support" tristate "Frame relay DLCI support"
depends on WAN depends on WAN
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
* Moxa C101 User's Manual * Moxa C101 User's Manual
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -31,9 +30,12 @@ ...@@ -31,9 +30,12 @@
#include "hd64570.h" #include "hd64570.h"
static const char* version = "Moxa C101 driver version: 1.14"; static const char* version = "Moxa C101 driver version: 1.15";
static const char* devname = "C101"; static const char* devname = "C101";
#undef DEBUG_PKT
#define DEBUG_RINGS
#define C101_PAGE 0x1D00 #define C101_PAGE 0x1D00
#define C101_DTR 0x1E00 #define C101_DTR 0x1E00
#define C101_SCA 0x1F00 #define C101_SCA 0x1F00
...@@ -95,7 +97,8 @@ static card_t **new_card = &first_card; ...@@ -95,7 +97,8 @@ static card_t **new_card = &first_card;
#define winsize(card) (C101_WINDOW_SIZE) #define winsize(card) (C101_WINDOW_SIZE)
#define win0base(card) ((card)->win0base) #define win0base(card) ((card)->win0base)
#define winbase(card) ((card)->win0base + 0x2000) #define winbase(card) ((card)->win0base + 0x2000)
#define get_port(card, port) ((port) == 0 ? (card) : NULL) #define get_port(card, port) (card)
static void sca_msci_intr(port_t *port);
static inline u8 sca_get_page(card_t *card) static inline u8 sca_get_page(card_t *card)
...@@ -116,9 +119,30 @@ static inline void openwin(card_t *card, u8 page) ...@@ -116,9 +119,30 @@ static inline void openwin(card_t *card, u8 page)
#include "hd6457x.c" #include "hd6457x.c"
static void sca_msci_intr(port_t *port)
{
card_t* card = port_to_card(port);
u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */
/* Reset MSCI TX underrun status bit */
sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card);
if (stat & ST1_UDRN) {
port->hdlc.stats.tx_errors++; /* TX Underrun error detected */
port->hdlc.stats.tx_fifo_errors++;
}
/* Reset MSCI CDCD status bit - uses ch#2 DCD input */
sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, card);
if (stat & ST1_CDCD)
hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD),
&port->hdlc);
}
static void c101_set_iface(port_t *port) static void c101_set_iface(port_t *port)
{ {
u8 msci = get_msci(port);
u8 rxs = port->rxs & CLK_BRG_MASK; u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK;
...@@ -145,8 +169,8 @@ static void c101_set_iface(port_t *port) ...@@ -145,8 +169,8 @@ static void c101_set_iface(port_t *port)
port->rxs = rxs; port->rxs = rxs;
port->txs = txs; port->txs = txs;
sca_out(rxs, msci + RXS, port); sca_out(rxs, MSCI1_OFFSET + RXS, port);
sca_out(txs, msci + TXS, port); sca_out(txs, MSCI1_OFFSET + TXS, port);
sca_set_port(port); sca_set_port(port);
} }
...@@ -164,6 +188,17 @@ static int c101_open(struct net_device *dev) ...@@ -164,6 +188,17 @@ static int c101_open(struct net_device *dev)
writeb(1, port->win0base + C101_DTR); writeb(1, port->win0base + C101_DTR);
sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
sca_open(hdlc); sca_open(hdlc);
/* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */
sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port);
sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port);
hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), hdlc);
printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port));
/* enable MSCI1 CDCD interrupt */
sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port);
sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port);
sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */
c101_set_iface(port); c101_set_iface(port);
return 0; return 0;
} }
...@@ -189,9 +224,14 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -189,9 +224,14 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc); port_t *port = hdlc_to_port(hdlc);
#ifdef CONFIG_HDLC_DEBUG_RINGS #ifdef DEBUG_RINGS
if (cmd == SIOCDEVPRIVATE) { if (cmd == SIOCDEVPRIVATE) {
sca_dump_rings(hdlc); sca_dump_rings(hdlc);
printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n",
sca_in(MSCI1_OFFSET + ST0, port),
sca_in(MSCI1_OFFSET + ST1, port),
sca_in(MSCI1_OFFSET + ST2, port),
sca_in(MSCI1_OFFSET + ST3, port));
return 0; return 0;
} }
#endif #endif
...@@ -298,9 +338,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) ...@@ -298,9 +338,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
card->tx_ring_buffers = TX_RING_BUFFERS; card->tx_ring_buffers = TX_RING_BUFFERS;
card->rx_ring_buffers = RX_RING_BUFFERS; card->rx_ring_buffers = RX_RING_BUFFERS;
printk(KERN_DEBUG "c101: using %u TX + %u RX packets rings\n",
card->tx_ring_buffers, card->rx_ring_buffers);
card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */
readb(card->win0base + C101_PAGE); /* Resets SCA? */ readb(card->win0base + C101_PAGE); /* Resets SCA? */
...@@ -333,6 +370,13 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) ...@@ -333,6 +370,13 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
} }
sca_init_sync_port(card); /* Set up C101 memory */ sca_init_sync_port(card); /* Set up C101 memory */
hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD),
&card->hdlc);
printk(KERN_INFO "%s: Moxa C101 on IRQ%u,"
" using %u TX + %u RX packets rings\n",
hdlc_to_name(&card->hdlc), card->irq,
card->tx_ring_buffers, card->rx_ring_buffers);
*new_card = card; *new_card = card;
new_card = &card->next_card; new_card = &card->next_card;
......
...@@ -217,12 +217,15 @@ typedef struct { ...@@ -217,12 +217,15 @@ typedef struct {
#define ST0_RXRDY 0x01 /* RX ready */ #define ST0_RXRDY 0x01 /* RX ready */
#define ST1_UDRN 0x80 /* MSCI TX underrun */ #define ST1_UDRN 0x80 /* MSCI TX underrun */
#define ST1_CDCD 0x04 /* DCD level changed */
#define ST3_CTS 0x08 /* modem input - /CTS */ #define ST3_CTS 0x08 /* modem input - /CTS */
#define ST3_DCD 0x04 /* modem input - /DCD */ #define ST3_DCD 0x04 /* modem input - /DCD */
#define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */ #define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */
#define IE0_RXINTA 0x40 /* RX INT A MSCI interrupt enable */
#define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */ #define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */
#define IE1_CDCD 0x04 /* DCD level changed */
#define DCR_ABORT 0x01 /* Software abort command */ #define DCR_ABORT 0x01 /* Software abort command */
#define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */ #define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -244,10 +243,14 @@ static void sca_init_sync_port(port_t *port) ...@@ -244,10 +243,14 @@ static void sca_init_sync_port(port_t *port)
sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card); sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card);
} }
} }
hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD),
&port->hdlc);
} }
#ifdef NEED_SCA_MSCI_INTR
/* MSCI interrupt service */ /* MSCI interrupt service */
static inline void sca_msci_intr(port_t *port) static inline void sca_msci_intr(port_t *port)
{ {
...@@ -255,17 +258,19 @@ static inline void sca_msci_intr(port_t *port) ...@@ -255,17 +258,19 @@ static inline void sca_msci_intr(port_t *port)
card_t* card = port_to_card(port); card_t* card = port_to_card(port);
u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */ u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */
/* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n", /* Reset MSCI TX underrun and CDCD status bit */
stat, sca_in(ILAR, card)); */ sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card);
/* Reset MSCI TX underrun status bit */
sca_out(stat & ST1_UDRN, msci + ST1, card);
if (stat & ST1_UDRN) { if (stat & ST1_UDRN) {
port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ port->hdlc.stats.tx_errors++; /* TX Underrun error detected */
port->hdlc.stats.tx_fifo_errors++; port->hdlc.stats.tx_fifo_errors++;
} }
if (stat & ST1_CDCD)
hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD),
&port->hdlc);
} }
#endif
...@@ -307,7 +312,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin) ...@@ -307,7 +312,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin)
openwin(card, 0); openwin(card, 0);
#endif #endif
skb_put(skb, len); skb_put(skb, len);
#ifdef CONFIG_HDLC_DEBUG_PKT #ifdef DEBUG_PKT
printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len);
debug_frame(skb); debug_frame(skb);
#endif #endif
...@@ -560,25 +565,28 @@ static void sca_open(hdlc_device *hdlc) ...@@ -560,25 +565,28 @@ static void sca_open(hdlc_device *hdlc)
#endif #endif
/* We're using the following interrupts: /* We're using the following interrupts:
- TXINT (DMAC completed all transmisions, underflow or CTS change) - TXINT (DMAC completed all transmisions, underrun or DCD change)
- all DMA interrupts - all DMA interrupts
*/ */
hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc);
#ifdef __HD64570_H #ifdef __HD64570_H
/* MSCI TX INT IRQ enable */ /* MSCI TX INT and RX INT A IRQ enable */
sca_out(IE0_TXINT, msci + IE0, card); sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card);
sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */ sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card);
sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08), sca_out(sca_in(IER0, card) | (phy_node(port) ? 0xC0 : 0x0C),
IER0, card); IER0, card); /* TXINT and RXINT */
/* DMA IRQ enable */ /* enable DMA IRQ */
sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
IER1, card); IER1, card);
#else #else
/* MSCI TX INT IRQ enable */ /* MSCI TXINT and RXINTA interrupt enable */
sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card); sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0,
card);
/* DMA & MSCI IRQ enable */ /* DMA & MSCI IRQ enable */
sca_outl(sca_in(IER0, card) | sca_outl(sca_inl(IER0, card) |
(phy_node(port) ? 0x02006600 : 0x00020066), IER0, card); (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card);
#endif #endif
#ifdef __HD64570_H #ifdef __HD64570_H
...@@ -600,10 +608,23 @@ static void sca_open(hdlc_device *hdlc) ...@@ -600,10 +608,23 @@ static void sca_open(hdlc_device *hdlc)
static void sca_close(hdlc_device *hdlc) static void sca_close(hdlc_device *hdlc)
{ {
port_t *port = hdlc_to_port(hdlc); port_t *port = hdlc_to_port(hdlc);
card_t* card = port_to_card(port);
/* reset channel */ /* reset channel */
netif_stop_queue(hdlc_to_dev(hdlc)); netif_stop_queue(hdlc_to_dev(hdlc));
sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
#ifdef __HD64570_H
/* disable MSCI interrupts */
sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0),
IER0, card);
/* disable DMA interrupts */
sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0),
IER1, card);
#else
/* disable DMA & MSCI IRQ */
sca_outl(sca_inl(IER0, card) &
(phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card);
#endif
} }
...@@ -636,7 +657,7 @@ static int sca_attach(hdlc_device *hdlc, unsigned short encoding, ...@@ -636,7 +657,7 @@ static int sca_attach(hdlc_device *hdlc, unsigned short encoding,
#ifdef CONFIG_HDLC_DEBUG_RINGS #ifdef DEBUG_RINGS
static void sca_dump_rings(hdlc_device *hdlc) static void sca_dump_rings(hdlc_device *hdlc)
{ {
port_t *port = hdlc_to_port(hdlc); port_t *port = hdlc_to_port(hdlc);
...@@ -651,30 +672,26 @@ static void sca_dump_rings(hdlc_device *hdlc) ...@@ -651,30 +672,26 @@ static void sca_dump_rings(hdlc_device *hdlc)
openwin(card, 0); openwin(card, 0);
#endif #endif
printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive",
sca_ina(get_dmac_rx(port) + CDAL, card), sca_ina(get_dmac_rx(port) + CDAL, card),
sca_ina(get_dmac_rx(port) + EDAL, card), sca_ina(get_dmac_rx(port) + EDAL, card),
sca_in(DSR_RX(phy_node(port)), card), sca_in(DSR_RX(phy_node(port)), card), port->rxin,
port->rxin,
sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in");
for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++)
printk(" %02X", printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
readb(&(desc_address(port, cnt, 0)->stat)));
printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
"last=%u %sactive", "last=%u %sactive",
sca_ina(get_dmac_tx(port) + CDAL, card), sca_ina(get_dmac_tx(port) + CDAL, card),
sca_ina(get_dmac_tx(port) + EDAL, card), sca_ina(get_dmac_tx(port) + EDAL, card),
sca_in(DSR_TX(phy_node(port)), card), port->txin, sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast,
port->txlast,
sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in");
for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++) for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++)
printk(" %02X", printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat)));
readb(&(desc_address(port, cnt, 1)->stat)));
printk("\n"); printk("\n");
printk(KERN_ERR "MSCI: MD: %02x %02x %02x, " printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, "
"ST: %02x %02x %02x %02x" "ST: %02x %02x %02x %02x"
#ifdef __HD64572_H #ifdef __HD64572_H
" %02x" " %02x"
...@@ -695,14 +712,18 @@ static void sca_dump_rings(hdlc_device *hdlc) ...@@ -695,14 +712,18 @@ static void sca_dump_rings(hdlc_device *hdlc)
sca_in(get_msci(port) + CST1, card)); sca_in(get_msci(port) + CST1, card));
#ifdef __HD64572_H #ifdef __HD64572_H
printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card)); printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card),
sca_inl(ISR0, card), sca_inl(ISR1, card));
#else
printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card),
sca_in(ISR1, card), sca_in(ISR2, card));
#endif #endif
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
openwin(card, page); /* Restore original page */ openwin(card, page); /* Restore original page */
#endif #endif
} }
#endif /* CONFIG_HDLC_DEBUG_RINGS */ #endif /* DEBUG_RINGS */
...@@ -723,7 +744,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -723,7 +744,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
desc = desc_address(port, port->txin + 1, 1); desc = desc_address(port, port->txin + 1, 1);
if (readb(&desc->stat)) { /* allow 1 packet gap */ if (readb(&desc->stat)) { /* allow 1 packet gap */
/* should never happen - previous xmit should stop queue */ /* should never happen - previous xmit should stop queue */
#ifdef CONFIG_HDLC_DEBUG_PKT #ifdef DEBUG_PKT
printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
#endif #endif
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -731,7 +752,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -731,7 +752,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
return 1; /* request packet to be queued */ return 1; /* request packet to be queued */
} }
#ifdef CONFIG_HDLC_DEBUG_PKT #ifdef DEBUG_PKT
printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len);
debug_frame(skb); debug_frame(skb);
#endif #endif
...@@ -828,7 +849,6 @@ static void __devinit sca_init(card_t *card, int wait_states) ...@@ -828,7 +849,6 @@ static void __devinit sca_init(card_t *card, int wait_states)
sca_out(0, DMER, card); /* DMA Master disable */ sca_out(0, DMER, card); /* DMA Master disable */
sca_out(0x03, PCR, card); /* DMA priority */ sca_out(0x03, PCR, card); /* DMA priority */
sca_out(0, IER1, card); /* DMA interrupt disable */
sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */
sca_out(0, DSR_TX(0), card); sca_out(0, DSR_TX(0), card);
sca_out(0, DSR_RX(1), card); sca_out(0, DSR_RX(1), card);
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -24,6 +23,7 @@ ...@@ -24,6 +23,7 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/hdlc.h> #include <linux/hdlc.h>
#undef DEBUG_HARD_HEADER
#define CISCO_MULTICAST 0x8F /* Cisco multicast address */ #define CISCO_MULTICAST 0x8F /* Cisco multicast address */
#define CISCO_UNICAST 0x0F /* Cisco unicast address */ #define CISCO_UNICAST 0x0F /* Cisco unicast address */
...@@ -39,7 +39,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, ...@@ -39,7 +39,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned int len) unsigned int len)
{ {
hdlc_header *data; hdlc_header *data;
#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER #ifdef DEBUG_HARD_HEADER
printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
#endif #endif
...@@ -182,7 +182,7 @@ static void cisco_rx(struct sk_buff *skb) ...@@ -182,7 +182,7 @@ static void cisco_rx(struct sk_buff *skb)
case CISCO_KEEPALIVE_REQ: case CISCO_KEEPALIVE_REQ:
hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) { if (ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
hdlc->state.cisco.last_poll = jiffies; hdlc->state.cisco.last_poll = jiffies;
if (!hdlc->state.cisco.up) { if (!hdlc->state.cisco.up) {
u32 sec, min, hrs, days; u32 sec, min, hrs, days;
...@@ -219,11 +219,12 @@ static void cisco_timer(unsigned long arg) ...@@ -219,11 +219,12 @@ static void cisco_timer(unsigned long arg)
{ {
hdlc_device *hdlc = (hdlc_device*)arg; hdlc_device *hdlc = (hdlc_device*)arg;
if (hdlc->state.cisco.up && if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >=
jiffies - hdlc->state.cisco.last_poll >=
hdlc->state.cisco.settings.timeout * HZ) { hdlc->state.cisco.settings.timeout * HZ) {
hdlc->state.cisco.up = 0; hdlc->state.cisco.up = 0;
printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
if (netif_carrier_ok(&hdlc->netdev))
netif_carrier_off(&hdlc->netdev);
} }
cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ,
...@@ -238,7 +239,7 @@ static void cisco_timer(unsigned long arg) ...@@ -238,7 +239,7 @@ static void cisco_timer(unsigned long arg)
static int cisco_open(hdlc_device *hdlc) static void cisco_start(hdlc_device *hdlc)
{ {
hdlc->state.cisco.last_poll = 0; hdlc->state.cisco.last_poll = 0;
hdlc->state.cisco.up = 0; hdlc->state.cisco.up = 0;
...@@ -249,14 +250,15 @@ static int cisco_open(hdlc_device *hdlc) ...@@ -249,14 +250,15 @@ static int cisco_open(hdlc_device *hdlc)
hdlc->state.cisco.timer.function = cisco_timer; hdlc->state.cisco.timer.function = cisco_timer;
hdlc->state.cisco.timer.data = (unsigned long)hdlc; hdlc->state.cisco.timer.data = (unsigned long)hdlc;
add_timer(&hdlc->state.cisco.timer); add_timer(&hdlc->state.cisco.timer);
return 0;
} }
static void cisco_close(hdlc_device *hdlc) static void cisco_stop(hdlc_device *hdlc)
{ {
del_timer_sync(&hdlc->state.cisco.timer); del_timer_sync(&hdlc->state.cisco.timer);
if (netif_carrier_ok(&hdlc->netdev))
netif_carrier_off(&hdlc->netdev);
} }
...@@ -301,12 +303,13 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr) ...@@ -301,12 +303,13 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
hdlc_proto_detach(hdlc); hdlc_proto_detach(hdlc);
memcpy(&hdlc->state.cisco.settings, &new_settings, size); memcpy(&hdlc->state.cisco.settings, &new_settings, size);
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
hdlc->open = cisco_open; hdlc->proto.start = cisco_start;
hdlc->stop = cisco_close; hdlc->proto.stop = cisco_stop;
hdlc->netif_rx = cisco_rx; hdlc->proto.netif_rx = cisco_rx;
hdlc->type_trans = cisco_type_trans; hdlc->proto.type_trans = cisco_type_trans;
hdlc->proto = IF_PROTO_CISCO; hdlc->proto.id = IF_PROTO_CISCO;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = cisco_hard_header; dev->hard_header = cisco_hard_header;
dev->type = ARPHRD_CISCO; dev->type = ARPHRD_CISCO;
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
* *
Theory of PVC state in DCE mode: Theory of PVC state
DCE mode:
(exist,new) -> 0,0 when "PVC create" or if "link unreliable" (exist,new) -> 0,0 when "PVC create" or if "link unreliable"
0,x -> 1,1 if "link reliable" when sending FULL STATUS 0,x -> 1,1 if "link reliable" when sending FULL STATUS
...@@ -17,9 +19,16 @@ ...@@ -17,9 +19,16 @@
(active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create"
-> 1 when "PVC up" and (exist,new) = 1,0 -> 1 when "PVC up" and (exist,new) = 1,0
DTE mode:
(exist,new,active) = FULL STATUS if "link reliable"
= 0, 0, 0 if "link unreliable"
No LMI:
active = open and "link reliable"
exist = new = not used
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -36,12 +45,96 @@ ...@@ -36,12 +45,96 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/hdlc.h> #include <linux/hdlc.h>
#undef DEBUG_PKT
#undef DEBUG_ECN
#undef DEBUG_LINK
#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */
#define PVC_STATE_NEW 0x01
#define PVC_STATE_ACTIVE 0x02
#define PVC_STATE_FECN 0x08 /* FECN condition */
#define PVC_STATE_BECN 0x10 /* BECN condition */
#define FR_UI 0x03
#define FR_PAD 0x00
#define NLPID_IP 0xCC
#define NLPID_IPV6 0x8E
#define NLPID_SNAP 0x80
#define NLPID_PAD 0x00
#define NLPID_Q933 0x08
#define LMI_DLCI 0 /* LMI DLCI */
#define LMI_PROTO 0x08
#define LMI_CALLREF 0x00 /* Call Reference */
#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */
#define LMI_REPTYPE 1 /* report type */
#define LMI_CCITT_REPTYPE 0x51
#define LMI_ALIVE 3 /* keep alive */
#define LMI_CCITT_ALIVE 0x53
#define LMI_PVCSTAT 7 /* pvc status */
#define LMI_CCITT_PVCSTAT 0x57
#define LMI_FULLREP 0 /* full report */
#define LMI_INTEGRITY 1 /* link integrity report */
#define LMI_SINGLE 2 /* single pvc report */
#define LMI_STATUS_ENQUIRY 0x75
#define LMI_STATUS 0x7D /* reply */
#define LMI_REPT_LEN 1 /* report type element length */
#define LMI_INTEG_LEN 2 /* link integrity element length */
#define LMI_LENGTH 13 /* standard LMI frame length */
#define LMI_ANSI_LENGTH 14
typedef struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned ea1: 1;
unsigned cr: 1;
unsigned dlcih: 6;
unsigned ea2: 1;
unsigned de: 1;
unsigned becn: 1;
unsigned fecn: 1;
unsigned dlcil: 4;
#else
unsigned dlcih: 6;
unsigned cr: 1;
unsigned ea1: 1;
unsigned dlcil: 4;
unsigned fecn: 1;
unsigned becn: 1;
unsigned de: 1;
unsigned ea2: 1;
#endif
}__attribute__ ((packed)) fr_hdr;
__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
static inline u16 q922_to_dlci(u8 *hdr)
{
return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
}
static inline void dlci_to_q922(u8 *hdr, u16 dlci)
{
hdr[0] = (dlci >> 2) & 0xFC;
hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
}
static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
{ {
pvc_device *pvc = hdlc->state.fr.first_pvc; pvc_device *pvc = hdlc->state.fr.first_pvc;
while(pvc) { while (pvc) {
if (pvc->dlci == dlci) if (pvc->dlci == dlci)
return pvc; return pvc;
if (pvc->dlci > dlci) if (pvc->dlci > dlci)
...@@ -53,15 +146,15 @@ __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) ...@@ -53,15 +146,15 @@ __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
} }
__inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci)
{ {
pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
while(*pvc_p) { while (*pvc_p) {
if ((*pvc_p)->dlci == dlci) if ((*pvc_p)->dlci == dlci)
return *pvc_p; return *pvc_p;
if ((*pvc_p)->dlci > dlci) if ((*pvc_p)->dlci > dlci)
break; /* the listed is sorted */ break; /* the list is sorted */
pvc_p = &(*pvc_p)->next; pvc_p = &(*pvc_p)->next;
} }
...@@ -78,17 +171,37 @@ __inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) ...@@ -78,17 +171,37 @@ __inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci)
} }
__inline__ int pvc_is_used(pvc_device *pvc) static inline int pvc_is_used(pvc_device *pvc)
{ {
return pvc->main != NULL || pvc->ether != NULL; return pvc->main != NULL || pvc->ether != NULL;
} }
__inline__ void delete_unused_pvcs(hdlc_device *hdlc) static inline void pvc_carrier(int on, pvc_device *pvc)
{
if (on) {
if (pvc->main)
if (!netif_carrier_ok(pvc->main))
netif_carrier_on(pvc->main);
if (pvc->ether)
if (!netif_carrier_ok(pvc->ether))
netif_carrier_on(pvc->ether);
} else {
if (pvc->main)
if (netif_carrier_ok(pvc->main))
netif_carrier_off(pvc->main);
if (pvc->ether)
if (netif_carrier_ok(pvc->ether))
netif_carrier_off(pvc->ether);
}
}
static inline void delete_unused_pvcs(hdlc_device *hdlc)
{ {
pvc_device **pvc_p = &hdlc->state.fr.first_pvc; pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
while(*pvc_p) { while (*pvc_p) {
if (!pvc_is_used(*pvc_p)) { if (!pvc_is_used(*pvc_p)) {
pvc_device *pvc = *pvc_p; pvc_device *pvc = *pvc_p;
*pvc_p = pvc->next; *pvc_p = pvc->next;
...@@ -100,7 +213,7 @@ __inline__ void delete_unused_pvcs(hdlc_device *hdlc) ...@@ -100,7 +213,7 @@ __inline__ void delete_unused_pvcs(hdlc_device *hdlc)
} }
__inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) static inline struct net_device** get_dev_p(pvc_device *pvc, int type)
{ {
if (type == ARPHRD_ETHER) if (type == ARPHRD_ETHER)
return &pvc->ether; return &pvc->ether;
...@@ -109,20 +222,19 @@ __inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) ...@@ -109,20 +222,19 @@ __inline__ struct net_device** get_dev_p(pvc_device *pvc, int type)
} }
__inline__ u16 status_to_dlci(u8 *status, int *active, int *new) static inline u16 status_to_dlci(u8 *status, int *active, int *new)
{ {
*new = (status[2] & 0x08) ? 1 : 0; *new = (status[2] & 0x08) ? 1 : 0;
*active = (status[2] & 0x02) ? 1 : 0; *active = (status[2] & 0x02) ? 1 : 0;
return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3);
} }
__inline__ void dlci_to_status(u16 dlci, u8 *status, static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new)
int active, int new)
{ {
status[0] = (dlci>>4) & 0x3F; status[0] = (dlci >> 4) & 0x3F;
status[1] = ((dlci<<3) & 0x78) | 0x80; status[1] = ((dlci << 3) & 0x78) | 0x80;
status[2] = 0x80; status[2] = 0x80;
if (new) if (new)
...@@ -138,7 +250,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) ...@@ -138,7 +250,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
u16 head_len; u16 head_len;
struct sk_buff *skb = *skb_p; struct sk_buff *skb = *skb_p;
switch(skb->protocol) { switch (skb->protocol) {
case __constant_ntohs(ETH_P_IP): case __constant_ntohs(ETH_P_IP):
head_len = 4; head_len = 4;
skb_push(skb, head_len); skb_push(skb, head_len);
...@@ -204,8 +316,9 @@ static int pvc_open(struct net_device *dev) ...@@ -204,8 +316,9 @@ static int pvc_open(struct net_device *dev)
if (pvc->open_count++ == 0) { if (pvc->open_count++ == 0) {
if (pvc->master->state.fr.settings.lmi == LMI_NONE) if (pvc->master->state.fr.settings.lmi == LMI_NONE)
pvc->state.active = 1; pvc->state.active = pvc->master->carrier;
pvc_carrier(pvc->state.active, pvc);
pvc->master->state.fr.dce_changed = 1; pvc->master->state.fr.dce_changed = 1;
} }
return 0; return 0;
...@@ -260,7 +373,7 @@ int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -260,7 +373,7 @@ int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
} }
__inline__ struct net_device_stats *pvc_get_stats(struct net_device *dev) static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
{ {
return (struct net_device_stats *) return (struct net_device_stats *)
((char *)dev + sizeof(struct net_device)); ((char *)dev + sizeof(struct net_device));
...@@ -402,6 +515,7 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) ...@@ -402,6 +515,7 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
/* ifconfig PVC up */ /* ifconfig PVC up */
if (pvc->open_count && !pvc->state.active && if (pvc->open_count && !pvc->state.active &&
pvc->state.exist && !pvc->state.new) { pvc->state.exist && !pvc->state.new) {
pvc_carrier(1, pvc);
pvc->state.active = 1; pvc->state.active = 1;
fr_log_dlci_active(pvc); fr_log_dlci_active(pvc);
} }
...@@ -423,6 +537,41 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) ...@@ -423,6 +537,41 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
static void fr_set_link_state(int reliable, hdlc_device *hdlc)
{
pvc_device *pvc = hdlc->state.fr.first_pvc;
hdlc->state.fr.reliable = reliable;
if (reliable) {
if (!netif_carrier_ok(&hdlc->netdev))
netif_carrier_on(&hdlc->netdev);
hdlc->state.fr.n391cnt = 0; /* Request full status */
hdlc->state.fr.dce_changed = 1;
if (hdlc->state.fr.settings.lmi == LMI_NONE) {
while (pvc) { /* Activate all PVCs */
pvc_carrier(1, pvc);
pvc->state.exist = pvc->state.active = 1;
pvc->state.new = 0;
pvc = pvc->next;
}
}
} else {
if (netif_carrier_ok(&hdlc->netdev))
netif_carrier_off(&hdlc->netdev);
while (pvc) { /* Deactivate all PVCs */
pvc_carrier(0, pvc);
pvc->state.exist = pvc->state.active = 0;
pvc->state.new = 0;
pvc = pvc->next;
}
}
}
static void fr_timer(unsigned long arg) static void fr_timer(unsigned long arg)
{ {
hdlc_device *hdlc = (hdlc_device*)arg; hdlc_device *hdlc = (hdlc_device*)arg;
...@@ -449,22 +598,9 @@ static void fr_timer(unsigned long arg) ...@@ -449,22 +598,9 @@ static void fr_timer(unsigned long arg)
} }
if (hdlc->state.fr.reliable != reliable) { if (hdlc->state.fr.reliable != reliable) {
pvc_device *pvc = hdlc->state.fr.first_pvc;
hdlc->state.fr.reliable = reliable;
printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
reliable ? "" : "un"); reliable ? "" : "un");
fr_set_link_state(reliable, hdlc);
if (reliable) {
hdlc->state.fr.n391cnt = 0; /* Request full status */
hdlc->state.fr.dce_changed = 1;
} else {
while (pvc) { /* Deactivate all PVCs */
pvc->state.exist = 0;
pvc->state.active = pvc->state.new = 0;
pvc = pvc->next;
}
}
} }
if (hdlc->state.fr.settings.dce) if (hdlc->state.fr.settings.dce)
...@@ -636,6 +772,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) ...@@ -636,6 +772,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
!pvc->state.exist) { !pvc->state.exist) {
pvc->state.new = new; pvc->state.new = new;
pvc->state.active = active; pvc->state.active = active;
pvc_carrier(active, pvc);
fr_log_dlci_active(pvc); fr_log_dlci_active(pvc);
} }
} }
...@@ -647,6 +784,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) ...@@ -647,6 +784,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
while (pvc) { while (pvc) {
if (pvc->state.deleted && pvc->state.exist) { if (pvc->state.deleted && pvc->state.exist) {
pvc_carrier(0, pvc);
pvc->state.active = pvc->state.new = 0; pvc->state.active = pvc->state.new = 0;
pvc->state.exist = 0; pvc->state.exist = 0;
fr_log_dlci_active(pvc); fr_log_dlci_active(pvc);
...@@ -699,7 +837,7 @@ static void fr_rx(struct sk_buff *skb) ...@@ -699,7 +837,7 @@ static void fr_rx(struct sk_buff *skb)
pvc = find_pvc(hdlc, dlci); pvc = find_pvc(hdlc, dlci);
if (!pvc) { if (!pvc) {
#ifdef CONFIG_HDLC_DEBUG_PKT #ifdef DEBUG_PKT
printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
hdlc_to_name(hdlc), dlci); hdlc_to_name(hdlc), dlci);
#endif #endif
...@@ -708,7 +846,7 @@ static void fr_rx(struct sk_buff *skb) ...@@ -708,7 +846,7 @@ static void fr_rx(struct sk_buff *skb)
} }
if (pvc->state.fecn != fh->fecn) { if (pvc->state.fecn != fh->fecn) {
#ifdef CONFIG_HDLC_DEBUG_ECN #ifdef DEBUG_ECN
printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc), printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc),
dlci, fh->fecn ? "N" : "FF"); dlci, fh->fecn ? "N" : "FF");
#endif #endif
...@@ -716,7 +854,7 @@ static void fr_rx(struct sk_buff *skb) ...@@ -716,7 +854,7 @@ static void fr_rx(struct sk_buff *skb)
} }
if (pvc->state.becn != fh->becn) { if (pvc->state.becn != fh->becn) {
#ifdef CONFIG_HDLC_DEBUG_ECN #ifdef DEBUG_ECN
printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc), printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc),
dlci, fh->becn ? "N" : "FF"); dlci, fh->becn ? "N" : "FF");
#endif #endif
...@@ -787,9 +925,14 @@ static void fr_rx(struct sk_buff *skb) ...@@ -787,9 +925,14 @@ static void fr_rx(struct sk_buff *skb)
static int fr_open(hdlc_device *hdlc) static void fr_start(hdlc_device *hdlc)
{ {
#ifdef DEBUG_LINK
printk(KERN_DEBUG "fr_start\n");
#endif
if (hdlc->state.fr.settings.lmi != LMI_NONE) { if (hdlc->state.fr.settings.lmi != LMI_NONE) {
if (netif_carrier_ok(&hdlc->netdev))
netif_carrier_off(&hdlc->netdev);
hdlc->state.fr.last_poll = 0; hdlc->state.fr.last_poll = 0;
hdlc->state.fr.reliable = 0; hdlc->state.fr.reliable = 0;
hdlc->state.fr.dce_changed = 1; hdlc->state.fr.dce_changed = 1;
...@@ -806,9 +949,19 @@ static int fr_open(hdlc_device *hdlc) ...@@ -806,9 +949,19 @@ static int fr_open(hdlc_device *hdlc)
hdlc->state.fr.timer.data = (unsigned long)hdlc; hdlc->state.fr.timer.data = (unsigned long)hdlc;
add_timer(&hdlc->state.fr.timer); add_timer(&hdlc->state.fr.timer);
} else } else
hdlc->state.fr.reliable = 1; fr_set_link_state(1, hdlc);
}
return 0;
static void fr_stop(hdlc_device *hdlc)
{
#ifdef DEBUG_LINK
printk(KERN_DEBUG "fr_stop\n");
#endif
if (hdlc->state.fr.settings.lmi != LMI_NONE)
del_timer_sync(&hdlc->state.fr.timer);
fr_set_link_state(0, hdlc);
} }
...@@ -817,22 +970,17 @@ static void fr_close(hdlc_device *hdlc) ...@@ -817,22 +970,17 @@ static void fr_close(hdlc_device *hdlc)
{ {
pvc_device *pvc = hdlc->state.fr.first_pvc; pvc_device *pvc = hdlc->state.fr.first_pvc;
if (hdlc->state.fr.settings.lmi != LMI_NONE) while (pvc) { /* Shutdown all PVCs for this FRAD */
del_timer_sync(&hdlc->state.fr.timer);
while(pvc) { /* Shutdown all PVCs for this FRAD */
if (pvc->main) if (pvc->main)
dev_close(pvc->main); dev_close(pvc->main);
if (pvc->ether) if (pvc->ether)
dev_close(pvc->ether); dev_close(pvc->ether);
pvc->state.active = pvc->state.new = pvc->state.fecn =
pvc->state.becn = 0;
pvc->state.exist = 0;
pvc = pvc->next; pvc = pvc->next;
} }
} }
static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
{ {
pvc_device *pvc = NULL; pvc_device *pvc = NULL;
...@@ -900,6 +1048,7 @@ static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) ...@@ -900,6 +1048,7 @@ static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
return -EIO; return -EIO;
} }
dev->destructor = (void (*)(struct net_device *)) kfree;
*get_dev_p(pvc, type) = dev; *get_dev_p(pvc, type) = dev;
if (!used) { if (!used) {
hdlc->state.fr.dce_changed = 1; hdlc->state.fr.dce_changed = 1;
...@@ -924,8 +1073,7 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) ...@@ -924,8 +1073,7 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP)
return -EBUSY; /* PVC in use */ return -EBUSY; /* PVC in use */
unregister_netdevice(dev); unregister_netdevice(dev); /* the destructor will kfree(dev) */
kfree(dev);
*get_dev_p(pvc, type) = NULL; *get_dev_p(pvc, type) = NULL;
if (!pvc_is_used(pvc)) { if (!pvc_is_used(pvc)) {
...@@ -940,24 +1088,24 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) ...@@ -940,24 +1088,24 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
static void fr_destroy(hdlc_device *hdlc) static void fr_destroy(hdlc_device *hdlc)
{ {
pvc_device *pvc = hdlc->state.fr.first_pvc; pvc_device *pvc;
while(pvc) {
pvc = hdlc->state.fr.first_pvc;
hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
hdlc->state.fr.dce_pvc_count = 0;
hdlc->state.fr.dce_changed = 1;
while (pvc) {
pvc_device *next = pvc->next; pvc_device *next = pvc->next;
if (pvc->main) { if (pvc->main) /* the destructor will kfree(main + ether) */
unregister_netdevice(pvc->main); unregister_netdevice(pvc->main);
kfree(pvc->main);
} if (pvc->ether)
if (pvc->ether) {
unregister_netdevice(pvc->ether); unregister_netdevice(pvc->ether);
kfree(pvc->ether);
}
kfree(pvc); kfree(pvc);
pvc = next; pvc = next;
} }
hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
hdlc->state.fr.dce_pvc_count = 0;
hdlc->state.fr.dce_changed = 1;
} }
...@@ -1012,19 +1160,20 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr) ...@@ -1012,19 +1160,20 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
if (result) if (result)
return result; return result;
if (hdlc->proto != IF_PROTO_FR) { if (hdlc->proto.id != IF_PROTO_FR) {
hdlc_proto_detach(hdlc); hdlc_proto_detach(hdlc);
hdlc->state.fr.first_pvc = NULL; hdlc->state.fr.first_pvc = NULL;
hdlc->state.fr.dce_pvc_count = 0; hdlc->state.fr.dce_pvc_count = 0;
} }
memcpy(&hdlc->state.fr.settings, &new_settings, size); memcpy(&hdlc->state.fr.settings, &new_settings, size);
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
hdlc->open = fr_open;
hdlc->stop = fr_close; hdlc->proto.close = fr_close;
hdlc->netif_rx = fr_rx; hdlc->proto.start = fr_start;
hdlc->type_trans = NULL; hdlc->proto.stop = fr_stop;
hdlc->proto_detach = fr_destroy; hdlc->proto.detach = fr_destroy;
hdlc->proto = IF_PROTO_FR; hdlc->proto.netif_rx = fr_rx;
hdlc->proto.id = IF_PROTO_FR;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_FRAD; dev->type = ARPHRD_FRAD;
......
...@@ -33,7 +33,9 @@ ...@@ -33,7 +33,9 @@
#include <linux/hdlc.h> #include <linux/hdlc.h>
static const char* version = "HDLC support module revision 1.14"; static const char* version = "HDLC support module revision 1.15";
#undef DEBUG_LINK
static int hdlc_change_mtu(struct net_device *dev, int new_mtu) static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
...@@ -57,8 +59,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -57,8 +59,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p) struct packet_type *p)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->netif_rx) if (hdlc->proto.netif_rx)
hdlc->netif_rx(skb); hdlc->proto.netif_rx(skb);
else { else {
hdlc->stats.rx_dropped++; /* Shouldn't happen */ hdlc->stats.rx_dropped++; /* Shouldn't happen */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -67,6 +69,103 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -67,6 +69,103 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
} }
void hdlc_set_carrier(int on, hdlc_device *hdlc)
{
on = on ? 1 : 0;
#ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_set_carrier %i\n", on);
#endif
spin_lock_irq(&hdlc->state_lock);
if (hdlc->carrier == on)
goto carrier_exit; /* no change in DCD line level */
printk(KERN_INFO "%s: carrier %s\n", hdlc_to_name(hdlc),
on ? "ON" : "off");
hdlc->carrier = on;
if (!hdlc->open)
goto carrier_exit;
if (hdlc->carrier) {
if (hdlc->proto.start)
hdlc->proto.start(hdlc);
else if (!netif_carrier_ok(&hdlc->netdev))
netif_carrier_on(&hdlc->netdev);
} else { /* no carrier */
if (hdlc->proto.stop)
hdlc->proto.stop(hdlc);
else if (netif_carrier_ok(&hdlc->netdev))
netif_carrier_off(&hdlc->netdev);
}
carrier_exit:
spin_unlock_irq(&hdlc->state_lock);
}
/* Must be called by hardware driver when HDLC device is being opened */
int hdlc_open(hdlc_device *hdlc)
{
#ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_open carrier %i open %i\n",
hdlc->carrier, hdlc->open);
#endif
if (hdlc->proto.id == -1)
return -ENOSYS; /* no protocol attached */
if (hdlc->proto.open) {
int result = hdlc->proto.open(hdlc);
if (result)
return result;
}
spin_lock_irq(&hdlc->state_lock);
if (hdlc->carrier) {
if (hdlc->proto.start)
hdlc->proto.start(hdlc);
else if (!netif_carrier_ok(&hdlc->netdev))
netif_carrier_on(&hdlc->netdev);
} else if (netif_carrier_ok(&hdlc->netdev))
netif_carrier_off(&hdlc->netdev);
hdlc->open = 1;
spin_unlock_irq(&hdlc->state_lock);
return 0;
}
/* Must be called by hardware driver when HDLC device is being closed */
void hdlc_close(hdlc_device *hdlc)
{
#ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_close carrier %i open %i\n",
hdlc->carrier, hdlc->open);
#endif
spin_lock_irq(&hdlc->state_lock);
hdlc->open = 0;
if (hdlc->carrier && hdlc->proto.stop)
hdlc->proto.stop(hdlc);
spin_unlock_irq(&hdlc->state_lock);
if (hdlc->proto.close)
hdlc->proto.close(hdlc);
}
#ifndef CONFIG_HDLC_RAW #ifndef CONFIG_HDLC_RAW
#define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS #define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS
#endif #endif
...@@ -111,7 +210,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -111,7 +210,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break; break;
default: default:
proto = hdlc->proto; proto = hdlc->proto.id;
} }
switch(proto) { switch(proto) {
...@@ -141,11 +240,14 @@ int register_hdlc_device(hdlc_device *hdlc) ...@@ -141,11 +240,14 @@ int register_hdlc_device(hdlc_device *hdlc)
dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->flags = IFF_POINTOPOINT | IFF_NOARP;
hdlc->proto = -1; hdlc->proto.id = -1;
hdlc->proto_detach = NULL; hdlc->proto.detach = NULL;
hdlc->carrier = 1;
hdlc->open = 0;
spin_lock_init(&hdlc->state_lock);
result = dev_alloc_name(dev, "hdlc%d"); result = dev_alloc_name(dev, "hdlc%d");
if (result<0) if (result < 0)
return result; return result;
result = register_netdev(dev); result = register_netdev(dev);
...@@ -171,6 +273,9 @@ MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); ...@@ -171,6 +273,9 @@ MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("HDLC support module"); MODULE_DESCRIPTION("HDLC support module");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
EXPORT_SYMBOL(hdlc_set_carrier);
EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(hdlc_ioctl);
EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(register_hdlc_device);
EXPORT_SYMBOL(unregister_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device);
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -99,12 +98,12 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr) ...@@ -99,12 +98,12 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
return result; return result;
hdlc_proto_detach(hdlc); hdlc_proto_detach(hdlc);
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
hdlc->open = ppp_open; hdlc->proto.open = ppp_open;
hdlc->stop = ppp_close; hdlc->proto.close = ppp_close;
hdlc->netif_rx = NULL; hdlc->proto.type_trans = ppp_type_trans;
hdlc->type_trans = ppp_type_trans; hdlc->proto.id = IF_PROTO_PPP;
hdlc->proto = IF_PROTO_PPP;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_PPP; dev->type = ARPHRD_PPP;
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -75,12 +74,10 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr) ...@@ -75,12 +74,10 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
hdlc_proto_detach(hdlc); hdlc_proto_detach(hdlc);
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
hdlc->open = NULL; hdlc->proto.type_trans = raw_type_trans;
hdlc->stop = NULL; hdlc->proto.id = IF_PROTO_HDLC;
hdlc->netif_rx = NULL;
hdlc->type_trans = raw_type_trans;
hdlc->proto = IF_PROTO_HDLC;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_RAWHDLC; dev->type = ARPHRD_RAWHDLC;
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -89,12 +88,10 @@ int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr) ...@@ -89,12 +88,10 @@ int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
hdlc_proto_detach(hdlc); hdlc_proto_detach(hdlc);
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
hdlc->open = NULL; hdlc->proto.type_trans = eth_type_trans;
hdlc->stop = NULL; hdlc->proto.id = IF_PROTO_HDLC_ETH;
hdlc->netif_rx = NULL;
hdlc->type_trans = eth_type_trans;
hdlc->proto = IF_PROTO_HDLC_ETH;
dev->hard_start_xmit = eth_tx; dev->hard_start_xmit = eth_tx;
old_ch_mtu = dev->change_mtu; old_ch_mtu = dev->change_mtu;
old_qlen = dev->tx_queue_len; old_qlen = dev->tx_queue_len;
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -199,12 +198,13 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr) ...@@ -199,12 +198,13 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
return result; return result;
hdlc_proto_detach(hdlc); hdlc_proto_detach(hdlc);
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
hdlc->open = x25_open; hdlc->proto.open = x25_open;
hdlc->stop = x25_close; hdlc->proto.close = x25_close;
hdlc->netif_rx = x25_rx; hdlc->proto.netif_rx = x25_rx;
hdlc->type_trans = NULL; hdlc->proto.type_trans = NULL;
hdlc->proto = IF_PROTO_X25; hdlc->proto.id = IF_PROTO_X25;
dev->hard_start_xmit = x25_xmit; dev->hard_start_xmit = x25_xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_X25; dev->type = ARPHRD_X25;
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
* SDL Inc. PPP/HDLC/CISCO driver * SDL Inc. PPP/HDLC/CISCO driver
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -34,9 +33,12 @@ ...@@ -34,9 +33,12 @@
#include "hd64570.h" #include "hd64570.h"
static const char* version = "SDL RISCom/N2 driver version: 1.14"; static const char* version = "SDL RISCom/N2 driver version: 1.15";
static const char* devname = "RISCom/N2"; static const char* devname = "RISCom/N2";
#undef DEBUG_PKT
#define DEBUG_RINGS
#define USE_WINDOWSIZE 16384 #define USE_WINDOWSIZE 16384
#define USE_BUS16BITS 1 #define USE_BUS16BITS 1
#define CLOCK_BASE 9830400 /* 9.8304 MHz */ #define CLOCK_BASE 9830400 /* 9.8304 MHz */
...@@ -48,6 +50,7 @@ static const char* devname = "RISCom/N2"; ...@@ -48,6 +50,7 @@ static const char* devname = "RISCom/N2";
#endif #endif
#define N2_IOPORTS 0x10 #define N2_IOPORTS 0x10
#define NEED_DETECT_RAM #define NEED_DETECT_RAM
#define NEED_SCA_MSCI_INTR
#define MAX_TX_BUFFERS 10 #define MAX_TX_BUFFERS 10
static char *hw = NULL; /* pointer to hw=xxx command line string */ static char *hw = NULL; /* pointer to hw=xxx command line string */
...@@ -257,7 +260,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -257,7 +260,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc); port_t *port = hdlc_to_port(hdlc);
#ifdef CONFIG_HDLC_DEBUG_RINGS #ifdef DEBUG_RINGS
if (cmd == SIOCDEVPRIVATE) { if (cmd == SIOCDEVPRIVATE) {
sca_dump_rings(hdlc); sca_dump_rings(hdlc);
return 0; return 0;
...@@ -415,7 +418,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, ...@@ -415,7 +418,7 @@ static int __init n2_run(unsigned long io, unsigned long irq,
card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) *
(card->tx_ring_buffers + card->rx_ring_buffers); (card->tx_ring_buffers + card->rx_ring_buffers);
printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " printk(KERN_INFO "n2: RISCom/N2 %u KB RAM, IRQ%u, "
"using %u TX + %u RX packets rings\n", card->ram_size / 1024, "using %u TX + %u RX packets rings\n", card->ram_size / 1024,
card->irq, card->tx_ring_buffers, card->rx_ring_buffers); card->irq, card->tx_ring_buffers, card->rx_ring_buffers);
...@@ -447,7 +450,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, ...@@ -447,7 +450,7 @@ static int __init n2_run(unsigned long io, unsigned long irq,
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
dev->irq = irq; dev->irq = irq;
dev->mem_start = winbase; dev->mem_start = winbase;
dev->mem_end = winbase + USE_WINDOWSIZE-1; dev->mem_end = winbase + USE_WINDOWSIZE - 1;
dev->tx_queue_len = 50; dev->tx_queue_len = 50;
dev->do_ioctl = n2_ioctl; dev->do_ioctl = n2_ioctl;
dev->open = n2_open; dev->open = n2_open;
......
...@@ -42,6 +42,9 @@ ...@@ -42,6 +42,9 @@
#define LMI_ANSI 2 /* ANSI Annex D */ #define LMI_ANSI 2 /* ANSI Annex D */
#define LMI_CCITT 3 /* ITU-T Annex A */ #define LMI_CCITT 3 /* ITU-T Annex A */
#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -50,78 +53,6 @@ ...@@ -50,78 +53,6 @@
#include <net/syncppp.h> #include <net/syncppp.h>
#include <linux/hdlc/ioctl.h> #include <linux/hdlc/ioctl.h>
#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */
#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */
#define PVC_STATE_NEW 0x01
#define PVC_STATE_ACTIVE 0x02
#define PVC_STATE_FECN 0x08 /* FECN condition */
#define PVC_STATE_BECN 0x10 /* BECN condition */
#define FR_UI 0x03
#define FR_PAD 0x00
#define NLPID_IP 0xCC
#define NLPID_IPV6 0x8E
#define NLPID_SNAP 0x80
#define NLPID_PAD 0x00
#define NLPID_Q933 0x08
#define LMI_DLCI 0 /* LMI DLCI */
#define LMI_PROTO 0x08
#define LMI_CALLREF 0x00 /* Call Reference */
#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */
#define LMI_REPTYPE 1 /* report type */
#define LMI_CCITT_REPTYPE 0x51
#define LMI_ALIVE 3 /* keep alive */
#define LMI_CCITT_ALIVE 0x53
#define LMI_PVCSTAT 7 /* pvc status */
#define LMI_CCITT_PVCSTAT 0x57
#define LMI_FULLREP 0 /* full report */
#define LMI_INTEGRITY 1 /* link integrity report */
#define LMI_SINGLE 2 /* single pvc report */
#define LMI_STATUS_ENQUIRY 0x75
#define LMI_STATUS 0x7D /* reply */
#define LMI_REPT_LEN 1 /* report type element length */
#define LMI_INTEG_LEN 2 /* link integrity element length */
#define LMI_LENGTH 13 /* standard LMI frame length */
#define LMI_ANSI_LENGTH 14
typedef struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned ea1 : 1;
unsigned cr : 1;
unsigned dlcih: 6;
unsigned ea2 : 1;
unsigned de : 1;
unsigned becn : 1;
unsigned fecn : 1;
unsigned dlcil: 4;
#elif defined (__BIG_ENDIAN_BITFIELD)
unsigned dlcih: 6;
unsigned cr : 1;
unsigned ea1 : 1;
unsigned dlcil: 4;
unsigned fecn : 1;
unsigned becn : 1;
unsigned de : 1;
unsigned ea2 : 1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}__attribute__ ((packed)) fr_hdr;
typedef struct { /* Used in Cisco and PPP mode */ typedef struct { /* Used in Cisco and PPP mode */
u8 address; u8 address;
...@@ -177,14 +108,25 @@ typedef struct hdlc_device_struct { ...@@ -177,14 +108,25 @@ typedef struct hdlc_device_struct {
/* Things below are for HDLC layer internal use only */ /* Things below are for HDLC layer internal use only */
int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); struct {
int (*open)(struct hdlc_device_struct *hdlc); int (*open)(struct hdlc_device_struct *hdlc);
void (*close)(struct hdlc_device_struct *hdlc);
/* if open & DCD */
void (*start)(struct hdlc_device_struct *hdlc);
/* if open & !DCD */
void (*stop)(struct hdlc_device_struct *hdlc); void (*stop)(struct hdlc_device_struct *hdlc);
void (*proto_detach)(struct hdlc_device_struct *hdlc);
void (*detach)(struct hdlc_device_struct *hdlc);
void (*netif_rx)(struct sk_buff *skb); void (*netif_rx)(struct sk_buff *skb);
unsigned short (*type_trans)(struct sk_buff *skb, unsigned short (*type_trans)(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */ int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */
}proto;
int carrier;
int open;
spinlock_t state_lock;
union { union {
struct { struct {
...@@ -271,26 +213,11 @@ static __inline__ const char *hdlc_to_name(hdlc_device *hdlc) ...@@ -271,26 +213,11 @@ static __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
} }
static __inline__ u16 q922_to_dlci(u8 *hdr)
{
return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
}
static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
{
hdr[0] = (dlci >> 2) & 0xFC;
hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
}
static __inline__ void debug_frame(const struct sk_buff *skb) static __inline__ void debug_frame(const struct sk_buff *skb)
{ {
int i; int i;
for (i=0; i<skb->len; i++) { for (i=0; i < skb->len; i++) {
if (i == 100) { if (i == 100) {
printk("...\n"); printk("...\n");
return; return;
...@@ -301,33 +228,19 @@ static __inline__ void debug_frame(const struct sk_buff *skb) ...@@ -301,33 +228,19 @@ static __inline__ void debug_frame(const struct sk_buff *skb)
} }
/* Must be called by hardware driver when HDLC device is being opened */ /* Must be called by hardware driver when HDLC device is being opened */
static __inline__ int hdlc_open(hdlc_device *hdlc) int hdlc_open(hdlc_device *hdlc);
{
if (hdlc->proto == -1)
return -ENOSYS; /* no protocol attached */
if (hdlc->open)
return hdlc->open(hdlc);
return 0;
}
/* Must be called by hardware driver when HDLC device is being closed */ /* Must be called by hardware driver when HDLC device is being closed */
static __inline__ void hdlc_close(hdlc_device *hdlc) void hdlc_close(hdlc_device *hdlc);
{ /* Called by hardware driver when DCD line level changes */
if (hdlc->stop) void hdlc_set_carrier(int on, hdlc_device *hdlc);
hdlc->stop(hdlc);
}
/* May be used by hardware driver to gain control over HDLC device */ /* May be used by hardware driver to gain control over HDLC device */
static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
{ {
if (hdlc->proto_detach) if (hdlc->proto.detach)
hdlc->proto_detach(hdlc); hdlc->proto.detach(hdlc);
hdlc->proto_detach = NULL; hdlc->proto.detach = NULL;
} }
...@@ -335,8 +248,8 @@ static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb, ...@@ -335,8 +248,8 @@ static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(skb->dev); hdlc_device *hdlc = dev_to_hdlc(skb->dev);
if (hdlc->type_trans) if (hdlc->proto.type_trans)
return hdlc->type_trans(skb, dev); return hdlc->proto.type_trans(skb, dev);
else else
return __constant_htons(ETH_P_HDLC); return __constant_htons(ETH_P_HDLC);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment