]> git.hungrycats.org Git - linux/commitdiff
[PATCH] HDLC update
authorKrzysztof Halasa <khc@pm.waw.pl>
Fri, 25 Jul 2003 08:24:04 +0000 (01:24 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Fri, 25 Jul 2003 08:24:04 +0000 (01:24 -0700)
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.

13 files changed:
drivers/net/wan/Kconfig
drivers/net/wan/c101.c
drivers/net/wan/hd64570.h
drivers/net/wan/hd6457x.c
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/hdlc_fr.c
drivers/net/wan/hdlc_generic.c
drivers/net/wan/hdlc_ppp.c
drivers/net/wan/hdlc_raw.c
drivers/net/wan/hdlc_raw_eth.c
drivers/net/wan/hdlc_x25.c
drivers/net/wan/n2.c
include/linux/hdlc.h

index 77f5ace58eaacb61a7265f50aec54dc7b3585c0e..929ca48131947c137d67b0924595d9dee99b8fca 100644 (file)
@@ -401,37 +401,6 @@ config FARSYNC
          should add "alias hdlcX farsync" to /etc/modules.conf for each
          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
        tristate "Frame relay DLCI support"
        depends on WAN
index 0854ade71ca9226200e88ac97e5474cff764501a..f47cd918ea565572fe914aa71a3376ba79ca2513 100644 (file)
@@ -14,7 +14,6 @@
  *    Moxa C101 User's Manual
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.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";
 
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
 #define C101_PAGE 0x1D00
 #define C101_DTR 0x1E00
 #define C101_SCA 0x1F00
@@ -95,7 +97,8 @@ static card_t **new_card = &first_card;
 #define winsize(card)             (C101_WINDOW_SIZE)
 #define win0base(card)            ((card)->win0base)
 #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)
@@ -116,9 +119,30 @@ static inline void openwin(card_t *card, u8 page)
 #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)
 {
-       u8 msci = get_msci(port);
        u8 rxs = port->rxs & CLK_BRG_MASK;
        u8 txs = port->txs & CLK_BRG_MASK;
 
@@ -145,8 +169,8 @@ static void c101_set_iface(port_t *port)
 
        port->rxs = rxs;
        port->txs = txs;
-       sca_out(rxs, msci + RXS, port);
-       sca_out(txs, msci + TXS, port);
+       sca_out(rxs, MSCI1_OFFSET + RXS, port);
+       sca_out(txs, MSCI1_OFFSET + TXS, port);
        sca_set_port(port);
 }
 
@@ -164,6 +188,17 @@ static int c101_open(struct net_device *dev)
        writeb(1, port->win0base + C101_DTR);
        sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
        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);
        return 0;
 }
@@ -189,9 +224,14 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        hdlc_device *hdlc = dev_to_hdlc(dev);
        port_t *port = hdlc_to_port(hdlc);
 
-#ifdef CONFIG_HDLC_DEBUG_RINGS
+#ifdef DEBUG_RINGS
        if (cmd == SIOCDEVPRIVATE) {
                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;
        }
 #endif
@@ -298,9 +338,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
 
        card->tx_ring_buffers = TX_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 */
 
        readb(card->win0base + C101_PAGE); /* Resets SCA? */
@@ -333,6 +370,13 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
        }
 
        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->next_card;
index cd3fcf86d6cfb83c6f88fbb49629efbbf798b6b5..3839662ff20148caa648dacd88ef71a97cc98f53 100644 (file)
@@ -217,12 +217,15 @@ typedef struct {
 #define ST0_RXRDY     0x01     /* RX ready */
 
 #define ST1_UDRN      0x80     /* MSCI TX underrun */
+#define ST1_CDCD      0x04     /* DCD level changed */
 
 #define ST3_CTS       0x08     /* modem input - /CTS */
 #define ST3_DCD       0x04     /* modem input - /DCD */
 
 #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_CDCD      0x04     /* DCD level changed */
 
 #define DCR_ABORT     0x01     /* Software abort command */
 #define DCR_CLEAR_EOF 0x02     /* Clear EOF interrupt */
index f85ae029f419e72c3e21acd99cfb0724c796d147..561216c1a4eb8cbc38ec1b513fa6b3c562a4f0a3 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/string.h>
-#include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -244,10 +243,14 @@ static void sca_init_sync_port(port_t *port)
                        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 */
 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);
        u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */
 
