Commit 94e5a9e0 authored by Krzysztof Halasa's avatar Krzysztof Halasa Committed by Jeff Garzik

A bunch of HDLC (WAN driver) bug fixes, plus much improves

device and protocol attach/detach support.

Overall, this is in preparation for update of HDLC API
parent ac51726a
/*
* Moxa C101 synchronous serial card driver for Linux
*
* Copyright (C) 2000-2001 Krzysztof Halasa <khc@pm.waw.pl>
* Copyright (C) 2000-2002 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
......@@ -31,7 +31,7 @@
#include "hd64570.h"
static const char* version = "Moxa C101 driver version: 1.09";
static const char* version = "Moxa C101 driver version: 1.10";
static const char* devname = "C101";
#define C101_PAGE 0x1D00
......@@ -107,18 +107,13 @@ static inline void openwin(card_t *card, u8 page)
#include "hd6457x.c"
static int c101_set_iface(port_t *port)
static void c101_set_iface(port_t *port)
{
u8 msci = get_msci(port);
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
switch(port->settings.clock_type) {
case CLOCK_EXT:
rxs |= CLK_LINE_RX; /* RXC input */
txs |= CLK_LINE_TX; /* TXC input */
break;
case CLOCK_INT:
rxs |= CLK_BRG_RX; /* TX clock */
txs |= CLK_RXCLK_TX; /* BRG output */
......@@ -134,8 +129,9 @@ static int c101_set_iface(port_t *port)
txs |= CLK_RXCLK_TX; /* RX clock */
break;
default:
return -EINVAL;
default: /* EXTernal clock */
rxs |= CLK_LINE_RX; /* RXC input */
txs |= CLK_LINE_TX; /* TXC input */
}
port->rxs = rxs;
......@@ -143,7 +139,6 @@ static int c101_set_iface(port_t *port)
sca_out(rxs, msci + RXS, port);
sca_out(txs, msci + TXS, port);
sca_set_port(port);
return 0;
}
......@@ -159,7 +154,8 @@ 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);
return c101_set_iface(port);
c101_set_iface(port);
return 0;
}
......@@ -181,6 +177,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
union line_settings *line = &ifr->ifr_settings->ifs_line;
const size_t size = sizeof(sync_serial_settings);
sync_serial_settings new_line;
hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
......@@ -204,10 +201,21 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if(!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&port->settings, &line->sync, size))
if (copy_from_user(&new_line, &line->sync, size))
return -EFAULT;
/* FIXME - put sanity checks here */
return c101_set_iface(port);
if (new_line.clock_type != CLOCK_EXT &&
new_line.clock_type != CLOCK_TXFROMRX &&
new_line.clock_type != CLOCK_INT &&
new_line.clock_type != CLOCK_TXINT)
return -EINVAL; /* No such clock setting */
if (new_line.loopback != 0 && new_line.loopback != 1)
return -EINVAL;
memcpy(&port->settings, &new_line, size); /* Update settings */
c101_set_iface(port);
return 0;
default:
return hdlc_ioctl(dev, ifr, cmd);
......
......@@ -291,9 +291,9 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin)
#endif
port->hdlc.stats.rx_packets++;
port->hdlc.stats.rx_bytes += skb->len;
skb->dev->last_rx = jiffies;
skb->mac.raw = skb->data;
skb->dev = hdlc_to_dev(&port->hdlc);
skb->dev->last_rx = jiffies;
skb->protocol = htons(ETH_P_HDLC);
netif_rx(skb);
}
......
......@@ -249,6 +249,7 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
{
cisco_proto *cisco_s = &ifr->ifr_settings->ifs_hdlc.cisco;
const size_t size = sizeof(cisco_proto);
cisco_proto new_settings;
struct net_device *dev = hdlc_to_dev(hdlc);
int result;
......@@ -266,17 +267,20 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
if(dev->flags & IFF_UP)
return -EBUSY;
if (copy_from_user(&hdlc->state.cisco.settings, cisco_s, size))
if (copy_from_user(&new_settings, cisco_s, size))
return -EFAULT;
/* FIXME - put sanity checks here */
hdlc_detach(hdlc);
if (new_settings.interval < 1 ||
new_settings.timeout < 2)
return -EINVAL;
result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
if (result) {
hdlc->proto = -1;
if (result)
return result;
}
hdlc_proto_detach(hdlc);
memcpy(&hdlc->state.cisco.settings, &new_settings, size);
hdlc->open = cisco_open;
hdlc->stop = cisco_close;
......
......@@ -602,13 +602,15 @@ static void fr_rx(struct sk_buff *skb)
}
if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) {
u16 oui = ntohl(*(u16*)(data + 6));
u16 pid = ntohl(*(u16*)(data + 8));
u16 oui = ntohs(*(u16*)(data + 6));
u16 pid = ntohs(*(u16*)(data + 8));
skb_pull(skb, 10);
switch ((((u32)oui) << 16) | pid) {
case ETH_P_ARP: /* routed frame with SNAP */
case ETH_P_IPX:
case ETH_P_IP: /* a long variant */
case ETH_P_IPV6:
skb->protocol = htons(pid);
break;
......@@ -762,7 +764,7 @@ static void fr_destroy(hdlc_device *hdlc)
pvc_device *pvc = hdlc->state.fr.first_pvc;
while(pvc) {
pvc_device *next = pvc->next;
unregister_netdevice(&pvc->netdev);
unregister_netdev(&pvc->netdev);
kfree(pvc);
pvc = next;
}
......@@ -778,6 +780,7 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
{
fr_proto *fr_s = &ifr->ifr_settings->ifs_hdlc.fr;
const size_t size = sizeof(fr_proto);
fr_proto new_settings;
struct net_device *dev = hdlc_to_dev(hdlc);
fr_proto_pvc pvc;
int result;
......@@ -796,26 +799,40 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
if(dev->flags & IFF_UP)
return -EBUSY;
if (copy_from_user(&hdlc->state.fr.settings, fr_s, size))
if (copy_from_user(&new_settings, fr_s, size))
return -EFAULT;
/* FIXME - put sanity checks here */
if (hdlc->proto != IF_PROTO_FR) {
hdlc_detach(hdlc);
hdlc->state.fr.first_pvc = NULL;
hdlc->state.fr.pvc_count = 0;
}
if (new_settings.lmi == LMI_DEFAULT)
new_settings.lmi = LMI_ANSI;
if ((new_settings.lmi != LMI_NONE &&
new_settings.lmi != LMI_ANSI &&
new_settings.lmi != LMI_CCITT) ||
new_settings.t391 < 1 ||
new_settings.t392 < 2 ||
new_settings.n391 < 1 ||
new_settings.n392 < 1 ||
new_settings.n393 < new_settings.n392 ||
new_settings.n393 > 32 ||
(new_settings.dce != 0 &&
new_settings.dce != 1))
return -EINVAL;
result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
if (result) {
hdlc->proto = -1;
if (result)
return result;
if (hdlc->proto != IF_PROTO_FR) {
hdlc_proto_detach(hdlc);
hdlc->state.fr.first_pvc = NULL;
hdlc->state.fr.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->detach = fr_destroy;
hdlc->proto_detach = fr_destroy;
hdlc->proto = IF_PROTO_FR;
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = fr_hard_header;
......
......@@ -38,7 +38,7 @@
#include <linux/hdlc.h>
static const char* version = "HDLC support module revision 1.08";
static const char* version = "HDLC support module revision 1.10";
static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
......@@ -66,6 +66,26 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
}
#ifndef CONFIG_HDLC_RAW
#define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_PPP
#define hdlc_ppp_ioctl(hdlc, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_CISCO
#define hdlc_cisco_ioctl(hdlc, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_FR
#define hdlc_fr_ioctl(hdlc, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_X25
#define hdlc_x25_ioctl(hdlc, ifr) -ENOSYS
#endif
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
......@@ -89,22 +109,12 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
switch(proto) {
#ifdef CONFIG_HDLC_RAW
case IF_PROTO_HDLC: return hdlc_raw_ioctl(hdlc, ifr);
#endif
#ifdef CONFIG_HDLC_PPP
case IF_PROTO_PPP: return hdlc_ppp_ioctl(hdlc, ifr);
#endif
#ifdef CONFIG_HDLC_CISCO
case IF_PROTO_CISCO: return hdlc_cisco_ioctl(hdlc, ifr);
#endif
#ifdef CONFIG_HDLC_FR
case IF_PROTO_FR: return hdlc_fr_ioctl(hdlc, ifr);
#endif
#ifdef CONFIG_HDLC_X25
case IF_PROTO_X25: return hdlc_x25_ioctl(hdlc, ifr);
#endif
default: return -ENOSYS;
default: return -EINVAL;
}
}
......@@ -125,7 +135,7 @@ int register_hdlc_device(hdlc_device *hdlc)
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
hdlc->proto = -1;
hdlc->detach = NULL;
hdlc->proto_detach = NULL;
result = dev_alloc_name(dev, "hdlc%d");
if (result<0)
......@@ -143,7 +153,7 @@ int register_hdlc_device(hdlc_device *hdlc)
void unregister_hdlc_device(hdlc_device *hdlc)
{
hdlc_detach(hdlc);
hdlc_proto_detach(hdlc);
unregister_netdev(hdlc_to_dev(hdlc));
MOD_DEC_USE_COUNT;
......
......@@ -96,13 +96,11 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
/* no settable parameters */
hdlc_detach(hdlc);
result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
if (result) {
hdlc->proto = -1;
if (result)
return result;
}
hdlc_proto_detach(hdlc);
hdlc->open = ppp_open;
hdlc->stop = ppp_close;
......
......@@ -39,35 +39,40 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
{
raw_hdlc_proto *raw_s = &ifr->ifr_settings->ifs_hdlc.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto);
raw_hdlc_proto new_settings;
struct net_device *dev = hdlc_to_dev(hdlc);
int result;
switch (ifr->ifr_settings->type) {
case IF_GET_PROTO:
ifr->ifr_settings->type = IF_PROTO_HDLC;
if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
return -EFAULT;
return 0;
case IF_PROTO_HDLC:
if(!capable(CAP_NET_ADMIN))
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if(dev->flags & IFF_UP)
if (dev->flags & IFF_UP)
return -EBUSY;
if (copy_from_user(&hdlc->state.raw_hdlc.settings, raw_s, size))
if (copy_from_user(&new_settings, raw_s, size))
return -EFAULT;
if (new_settings.encoding == ENCODING_DEFAULT)
new_settings.encoding = ENCODING_NRZ;
/* FIXME - put sanity checks here */
hdlc_detach(hdlc);
if (new_settings.parity == PARITY_DEFAULT)
new_settings.parity = PARITY_NONE;
result=hdlc->attach(hdlc, hdlc->state.raw_hdlc.settings.encoding,
hdlc->state.raw_hdlc.settings.parity);
if (result) {
hdlc->proto = -1;
result = hdlc->attach(hdlc, new_settings.encoding,
new_settings.parity);
if (result)
return result;
}
hdlc_proto_detach(hdlc);
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
hdlc->open = NULL;
hdlc->stop = NULL;
......
......@@ -196,13 +196,11 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
if(dev->flags & IFF_UP)
return -EBUSY;
hdlc_detach(hdlc);
result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
if (result) {
hdlc->proto = -1;
if (result)
return result;
}
hdlc_proto_detach(hdlc);
hdlc->open = x25_open;
hdlc->stop = x25_close;
......
/*
* SDL Inc. RISCom/N2 synchronous serial card driver for Linux
*
* Copyright (C) 1998-2001 Krzysztof Halasa <khc@pm.waw.pl>
* Copyright (C) 1998-2002 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
......@@ -35,7 +35,7 @@
#include "hd64570.h"
static const char* version = "SDL RISCom/N2 driver version: 1.09";
static const char* version = "SDL RISCom/N2 driver version: 1.10";
static const char* devname = "RISCom/N2";
#define USE_WINDOWSIZE 16384
......@@ -159,7 +159,7 @@ static __inline__ void close_windows(card_t *card)
static int n2_set_iface(port_t *port)
static void n2_set_iface(port_t *port)
{
card_t *card = port->card;
int io = card->io;
......@@ -169,12 +169,6 @@ static int n2_set_iface(port_t *port)
u8 txs = port->txs & CLK_BRG_MASK;
switch(port->settings.clock_type) {
case CLOCK_EXT:
mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
rxs |= CLK_LINE_RX; /* RXC input */
txs |= CLK_LINE_TX; /* TXC input */
break;
case CLOCK_INT:
mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
rxs |= CLK_BRG_RX; /* BRG output */
......@@ -193,8 +187,10 @@ static int n2_set_iface(port_t *port)
txs |= CLK_RXCLK_TX; /* RX clock */
break;
default:
return -EINVAL;
default: /* Clock EXTernal */
mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
rxs |= CLK_LINE_RX; /* RXC input */
txs |= CLK_LINE_TX; /* TXC input */
}
outb(mcr, io + N2_MCR);
......@@ -203,7 +199,6 @@ static int n2_set_iface(port_t *port)
sca_out(rxs, msci + RXS, card);
sca_out(txs, msci + TXS, card);
sca_set_port(port);
return 0;
}
......@@ -226,7 +221,8 @@ static int n2_open(struct net_device *dev)
outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
sca_open(hdlc);
return n2_set_iface(port);
n2_set_iface(port);
return 0;
}
......@@ -252,6 +248,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
union line_settings *line = &ifr->ifr_settings->ifs_line;
const size_t size = sizeof(sync_serial_settings);
sync_serial_settings new_line;
hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
......@@ -275,10 +272,21 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if(!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&port->settings, &line->sync, size))
if (copy_from_user(&new_line, &line->sync, size))
return -EFAULT;
/* FIXME - put sanity checks here */
return n2_set_iface(port);
if (new_line.clock_type != CLOCK_EXT &&
new_line.clock_type != CLOCK_TXFROMRX &&
new_line.clock_type != CLOCK_INT &&
new_line.clock_type != CLOCK_TXINT)
return -EINVAL; /* No such clock setting */
if (new_line.loopback != 0 && new_line.loopback != 1)
return -EINVAL;
memcpy(&port->settings, &new_line, size); /* Update settings */
n2_set_iface(port);
return 0;
default:
return hdlc_ioctl(dev, ifr, cmd);
......
......@@ -12,14 +12,16 @@
#ifndef __HDLC_H
#define __HDLC_H
#define CLOCK_DEFAULT 0 /* Default (current) setting */
#define GENERIC_HDLC_VERSION 3 /* For synchronization with sethdlc utility */
#define CLOCK_DEFAULT 0 /* Default setting */
#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
#define ENCODING_DEFAULT 0 /* Default (current) setting */
#define ENCODING_DEFAULT 0 /* Default setting */
#define ENCODING_NRZ 1
#define ENCODING_NRZI 2
#define ENCODING_FM_MARK 3
......@@ -27,7 +29,7 @@
#define ENCODING_MANCHESTER 5
#define PARITY_DEFAULT 0 /* Default (current) setting */
#define PARITY_DEFAULT 0 /* Default setting */
#define PARITY_NONE 1 /* No parity */
#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
......@@ -36,13 +38,11 @@
#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
#define LMI_DEFAULT 0 /* Default (current) setting */
#define LMI_DEFAULT 0 /* Default setting */
#define LMI_NONE 1 /* No LMI, all PVCs are static */
#define LMI_ANSI 2 /* ANSI Annex D */
#define LMI_CCITT 3 /* ITU-T Annex A */
/* PPP doesn't need any info now - supply length = 0 to ioctl */
#ifdef __KERNEL__
......@@ -178,7 +178,7 @@ typedef struct hdlc_device_struct {
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 (*detach)(struct hdlc_device_struct *hdlc);
void (*proto_detach)(struct hdlc_device_struct *hdlc);
void (*netif_rx)(struct sk_buff *skb);
int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */
......@@ -337,11 +337,11 @@ static __inline__ void hdlc_close(hdlc_device *hdlc)
/* May be used by hardware driver to gain control over HDLC device */
static __inline__ void hdlc_detach(hdlc_device *hdlc)
static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
{
if (hdlc->detach)
hdlc->detach(hdlc);
hdlc->detach = NULL;
if (hdlc->proto_detach)
hdlc->proto_detach(hdlc);
hdlc->proto_detach = NULL;
}
......
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