diff options
Diffstat (limited to 'drivers/net/hamradio/yam.c')
-rw-r--r-- | drivers/net/hamradio/yam.c | 547 |
1 files changed, 283 insertions, 264 deletions
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 836414a53..97f12491d 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1,6 +1,5 @@ -/*****************************************************************************/ - -/* +/***************************************************************************** + * * yam.c -- YAM radio modem driver. * * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr) @@ -26,22 +25,25 @@ * * * History: - * 0.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3 - * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration - * 0.2 F6FBB 08.06.98 Added delay after FPGA programming - * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2 - * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistance - * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics - * 0.6 F6FBB 25.08.98 Added 1200Bds format - * 0.7 F6FBB 12.09.98 Added to the kernel configuration - * 0.8 F6FBB 14.10.98 Fixed slottime/persistance timing bug - */ - -/*****************************************************************************/ + * 0.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3 + * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration + * 0.2 F6FBB 08.06.98 Added delay after FPGA programming + * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2 + * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistance + * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics + * 0.6 F6FBB 25.08.98 Added 1200Bds format + * 0.7 F6FBB 12.09.98 Added to the kernel configuration + * 0.8 F6FBB 14.10.98 Fixed slottime/persistance timing bug + * 0.9 DG1KJD 10.03.00 Fixed media access and converted to new DDI + * + *****************************************************************************/ #include <linux/config.h> -#include <linux/module.h> +#include <linux/version.h> #include <linux/types.h> +#include <linux/module.h> +#include <linux/init.h> +#include <asm/uaccess.h> #include <linux/net.h> #include <linux/in.h> #include <linux/if.h> @@ -52,28 +54,17 @@ #include <asm/system.h> #include <linux/interrupt.h> #include <linux/ioport.h> - #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) -/* prototypes for ax25_encapsulate and ax25_rebuild_header */ #include <net/ax25.h> -#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ - -/* make genksyms happy */ +#include <net/ax25dev.h> #include <linux/ip.h> #include <linux/udp.h> #include <linux/tcp.h> - #include <linux/kernel.h> #include <linux/proc_fs.h> - -#include <linux/version.h> -#include <asm/uaccess.h> -#include <linux/init.h> - #include <linux/yam.h> #include "yam9600.h" #include "yam1200.h" @@ -81,71 +72,53 @@ /* --------------------------------------------------------------------- */ static const char yam_drvname[] = "yam"; -static const char yam_drvinfo[] __initdata = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n"; +static const char yam_drvinfo[] = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n"; /* --------------------------------------------------------------------- */ #define YAM_9600 1 #define YAM_1200 2 - -#define NR_PORTS 4 +#define NR_PORTS 4 #define YAM_MAGIC 0xF10A7654 /* Transmitter states */ - -#define TX_OFF 0 +#define TX_OFF 0 #define TX_HEAD 1 -#define TX_DATA 2 -#define TX_CRC1 3 -#define TX_CRC2 4 -#define TX_TAIL 5 +#define TX_DATA 2 +#define TX_CRC1 3 +#define TX_CRC2 4 +#define TX_TAIL 5 #define YAM_MAX_FRAME 1024 -#define DEFAULT_BITRATE 9600 /* bps */ -#define DEFAULT_HOLDD 10 /* sec */ -#define DEFAULT_TXD 300 /* ms */ -#define DEFAULT_TXTAIL 10 /* ms */ -#define DEFAULT_SLOT 100 /* ms */ -#define DEFAULT_PERS 64 /* 0->255 */ +#define DEFAULT_BITRATE 9600 /* bps */ +#define DEFAULT_HOLDD 10 /* sec */ +#define DEFAULT_TXD 300 /* ms */ +#define DEFAULT_TXTAIL 10 /* ms */ struct yam_port { int magic; - int bitrate; - int baudrate; int iobase; int irq; - int dupmode; + /* device stuff */ struct net_device dev; + struct ax25_dev ax25dev; /* Stats section */ - struct net_device_stats stats; - int nb_rxint; int nb_mdint; - /* Parameters section */ - - int txd; /* tx delay */ - int holdd; /* duplex ptt delay */ - int txtail; /* txtail delay */ - int slot; /* slottime */ - int pers; /* persistence */ - /* Tx section */ - int tx_state; int tx_count; - int slotcnt; unsigned char tx_buf[YAM_MAX_FRAME]; int tx_len; int tx_crcl, tx_crch; struct sk_buff_head send_queue; /* Packets awaiting transmission */ /* Rx section */ - int dcd; unsigned char rx_buf[YAM_MAX_FRAME]; int rx_len; @@ -158,49 +131,65 @@ struct yam_mcs { struct yam_mcs *next; }; +enum uart { + c_uart_unknown, c_uart_8250, + c_uart_16450, c_uart_16550, c_uart_16550A +}; + +static const char *uart_str[] = +{"unknown", "8250", "16450", "16550", "16550A"}; + static struct yam_port yam_ports[NR_PORTS]; +static struct yam_mcs *yam_data = NULL; +static unsigned irqs[16]; +static struct timer_list yam_timer; -static struct yam_mcs *yam_data; +#ifdef CONFIG_PROC_FS +static int yam_net_get_info(char *buffer, char **start, off_t offset, int length); -static char ax25_bcast[7] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_test[7] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; +#define yam_net_procfs_init() proc_net_create("yam", 0, yam_net_get_info); +#define yam_net_procfs_remove() proc_net_remove("yam"); +#else +#define yam_net_procfs_init() +#define yam_net_procfs_remove() +#endif -static struct timer_list yam_timer; +static unsigned int yam_report_dcd(struct net_device *dev); +static unsigned int yam_report_ptt(struct net_device *dev); +static void yam_param_notify(struct net_device *dev, int valueno, int old, int new); /* --------------------------------------------------------------------- */ -#define RBR(iobase) (iobase+0) -#define THR(iobase) (iobase+0) -#define IER(iobase) (iobase+1) -#define IIR(iobase) (iobase+2) -#define FCR(iobase) (iobase+2) -#define LCR(iobase) (iobase+3) -#define MCR(iobase) (iobase+4) -#define LSR(iobase) (iobase+5) -#define MSR(iobase) (iobase+6) -#define SCR(iobase) (iobase+7) -#define DLL(iobase) (iobase+0) -#define DLM(iobase) (iobase+1) - -#define YAM_EXTENT 8 +#define RBR(iobase) (iobase+0) +#define THR(iobase) (iobase+0) +#define IER(iobase) (iobase+1) +#define IIR(iobase) (iobase+2) +#define FCR(iobase) (iobase+2) +#define LCR(iobase) (iobase+3) +#define MCR(iobase) (iobase+4) +#define LSR(iobase) (iobase+5) +#define MSR(iobase) (iobase+6) +#define SCR(iobase) (iobase+7) +#define DLL(iobase) (iobase+0) +#define DLM(iobase) (iobase+1) + +#define YAM_EXTENT 8 /* Interrupt Identification Register Bit Masks */ -#define IIR_NOPEND 1 -#define IIR_MSR 0 -#define IIR_TX 2 -#define IIR_RX 4 -#define IIR_LSR 6 +#define IIR_NOPEND 1 +#define IIR_MSR 0 +#define IIR_TX 2 +#define IIR_RX 4 +#define IIR_LSR 6 #define IIR_TIMEOUT 12 /* Fifo mode only */ #define IIR_MASK 0x0F /* Interrupt Enable Register Bit Masks */ -#define IER_RX 1 /* enable rx interrupt */ -#define IER_TX 2 /* enable tx interrupt */ -#define IER_LSR 4 /* enable line status interrupts */ -#define IER_MSR 8 /* enable modem status interrupts */ +#define IER_RX 1 /* enable rx interrupt */ +#define IER_TX 2 /* enable tx interrupt */ +#define IER_LSR 4 /* enable line status interrupts */ +#define IER_MSR 8 /* enable modem status interrupts */ /* Modem Control Register Bit Masks */ #define MCR_DTR 0x01 /* DTR output */ @@ -254,6 +243,8 @@ static struct timer_list yam_timer; #define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */ #define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */ +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) /************************************************************************* * CRC Tables @@ -298,6 +289,8 @@ static const unsigned char chktabh[256] = 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e, 0x0f}; +/* --------------------------------------------------------------------- */ + /************************************************************************* * FPGA functions ************************************************************************/ @@ -308,10 +301,11 @@ static void delay(int ms) while (jiffies < timeout); } +/* --------------------------------------------------------------------- */ + /* * reset FPGA */ - static void fpga_reset(int iobase) { outb(0, IER(iobase)); @@ -330,10 +324,11 @@ static void fpga_reset(int iobase) delay(100); } +/* --------------------------------------------------------------------- */ + /* * send one byte to FPGA */ - static int fpga_write(int iobase, unsigned char wrd) { unsigned char bit; @@ -349,10 +344,26 @@ static int fpga_write(int iobase, unsigned char wrd) if (jiffies > timeout) return -1; } - return 0; } +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +static void free_mcs(void) +{ + struct yam_mcs *p; + + while (yam_data) { + p = yam_data; + yam_data = yam_data->next; + kfree(p); + } +} +#endif + +/* --------------------------------------------------------------------- */ + static unsigned char *add_mcs(unsigned char *bits, int bitrate) { struct yam_mcs *p; @@ -368,7 +379,8 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate) } /* Allocate a new mcs */ - if ((p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL)) == NULL) { + p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL); + if (p == NULL) { printk(KERN_WARNING "YAM: no memory to allocate mcs\n"); return NULL; } @@ -380,6 +392,8 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate) return p->bits; } +/* --------------------------------------------------------------------- */ + static unsigned char *get_mcs(int bitrate) { struct yam_mcs *p; @@ -400,11 +414,12 @@ static unsigned char *get_mcs(int bitrate) } } +/* --------------------------------------------------------------------- */ + /* * download bitstream to FPGA * data is contained in bits[] array in yam1200.h resp. yam9600.h */ - static int fpga_download(int iobase, int bitrate) { int i, rc; @@ -417,7 +432,7 @@ static int fpga_download(int iobase, int bitrate) fpga_reset(iobase); for (i = 0; i < YAM_FPGA_SIZE; i++) { if (fpga_write(iobase, pbits[i])) { - printk(KERN_ERR "yam: error in write cycle\n"); + printk("yam: error in write cycle\n"); return -1; /* write... */ } } @@ -431,6 +446,7 @@ static int fpga_download(int iobase, int bitrate) return (rc & MSR_DSR) ? 0 : -1; } +/* --------------------------------------------------------------------- */ /************************************************************************ * Serial port init @@ -438,8 +454,7 @@ static int fpga_download(int iobase, int bitrate) static void yam_set_uart(struct net_device *dev) { - struct yam_port *yp = (struct yam_port *) dev->priv; - int divisor = 115200 / yp->baudrate; + int divisor = 115200 / (2 * ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE)); outb(0, IER(dev->base_addr)); outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr)); @@ -459,17 +474,8 @@ static void yam_set_uart(struct net_device *dev) outb(ENABLE_RTXINT, IER(dev->base_addr)); } - /* --------------------------------------------------------------------- */ -enum uart { - c_uart_unknown, c_uart_8250, - c_uart_16450, c_uart_16550, c_uart_16550A -}; - -static const char *uart_str[] = -{"unknown", "8250", "16450", "16550", "16550A"}; - static enum uart yam_check_uart(unsigned int iobase) { unsigned char b1, b2, b3; @@ -501,27 +507,29 @@ static enum uart yam_check_uart(unsigned int iobase) return u; } +/* --------------------------------------------------------------------- */ + /****************************************************************************** * Rx Section ******************************************************************************/ -static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp) + +static void inline yam_rx_flag(struct net_device *dev, struct yam_port *yp) { if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) { - int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */ + int pkt_len = yp->rx_len - 2; /* -CRC */ struct sk_buff *skb; if ((yp->rx_crch & yp->rx_crcl) != 0xFF) { /* Bad crc */ } else { if (!(skb = dev_alloc_skb(pkt_len))) { - printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name); + printk("%s: memory squeeze, dropping packet\n", dev->name); ++yp->stats.rx_dropped; } else { unsigned char *cp; skb->dev = dev; cp = skb_put(skb, pkt_len); - *cp++ = 0; /* KISS kludge */ - memcpy(cp, yp->rx_buf, pkt_len - 1); + memcpy(cp, yp->rx_buf, pkt_len); skb->protocol = htons(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); @@ -534,7 +542,9 @@ static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp) yp->rx_crch = 0xf3; } -static inline void yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb) +/* --------------------------------------------------------------------- */ + +static void inline yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb) { if (yp->rx_len < YAM_MAX_FRAME) { unsigned char c = yp->rx_crcl; @@ -544,6 +554,8 @@ static inline void yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsi } } +/* --------------------------------------------------------------------- */ + /******************************************************************************** * TX Section ********************************************************************************/ @@ -553,38 +565,48 @@ static void ptt_on(struct net_device *dev) outb(PTT_ON, MCR(dev->base_addr)); } +/* --------------------------------------------------------------------- */ + static void ptt_off(struct net_device *dev) { outb(PTT_OFF, MCR(dev->base_addr)); } +/* --------------------------------------------------------------------- */ + static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) { struct yam_port *yp = dev->priv; + if (skb == NULL) { + return 0; + } skb_queue_tail(&yp->send_queue, skb); dev->trans_start = jiffies; return 0; } +/* --------------------------------------------------------------------- */ + static void yam_start_tx(struct net_device *dev, struct yam_port *yp) { - if ((yp->tx_state == TX_TAIL) || (yp->txd == 0)) + int bitrate = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE); + int txd = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXDELAY); + + if ((yp->tx_state == TX_TAIL) || (txd == 0)) yp->tx_count = 1; else - yp->tx_count = (yp->bitrate * yp->txd) / 8000; + yp->tx_count = (bitrate * txd) / 8000; yp->tx_state = TX_HEAD; ptt_on(dev); } -static unsigned short random_seed; - -static inline unsigned short random_num(void) -{ - random_seed = 28629 * random_seed + 157; - return random_seed; -} +/* --------------------------------------------------------------------- */ +/* + * note: this used to be a real channel arbiter, but this is now done in + * the DDI layer of AX.25 protocol engine. + */ static void yam_arbitrate(struct net_device *dev) { struct yam_port *yp = dev->priv; @@ -593,31 +615,13 @@ static void yam_arbitrate(struct net_device *dev) || yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) { return; } - /* tx_state is TX_OFF and there is data to send */ - - if (yp->dupmode) { - /* Full duplex mode, don't wait */ - yam_start_tx(dev, yp); - return; - } - if (yp->dcd) { - /* DCD on, wait slotime ... */ - yp->slotcnt = yp->slot / 10; - return; - } - /* Is slottime passed ? */ - if ((--yp->slotcnt) > 0) - return; - - yp->slotcnt = yp->slot / 10; - - /* is random > persist ? */ - if ((random_num() % 256) > yp->pers) - return; + /* tx_state is TX_OFF and there is data to send */ yam_start_tx(dev, yp); } +/* --------------------------------------------------------------------- */ + static void yam_dotimer(unsigned long dummy) { int i; @@ -631,10 +635,14 @@ static void yam_dotimer(unsigned long dummy) add_timer(&yam_timer); } +/* --------------------------------------------------------------------- */ + static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) { struct sk_buff *skb; unsigned char b, temp; + int bitrate = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE); + int txtail = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXTAIL); switch (yp->tx_state) { case TX_OFF: @@ -647,17 +655,12 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) break; } yp->tx_state = TX_DATA; - if (skb->data[0] != 0) { -/* do_kiss_params(s, skb->data, skb->len); */ - dev_kfree_skb(skb); - break; - } - yp->tx_len = skb->len - 1; /* strip KISS byte */ + yp->tx_len = skb->len; if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) { dev_kfree_skb(skb); break; } - memcpy(yp->tx_buf, skb->data + 1, yp->tx_len); + memcpy(yp->tx_buf, skb->data, yp->tx_len); dev_kfree_skb(skb); yp->tx_count = 0; yp->tx_crcl = 0x21; @@ -684,9 +687,7 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) case TX_CRC2: outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr)); if (skb_queue_empty(&yp->send_queue)) { - yp->tx_count = (yp->bitrate * yp->txtail) / 8000; - if (yp->dupmode == 2) - yp->tx_count += (yp->bitrate * yp->holdd) / 8; + yp->tx_count = (bitrate * txtail) / 8000; if (yp->tx_count == 0) yp->tx_count = 1; yp->tx_state = TX_TAIL; @@ -705,6 +706,8 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) } } +/* --------------------------------------------------------------------- */ + /*********************************************************************************** * ISR routine ************************************************************************************/ @@ -714,7 +717,7 @@ static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev; struct yam_port *yp; unsigned char iir; - int counter = 100; + int irq_work = 100; int i; sti(); @@ -736,8 +739,8 @@ static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) yp->dcd = (msr & RX_DCD) ? 1 : 0; - if (--counter <= 0) { - printk(KERN_ERR "%s: too many irq iir=%d\n", dev->name, iir); + if (--irq_work <= 0) { + printk("%s: too many irq iir=%d\n", dev->name, iir); return; } if (msr & TX_RDY) { @@ -756,6 +759,8 @@ static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } +/* --------------------------------------------------------------------- */ + static int yam_net_get_info(char *buffer, char **start, off_t offset, int length) { int len = 0; @@ -766,21 +771,31 @@ static int yam_net_get_info(char *buffer, char **start, off_t offset, int length cli(); for (i = 0; i < NR_PORTS; i++) { + struct net_device *dev; + if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0) continue; - len += sprintf(buffer + len, "Device yam%d\n", i); + dev = &yam_ports[i].dev; + + len += sprintf(buffer + len, "Device %d\n", i); len += sprintf(buffer + len, " Up %d\n", netif_running(&yam_ports[i].dev)); - len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate); + len += sprintf(buffer + len, " Speed %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE)); len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase); - len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate); + len += sprintf(buffer + len, " BaudRate %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE)*2); len += sprintf(buffer + len, " IRQ %u\n", yam_ports[i].irq); len += sprintf(buffer + len, " TxState %u\n", yam_ports[i].tx_state); - len += sprintf(buffer + len, " Duplex %u\n", yam_ports[i].dupmode); - len += sprintf(buffer + len, " HoldDly %u\n", yam_ports[i].holdd); - len += sprintf(buffer + len, " TxDelay %u\n", yam_ports[i].txd); - len += sprintf(buffer + len, " TxTail %u\n", yam_ports[i].txtail); - len += sprintf(buffer + len, " SlotTime %u\n", yam_ports[i].slot); - len += sprintf(buffer + len, " Persist %u\n", yam_ports[i].pers); + len += sprintf(buffer + len, " Duplex %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_DUPLEX)); + len += sprintf(buffer + len, " TxDelay %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXDELAY)); + len += sprintf(buffer + len, " TxTail %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXTAIL)); + len += sprintf(buffer + len, " SlotTime %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_SLOTTIME)); + len += sprintf(buffer + len, " Persist %u\n", + ax25_dev_get_value(dev, AX25_VALUES_MEDIA_PPERSISTENCE)); len += sprintf(buffer + len, " TxFrames %lu\n", yam_ports[i].stats.tx_packets); len += sprintf(buffer + len, " RxFrames %lu\n", yam_ports[i].stats.rx_packets); len += sprintf(buffer + len, " TxInt %u\n", yam_ports[i].nb_mdint); @@ -805,13 +820,14 @@ static int yam_net_get_info(char *buffer, char **start, off_t offset, int length if (len > length) len = length; - return len; } + + /* --------------------------------------------------------------------- */ -static struct net_device_stats *yam_get_stats(struct net_device *dev) +static struct net_device_stats * yam_get_stats(struct net_device *dev) { struct yam_port *yp; @@ -836,39 +852,38 @@ static int yam_open(struct net_device *dev) struct yam_port *yp = (struct yam_port *) dev->priv; enum uart u; int i; + int bitrate; printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq); - if (!dev || !yp || !yp->bitrate) - return -ENXIO; + if (!dev) return -ENXIO; + bitrate = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE); + if (!yp || !bitrate) return -ENXIO; if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT || dev->irq < 2 || dev->irq > 15) { return -ENXIO; } if (check_region(dev->base_addr, YAM_EXTENT)) { - printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr); + printk("%s: cannot 0x%lx busy\n", dev->name, dev->base_addr); return -EACCES; } if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) { - printk(KERN_ERR "%s: cannot find uart type\n", dev->name); + printk("%s: cannot find uart type\n", dev->name); return -EIO; } - if (fpga_download(dev->base_addr, yp->bitrate)) { - printk(KERN_ERR "%s: cannot init FPGA\n", dev->name); + if (fpga_download(dev->base_addr, bitrate)) { + printk("%s: cannot init FPGA\n", dev->name); return -EIO; } outb(0, IER(dev->base_addr)); if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, NULL)) { - printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq); + printk("%s: irq %d busy\n", dev->name, dev->irq); return -EBUSY; } request_region(dev->base_addr, YAM_EXTENT, dev->name); yam_set_uart(dev); - netif_start_queue(dev); - - yp->slotcnt = yp->slot / 10; /* Reset overruns for all ports - FPGA programming makes overruns */ for (i = 0; i < NR_PORTS; i++) { @@ -898,7 +913,9 @@ static int yam_close(struct net_device *dev) /* Remove IRQ handler if last */ free_irq(dev->irq, NULL); release_region(dev->base_addr, YAM_EXTENT); + netif_stop_queue(dev); + while ((skb = skb_dequeue(&yp->send_queue))) dev_kfree_skb(skb); @@ -963,9 +980,6 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; /* Cannot change this parameter when up */ if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev)) - return -EINVAL; /* Cannot change this parameter when up */ - if (yi.cfg.mask & YAM_IOBASE) { yp->iobase = yi.cfg.iobase; dev->base_addr = yi.cfg.iobase; @@ -979,43 +993,23 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (yi.cfg.mask & YAM_BITRATE) { if (yi.cfg.bitrate > YAM_MAXBITRATE) return -EINVAL; - yp->bitrate = yi.cfg.bitrate; - } - if (yi.cfg.mask & YAM_BAUDRATE) { - if (yi.cfg.baudrate > YAM_MAXBAUDRATE) - return -EINVAL; - yp->baudrate = yi.cfg.baudrate; + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXBITRATE, yi.cfg.bitrate); + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_RXBITRATE, yi.cfg.bitrate); } if (yi.cfg.mask & YAM_MODE) { if (yi.cfg.mode > YAM_MAXMODE) return -EINVAL; - yp->dupmode = yi.cfg.mode; - } - if (yi.cfg.mask & YAM_HOLDDLY) { - if (yi.cfg.holddly > YAM_MAXHOLDDLY) - return -EINVAL; - yp->holdd = yi.cfg.holddly; + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_DUPLEX, yi.cfg.mode); } if (yi.cfg.mask & YAM_TXDELAY) { if (yi.cfg.txdelay > YAM_MAXTXDELAY) return -EINVAL; - yp->txd = yi.cfg.txdelay; + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXDELAY, yi.cfg.txdelay); } if (yi.cfg.mask & YAM_TXTAIL) { if (yi.cfg.txtail > YAM_MAXTXTAIL) return -EINVAL; - yp->txtail = yi.cfg.txtail; - } - if (yi.cfg.mask & YAM_PERSIST) { - if (yi.cfg.persist > YAM_MAXPERSIST) - return -EINVAL; - yp->pers = yi.cfg.persist; - } - if (yi.cfg.mask & YAM_SLOTTIME) { - if (yi.cfg.slottime > YAM_MAXSLOTTIME) - return -EINVAL; - yp->slot = yi.cfg.slottime; - yp->slotcnt = yp->slot / 10; + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXTAIL, yi.cfg.txtail); } break; @@ -1023,14 +1017,10 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) yi.cfg.mask = 0xffffffff; yi.cfg.iobase = yp->iobase; yi.cfg.irq = yp->irq; - yi.cfg.bitrate = yp->bitrate; - yi.cfg.baudrate = yp->baudrate; - yi.cfg.mode = yp->dupmode; - yi.cfg.txdelay = yp->txd; - yi.cfg.holddly = yp->holdd; - yi.cfg.txtail = yp->txtail; - yi.cfg.persist = yp->pers; - yi.cfg.slottime = yp->slot; + yi.cfg.bitrate = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXBITRATE); + yi.cfg.mode = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_DUPLEX); + yi.cfg.txdelay = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXDELAY); + yi.cfg.txtail = ax25_dev_get_value(dev, AX25_VALUES_MEDIA_TXTAIL); if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg))) return -EFAULT; break; @@ -1045,6 +1035,50 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* --------------------------------------------------------------------- */ +static unsigned int yam_report_dcd(struct net_device *dev) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + + if (!yp) return 0; /* paranoia */ + return yp->dcd; +} + +/* --------------------------------------------------------------------- */ + +static unsigned int yam_report_ptt(struct net_device *dev) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + + return (yp->tx_state != TX_OFF); +} + +/* --------------------------------------------------------------------- */ + +static void yam_param_notify(struct net_device *dev, int valueno, int old, int new) +{ + switch (valueno) { + case AX25_VALUES_MEDIA_RXBITRATE: + case AX25_VALUES_MEDIA_TXBITRATE: + if (netif_running(dev)) break; + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXBITRATE, new); + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_RXBITRATE, new); + return; + case AX25_VALUES_MEDIA_DUPLEX: + if (netif_running(dev)) break; + return; + case AX25_VALUES_MEDIA_TXDELAY: + case AX25_VALUES_MEDIA_TXTAIL: + default: + /* just let them do it. */ + return; + } + /* reject */ + ax25_dev_set_value(dev, valueno, old); + return; +} + +/* --------------------------------------------------------------------- */ + static int yam_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *sa = (struct sockaddr *) addr; @@ -1065,62 +1099,58 @@ static int yam_probe(struct net_device *dev) yp = (struct yam_port *) dev->priv; - dev->open = yam_open; - dev->stop = yam_close; - dev->do_ioctl = yam_ioctl; - dev->hard_start_xmit = yam_send_packet; - dev->get_stats = yam_get_stats; - + dev->open = yam_open; + dev->stop = yam_close; + dev->do_ioctl = yam_ioctl; + dev->hard_start_xmit = yam_send_packet; + dev->get_stats = yam_get_stats; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = yam_set_mac_address; + dev->type = ARPHRD_AX25; /* AF_AX25 device */ + dev->hard_header_len = AX25_MAX_HEADER_LEN; /* We do digipeaters now */ + dev->mtu = 256; /* AX25 is the default */ + dev->addr_len = 7; /* sizeof an ax.25 address */ dev_init_buffers(dev); skb_queue_head_init(&yp->send_queue); -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; -#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ - dev->hard_header = NULL; - dev->rebuild_header = NULL; -#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ - - dev->set_mac_address = yam_set_mac_address; - - dev->type = ARPHRD_AX25; /* AF_AX25 device */ - dev->hard_header_len = 73; /* We do digipeaters now */ - dev->mtu = 256; /* AX25 is the default */ - dev->addr_len = 7; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, ax25_bcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); - /* New style flags */ - dev->flags = 0; + dev->flags = IFF_BROADCAST; + /* AX.25 downcalls */ + AX25_PTR(dev)->hw.dcd = yam_report_dcd; + AX25_PTR(dev)->hw.ptt = yam_report_ptt; + AX25_PTR(dev)->hw.parameter_change_notify = yam_param_notify; return 0; } /* --------------------------------------------------------------------- */ -static int __init yam_init_driver(void) +int __init yam_init(void) { struct net_device *dev; int i; printk(yam_drvinfo); + /* Clears the IRQ table */ + + memset(irqs, 0, sizeof(irqs)); + memset(yam_ports, 0, sizeof(yam_ports)); + for (i = 0; i < NR_PORTS; i++) { sprintf(yam_ports[i].dev.name, "yam%d", i); yam_ports[i].magic = YAM_MAGIC; - yam_ports[i].bitrate = DEFAULT_BITRATE; - yam_ports[i].baudrate = DEFAULT_BITRATE * 2; + dev = &yam_ports[i].dev; + AX25_PTR(dev)=&yam_ports[i].ax25dev; + memset(AX25_PTR(dev), 0, sizeof(struct ax25_dev)); + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXBITRATE, DEFAULT_BITRATE); + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_RXBITRATE, DEFAULT_BITRATE); yam_ports[i].iobase = 0; yam_ports[i].irq = 0; - yam_ports[i].dupmode = 0; - yam_ports[i].holdd = DEFAULT_HOLDD; - yam_ports[i].txd = DEFAULT_TXD; - yam_ports[i].txtail = DEFAULT_TXTAIL; - yam_ports[i].slot = DEFAULT_SLOT; - yam_ports[i].pers = DEFAULT_PERS; - - dev = &yam_ports[i].dev; + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_DUPLEX, 0); + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXDELAY, DEFAULT_TXD); + ax25_dev_set_value(dev, AX25_VALUES_MEDIA_TXTAIL, DEFAULT_TXTAIL); dev->priv = &yam_ports[i]; dev->base_addr = yam_ports[i].iobase; @@ -1141,15 +1171,14 @@ static int __init yam_init_driver(void) yam_timer.expires = jiffies + HZ / 100; add_timer(&yam_timer); - proc_net_create("yam", 0, yam_net_get_info); + yam_net_procfs_init(); return 0; } /* --------------------------------------------------------------------- */ -static void __exit yam_cleanup_driver(void) +void __exit yam_exit(void) { - struct yam_mcs *p; int i; del_timer(&yam_timer); @@ -1161,23 +1190,13 @@ static void __exit yam_cleanup_driver(void) yam_close(dev); unregister_netdev(dev); } - - while (yam_data) { - p = yam_data; - yam_data = yam_data->next; - kfree(p); - } - - proc_net_remove("yam"); + free_mcs(); + yam_net_procfs_remove(); } /* --------------------------------------------------------------------- */ MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr"); -MODULE_DESCRIPTION("Yam amateur radio modem driver"); - -module_init(yam_init_driver); -module_exit(yam_cleanup_driver); - -/* --------------------------------------------------------------------- */ - +MODULE_DESCRIPTION("YAM Amateur Radio modem driver"); +module_init(yam_init); +module_exit(yam_exit); |