-       /* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n",
-          stat, sca_in(ILAR, card)); */
-
-       /* Reset MSCI TX underrun status bit */
-       sca_out(stat & ST1_UDRN, msci + ST1, card);
+       /* Reset MSCI TX underrun and CDCD status bit */
+       sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card);
 
        if (stat & ST1_UDRN) {
                port->hdlc.stats.tx_errors++; /* TX Underrun error detected */
                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)
        openwin(card, 0);
 #endif
        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);
        debug_frame(skb);
 #endif
@@ -560,25 +565,28 @@ static void sca_open(hdlc_device *hdlc)
 #endif
 
 /* 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
 */
 
+       hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc);
+
 #ifdef __HD64570_H
-       /* MSCI TX INT IRQ enable */
-       sca_out(IE0_TXINT, msci + IE0, card);
-       sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */
-       sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08),
-               IER0, card);
-       /* DMA IRQ enable */
+       /* MSCI TX INT and RX INT A IRQ enable */
+       sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card);
+       sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card);
+       sca_out(sca_in(IER0, card) | (phy_node(port) ? 0xC0 : 0x0C),
+               IER0, card); /* TXINT and RXINT */
+       /* enable DMA IRQ */
        sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
                IER1, card);
 #else
-       /* MSCI TX INT IRQ enable */
-       sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card);
+       /* MSCI TXINT and RXINTA interrupt enable */
+       sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0,
+                card);
        /* DMA & MSCI IRQ enable */
-       sca_outl(sca_in(IER0, card) |
-                (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card);
+       sca_outl(sca_inl(IER0, card) |
+                (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card);
 #endif
 
 #ifdef __HD64570_H
@@ -600,10 +608,23 @@ static void sca_open(hdlc_device *hdlc)
 static void sca_close(hdlc_device *hdlc)
 {
        port_t *port = hdlc_to_port(hdlc);
+       card_t* card = port_to_card(port);
 
        /* reset channel */
        netif_stop_queue(hdlc_to_dev(hdlc));
        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,
 
 
 
-#ifdef CONFIG_HDLC_DEBUG_RINGS
+#ifdef DEBUG_RINGS
 static void sca_dump_rings(hdlc_device *hdlc)
 {
        port_t *port = hdlc_to_port(hdlc);
@@ -651,30 +672,26 @@ static void sca_dump_rings(hdlc_device *hdlc)
        openwin(card, 0);
 #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) + EDAL, card),
-              sca_in(DSR_RX(phy_node(port)), card),
-              port->rxin,
+              sca_in(DSR_RX(phy_node(port)), card), port->rxin,
               sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in");
        for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++)
-               printk(" %02X",
-                      readb(&(desc_address(port, cnt, 0)->stat)));
+               printk(" %02X", 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",
               sca_ina(get_dmac_tx(port) + CDAL, card),
               sca_ina(get_dmac_tx(port) + EDAL, card),
-              sca_in(DSR_TX(phy_node(port)), card), port->txin,
-              port->txlast,
+              sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast,
               sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in");
 
        for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++)
-               printk(" %02X",
-                      readb(&(desc_address(port, cnt, 1)->stat)));
+               printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat)));
        printk("\n");
 
