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
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
......
......@@ -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>
......@@ -31,9 +30,12 @@
#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;
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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;
......
......@@ -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
......@@ -17,9 +19,16 @@
(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>
......@@ -36,12 +45,96 @@
#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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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>
......@@ -34,9 +33,12 @@
#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;
......
......@@ -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__
......@@ -50,78 +53,6 @@
#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);
}
......
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