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.
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
* 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
#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)
#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;
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);
}
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;
}
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
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? */
}
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;
#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 */
#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>
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)
{
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
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
#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
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
}
-#ifdef CONFIG_HDLC_DEBUG_RINGS
+#ifdef DEBUG_RINGS
static void sca_dump_rings(hdlc_device *hdlc)
{
port_t *port = hdlc_to_port(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"
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 */
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);
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
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);
* as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#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 */
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
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;
{
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,
-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;
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);
}
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;
* 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)
}
-__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;
}
}
-__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;
}
-__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;
}
-__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)
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);
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;
}
-__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));
/* 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);
}
+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;
}
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)
!pvc->state.exist) {
pvc->state.new = new;
pvc->state.active = active;
+ pvc_carrier(active, pvc);
fr_log_dlci_active(pvc);
}
}
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);
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
}
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
}
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
-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;
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);
}
{
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;
return -EIO;
}
+ dev->destructor = (void (*)(struct net_device *)) kfree;
*get_dev_p(pvc, type) = dev;
if (!used) {
hdlc->state.fr.dce_changed = 1;
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)) {
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;
}
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;
#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)
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);
}
+
+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
break;
default:
- proto = hdlc->proto;
+ proto = hdlc->proto.id;
}
switch(proto) {
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);
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);
* as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
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;
* as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
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;
* as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
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;
* as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
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;
* 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 */
#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 */
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;
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);
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;
#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;
/* 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 {
}
-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;
}
-
/* 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;
}
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);
}