-       printk(KERN_ERR "MSCI: MD: %02x %02x %02x, "
+       printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, "
               "ST: %02x %02x %02x %02x"
 #ifdef __HD64572_H
               " %02x"
@@ -695,14 +712,18 @@ static void sca_dump_rings(hdlc_device *hdlc)
               sca_in(get_msci(port) + CST1, card));
 
 #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
 
 #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
        openwin(card, page); /* Restore original page */
 #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)
        desc = desc_address(port, port->txin + 1, 1);
        if (readb(&desc->stat)) { /* allow 1 packet gap */
                /* 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);
 #endif
                netif_stop_queue(dev);
@@ -731,7 +752,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
                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);
        debug_frame(skb);
 #endif
@@ -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(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_TX(0), card);
        sca_out(0, DSR_RX(1), card);
index f6234c5a64cc3b49021873c728c8d46712995014..c639524042c5738025f92736eafa20198bdff668 100644 (file)
@@ -9,7 +9,6 @@
  * as published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -24,6 +23,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/hdlc.h>
 
+#undef DEBUG_HARD_HEADER
 
 #define CISCO_MULTICAST                0x8F    /* Cisco multicast 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,
                             unsigned int len)
 {
        hdlc_header *data;
-#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+#ifdef DEBUG_HARD_HEADER
        printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
 #endif
 
@@ -182,7 +182,7 @@ static void cisco_rx(struct sk_buff *skb)
 
                case CISCO_KEEPALIVE_REQ:
                        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;
                                if (!hdlc->state.cisco.up) {
                                        u32 sec, min, hrs, days;
@@ -219,11 +219,12 @@ static void cisco_timer(unsigned long arg)
 {
        hdlc_device *hdlc = (hdlc_device*)arg;
 
-       if (hdlc->state.cisco.up &&
-           jiffies - hdlc->state.cisco.last_poll >=
+       if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >=
            hdlc->state.cisco.settings.timeout * HZ) {
                hdlc->state.cisco.up = 0;
                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,
@@ -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.up = 0;
@@ -249,14 +250,15 @@ static int cisco_open(hdlc_device *hdlc)
        hdlc->state.cisco.timer.function = cisco_timer;
        hdlc->state.cisco.timer.data = (unsigned long)hdlc;
        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);
+       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)
 
                hdlc_proto_detach(hdlc);
                memcpy(&hdlc->state.cisco.settings, &new_settings, size);
+               memset(&hdlc->proto, 0, sizeof(hdlc->proto));
 
-               hdlc->open = cisco_open;
-               hdlc->stop = cisco_close;
-               hdlc->netif_rx = cisco_rx;
-               hdlc->type_trans = cisco_type_trans;
-               hdlc->proto = IF_PROTO_CISCO;
+               hdlc->proto.start = cisco_start;
+               hdlc->proto.stop = cisco_stop;
+               hdlc->proto.netif_rx = cisco_rx;
+               hdlc->proto.type_trans = cisco_type_trans;
+               hdlc->proto.id = IF_PROTO_CISCO;
                dev->hard_start_xmit = hdlc->xmit;
                dev->hard_header = cisco_hard_header;
                dev->type = ARPHRD_CISCO;
index c0b5f1821043f3a4b0e553079c75c58f082d1ab2..45cbde46c34f3bf6275c46d20e5f432468c90a92 100644 (file)
@@ -9,7 +9,9 @@
  * 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"
          0,x -> 1,1 if "link reliable" when sending FULL STATUS
 
  (active)    -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create"
              -> 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/kernel.h>
 #include <linux/slab.h>
 #include <linux/etherdevice.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;
 
-       while(pvc) {
+       while (pvc) {
                if (pvc->dlci == dlci)
                        return pvc;
                if (pvc->dlci > 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;
 
-       while(*pvc_p) {
+       while (*pvc_p) {
                if ((*pvc_p)->dlci == dlci)
                        return *pvc_p;
                if ((*pvc_p)->dlci > dlci)
-                       break;  /* the listed is sorted */
+                       break;  /* the list is sorted */
                pvc_p = &(*pvc_p)->next;
        }
 
@@ -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;
 }
 
 
-__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;
 
-       while(*pvc_p) {
+       while (*pvc_p) {
                if (!pvc_is_used(*pvc_p)) {
                        pvc_device *pvc = *pvc_p;
                        *pvc_p = pvc->next;
@@ -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)
                return &pvc->ether;
@@ -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;
        *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,
-                              int active, int new)
+static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new)
 {
-       status[0] = (dlci>>4) & 0x3F;
-       status[1] = ((dlci<<3) & 0x78) | 0x80;
+       status[0] = (dlci >> 4) & 0x3F;
+       status[1] = ((dlci << 3) & 0x78) | 0x80;
        status[2] = 0x80;
 
        if (new)
@@ -138,7 +250,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
        u16 head_len;
        struct sk_buff *skb = *skb_p;
 
-       switch(skb->protocol) {
+       switch (skb->protocol) {
        case __constant_ntohs(ETH_P_IP):
                head_len = 4;
                skb_push(skb, head_len);
@@ -204,8 +316,9 @@ static int pvc_open(struct net_device *dev)
 
        if (pvc->open_count++ == 0) {
                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;
        }
        return 0;
@@ -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 *)
                ((char *)dev + sizeof(struct net_device));
@@ -402,6 +515,7 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
                        /* ifconfig PVC up */
                        if (pvc->open_count && !pvc->state.active &&
                            pvc->state.exist && !pvc->state.new) {
+                               pvc_carrier(1, pvc);
                                pvc->state.active = 1;
                                fr_log_dlci_active(pvc);
                        }
@@ -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)
 {
        hdlc_device *hdlc = (hdlc_device*)arg;
@@ -449,22 +598,9 @@ static void fr_timer(unsigned long arg)
        }
 
        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),
                       reliable ? "" : "un");
-
-               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;
-                       }
-               }
+               fr_set_link_state(reliable, hdlc);
        }
 
        if (hdlc->state.fr.settings.dce)
@@ -636,6 +772,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
                            !pvc->state.exist) {
                                pvc->state.new = new;
                                pvc->state.active = active;
+                               pvc_carrier(active, pvc);
                                fr_log_dlci_active(pvc);
                        }
                }
@@ -647,6 +784,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
 
        while (pvc) {
                if (pvc->state.deleted && pvc->state.exist) {
+                       pvc_carrier(0, pvc);
                        pvc->state.active = pvc->state.new = 0;
                        pvc->state.exist = 0;
                        fr_log_dlci_active(pvc);
@@ -699,7 +837,7 @@ static void fr_rx(struct sk_buff *skb)
 
        pvc = find_pvc(hdlc, dlci);
        if (!pvc) {
-#ifdef CONFIG_HDLC_DEBUG_PKT
+#ifdef DEBUG_PKT
                printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
                       hdlc_to_name(hdlc), dlci);
 #endif
@@ -708,7 +846,7 @@ static void fr_rx(struct sk_buff *skb)
        }
 
        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),
                       dlci, fh->fecn ? "N" : "FF");
 #endif
@@ -716,7 +854,7 @@ static void fr_rx(struct sk_buff *skb)
        }
 
        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),
                       dlci, fh->becn ? "N" : "FF");
 #endif
@@ -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 (netif_carrier_ok(&hdlc->netdev))
+                       netif_carrier_off(&hdlc->netdev);
                hdlc->state.fr.last_poll = 0;
                hdlc->state.fr.reliable = 0;
                hdlc->state.fr.dce_changed = 1;
@@ -806,9 +949,19 @@ static int fr_open(hdlc_device *hdlc)
                hdlc->state.fr.timer.data = (unsigned long)hdlc;
                add_timer(&hdlc->state.fr.timer);
        } 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)
 {
        pvc_device *pvc = hdlc->state.fr.first_pvc;
 
-       if (hdlc->state.fr.settings.lmi != LMI_NONE)
-               del_timer_sync(&hdlc->state.fr.timer);
-
-       while(pvc) {            /* Shutdown all PVCs for this FRAD */
+       while (pvc) {           /* Shutdown all PVCs for this FRAD */
                if (pvc->main)
                        dev_close(pvc->main);
                if (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;
        }
 }
 
 
+
 static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
 {
        pvc_device *pvc = NULL;
@@ -900,6 +1048,7 @@ static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
                return -EIO;
        }
 
+       dev->destructor = (void (*)(struct net_device *)) kfree;
        *get_dev_p(pvc, type) = dev;
        if (!used) {
                hdlc->state.fr.dce_changed = 1;
@@ -924,8 +1073,7 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
        if (dev->flags & IFF_UP)
                return -EBUSY;          /* PVC in use */
 
-       unregister_netdevice(dev);
-       kfree(dev);
+       unregister_netdevice(dev); /* the destructor will kfree(dev) */
        *get_dev_p(pvc, type) = NULL;
 
        if (!pvc_is_used(pvc)) {
@@ -940,24 +1088,24 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
 
 static void fr_destroy(hdlc_device *hdlc)
 {
-       pvc_device *pvc = hdlc->state.fr.first_pvc;
-       while(pvc) {
+       pvc_device *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;
-               if (pvc->main) {
+               if (pvc->main)  /* the destructor will kfree(main + ether) */
                        unregister_netdevice(pvc->main);
-                       kfree(pvc->main);
-               }
-               if (pvc->ether) {
+
+               if (pvc->ether)
                        unregister_netdevice(pvc->ether);
-                       kfree(pvc->ether);
-               }
+
                kfree(pvc);
                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)
                if (result)
                        return result;
 
-               if (hdlc->proto != IF_PROTO_FR) {
+               if (hdlc->proto.id != IF_PROTO_FR) {
                        hdlc_proto_detach(hdlc);
                        hdlc->state.fr.first_pvc = NULL;
                        hdlc->state.fr.dce_pvc_count = 0;
                }
                memcpy(&hdlc->state.fr.settings, &new_settings, size);
-
-               hdlc->open = fr_open;
-               hdlc->stop = fr_close;
-               hdlc->netif_rx = fr_rx;
-               hdlc->type_trans = NULL;
-               hdlc->proto_detach = fr_destroy;
-               hdlc->proto = IF_PROTO_FR;
+               memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+
+               hdlc->proto.close = fr_close;
+               hdlc->proto.start = fr_start;
+               hdlc->proto.stop = fr_stop;
+               hdlc->proto.detach = fr_destroy;
+               hdlc->proto.netif_rx = fr_rx;
+               hdlc->proto.id = IF_PROTO_FR;
                dev->hard_start_xmit = hdlc->xmit;
                dev->hard_header = NULL;
                dev->type = ARPHRD_FRAD;
index fd0b3dfeeb19c7076c3a39cf48211b19a026c40f..4d150428ec8938a8ac2e9ee8341b2379b5a3aa4d 100644 (file)
@@ -33,7 +33,9 @@
 #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)
@@ -57,8 +59,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
                    struct packet_type *p)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
-       if (hdlc->netif_rx)
-               hdlc->netif_rx(skb);
+       if (hdlc->proto.netif_rx)
+               hdlc->proto.netif_rx(skb);
        else {
                hdlc->stats.rx_dropped++; /* Shouldn't happen */
                dev_kfree_skb(skb);
@@ -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
 #define hdlc_raw_ioctl(hdlc, ifr)      -ENOSYS
 #endif
@@ -111,7 +210,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                break;
 
        default:
-               proto = hdlc->proto;
+               proto = hdlc->proto.id;
        }
 
        switch(proto) {
@@ -141,11 +240,14 @@ int register_hdlc_device(hdlc_device *hdlc)
 
        dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 
-       hdlc->proto = -1;
-       hdlc->proto_detach = NULL;
+       hdlc->proto.id = -1;
+       hdlc->proto.detach = NULL;
+       hdlc->carrier = 1;
+       hdlc->open = 0;
+       spin_lock_init(&hdlc->state_lock);
 
        result = dev_alloc_name(dev, "hdlc%d");
-       if (result<0)
+       if (result < 0)
                return result;
 
        result = register_netdev(dev);
@@ -171,6 +273,9 @@ MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
 MODULE_DESCRIPTION("HDLC support module");
 MODULE_LICENSE("GPL v2");
 
+EXPORT_SYMBOL(hdlc_open);
+EXPORT_SYMBOL(hdlc_close);
+EXPORT_SYMBOL(hdlc_set_carrier);
 EXPORT_SYMBOL(hdlc_ioctl);
 EXPORT_SYMBOL(register_hdlc_device);
 EXPORT_SYMBOL(unregister_hdlc_device);
index 1d93f3ac14edf9469c700b79f71cb6a12c49e313..7eeec068d5a29b6fa237e9e5080c74a917cb1f19 100644 (file)
@@ -9,7 +9,6 @@
  * as published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -99,12 +98,12 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
                        return result;
 
                hdlc_proto_detach(hdlc);
+               memset(&hdlc->proto, 0, sizeof(hdlc->proto));
 
-               hdlc->open = ppp_open;
-               hdlc->stop = ppp_close;
-               hdlc->netif_rx = NULL;
-               hdlc->type_trans = ppp_type_trans;
-               hdlc->proto = IF_PROTO_PPP;
+               hdlc->proto.open = ppp_open;
+               hdlc->proto.close = ppp_close;
+               hdlc->proto.type_trans = ppp_type_trans;
+               hdlc->proto.id = IF_PROTO_PPP;
                dev->hard_start_xmit = hdlc->xmit;
                dev->hard_header = NULL;
                dev->type = ARPHRD_PPP;
index 7bc89d695ecd1e5892007402c58fd8db0134f638..6c0aecc442fad5e37d540fa3b558d2fdad19cb72 100644 (file)
@@ -9,7 +9,6 @@
  * as published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -75,12 +74,10 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
 
                hdlc_proto_detach(hdlc);
                memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+               memset(&hdlc->proto, 0, sizeof(hdlc->proto));
 
-               hdlc->open = NULL;
-               hdlc->stop = NULL;
-               hdlc->netif_rx = NULL;
-               hdlc->type_trans = raw_type_trans;
-               hdlc->proto = IF_PROTO_HDLC;
+               hdlc->proto.type_trans = raw_type_trans;
+               hdlc->proto.id = IF_PROTO_HDLC;
                dev->hard_start_xmit = hdlc->xmit;
                dev->hard_header = NULL;
                dev->type = ARPHRD_RAWHDLC;
index 90c69addb6d590650bbcf739ea053edc8505fdc5..d91a4fc87730ff2854ee0a974a350b10376f5fba 100644 (file)
@@ -9,7 +9,6 @@
  * as published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -89,12 +88,10 @@ int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
 
                hdlc_proto_detach(hdlc);
                memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+               memset(&hdlc->proto, 0, sizeof(hdlc->proto));
 
-               hdlc->open = NULL;
-               hdlc->stop = NULL;
-               hdlc->netif_rx = NULL;
-               hdlc->type_trans = eth_type_trans;
-               hdlc->proto = IF_PROTO_HDLC_ETH;
+               hdlc->proto.type_trans = eth_type_trans;
+               hdlc->proto.id = IF_PROTO_HDLC_ETH;
                dev->hard_start_xmit = eth_tx;
                old_ch_mtu = dev->change_mtu;
                old_qlen = dev->tx_queue_len;
index 53b118c5f8d5e311e5e4159aeecb406fa5ae96d2..7433c966028e7cc19d9ff04faefec621df692bf0 100644 (file)
@@ -9,7 +9,6 @@
  * as published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -199,12 +198,13 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
                        return result;
 
                hdlc_proto_detach(hdlc);
+               memset(&hdlc->proto, 0, sizeof(hdlc->proto));
 
-               hdlc->open = x25_open;
-               hdlc->stop = x25_close;
-               hdlc->netif_rx = x25_rx;
-               hdlc->type_trans = NULL;
-               hdlc->proto = IF_PROTO_X25;
+               hdlc->proto.open = x25_open;
+               hdlc->proto.close = x25_close;
+               hdlc->proto.netif_rx = x25_rx;
+               hdlc->proto.type_trans = NULL;
+               hdlc->proto.id = IF_PROTO_X25;
                dev->hard_start_xmit = x25_xmit;
                dev->hard_header = NULL;
                dev->type = ARPHRD_X25;
index 53e0701da0ff23ec13e33345ed61be9f1cd5f74e..7e50bc51f0212772f4cad3814314c6842a6f6f4d 100644 (file)
@@ -16,7 +16,6 @@
  *    SDL Inc. PPP/HDLC/CISCO driver
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.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";
 
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
 #define USE_WINDOWSIZE 16384
 #define USE_BUS16BITS 1
 #define CLOCK_BASE 9830400     /* 9.8304 MHz */
@@ -48,6 +50,7 @@ static const char* devname = "RISCom/N2";
 #endif
 #define N2_IOPORTS 0x10
 #define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
 #define MAX_TX_BUFFERS 10
 
 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)
        hdlc_device *hdlc = dev_to_hdlc(dev);
        port_t *port = hdlc_to_port(hdlc);
 
-#ifdef CONFIG_HDLC_DEBUG_RINGS
+#ifdef DEBUG_RINGS
        if (cmd == SIOCDEVPRIVATE) {
                sca_dump_rings(hdlc);
                return 0;
@@ -415,7 +418,7 @@ static int __init n2_run(unsigned long io, unsigned long irq,
        card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) *
                (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,
               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,
                SET_MODULE_OWNER(dev);
                dev->irq = irq;
                dev->mem_start = winbase;
-               dev->mem_end = winbase + USE_WINDOWSIZE-1;
+               dev->mem_end = winbase + USE_WINDOWSIZE - 1;
                dev->tx_queue_len = 50;
                dev->do_ioctl = n2_ioctl;
                dev->open = n2_open;
index 6b89e9c85f9b25354b9aa8525d61025f75ed77bd..94c967d945e7b23e3afc56f9826b1cf31fe95b23 100644 (file)
@@ -42,6 +42,9 @@
 #define LMI_ANSI               2 /* ANSI Annex D */
 #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__
 
 #include <net/syncppp.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 */
        u8 address;
@@ -177,14 +108,25 @@ typedef struct hdlc_device_struct {
 
 
        /* Things below are for HDLC layer internal use only */
-       int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
-       int (*open)(struct hdlc_device_struct *hdlc);
-       void (*stop)(struct hdlc_device_struct *hdlc);
-       void (*proto_detach)(struct hdlc_device_struct *hdlc);
-       void (*netif_rx)(struct sk_buff *skb);
-       unsigned short (*type_trans)(struct sk_buff *skb,
-                                    struct net_device *dev);
-       int proto;              /* IF_PROTO_HDLC/CISCO/FR/etc. */
+       struct {
+               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 (*detach)(struct hdlc_device_struct *hdlc);
+               void (*netif_rx)(struct sk_buff *skb);
+               unsigned short (*type_trans)(struct sk_buff *skb,
+                                            struct net_device *dev);
+               int id;         /* IF_PROTO_HDLC/CISCO/FR/etc. */
+       }proto;
+
+       int carrier;
+       int open;
+       spinlock_t state_lock;
 
        union {
                struct {
@@ -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)
 {
        int i;
 
-       for (i=0; i<skb->len; i++) {
+       for (i=0; i < skb->len; i++) {
                if (i == 100) {
                        printk("...\n");
                        return;
@@ -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 */
-static __inline__ int hdlc_open(hdlc_device *hdlc)
-{
-       if (hdlc->proto == -1)
-               return -ENOSYS;         /* no protocol attached */
-
-       if (hdlc->open)
-               return hdlc->open(hdlc);
-       return 0;
-}
-
-
+int hdlc_open(hdlc_device *hdlc);
 /* Must be called by hardware driver when HDLC device is being closed */
-static __inline__ void hdlc_close(hdlc_device *hdlc)
-{
-       if (hdlc->stop)
-               hdlc->stop(hdlc);
-}
-
+void hdlc_close(hdlc_device *hdlc);
+/* Called by hardware driver when DCD line level changes */
+void hdlc_set_carrier(int on, hdlc_device *hdlc);
 
 /* May be used by hardware driver to gain control over HDLC device */
 static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
 {
-       if (hdlc->proto_detach)
-               hdlc->proto_detach(hdlc);
-       hdlc->proto_detach = NULL;
+       if (hdlc->proto.detach)
+               hdlc->proto.detach(hdlc);
+       hdlc->proto.detach = NULL;
 }
 
 
@@ -335,8 +248,8 @@ static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb,
                                                 struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(skb->dev);
-       if (hdlc->type_trans)
-               return hdlc->type_trans(skb, dev);
+       if (hdlc->proto.type_trans)
+               return hdlc->proto.type_trans(skb, dev);
        else
                return __constant_htons(ETH_P_HDLC);
 }