summaryrefslogtreecommitdiffstats
path: root/drivers/net/hamradio/baycom_epp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/hamradio/baycom_epp.c')
-rw-r--r--drivers/net/hamradio/baycom_epp.c202
1 files changed, 98 insertions, 104 deletions
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index d4191258d..98d228b91 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -3,7 +3,7 @@
/*
* baycom_epp.c -- baycom epp radio modem driver.
*
- * Copyright (C) 1998-1999
+ * Copyright (C) 1998-2000
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
@@ -26,14 +26,15 @@
*
*
* History:
- * 0.1 xx.xx.98 Initial version by Matthias Welwarsky (dg2fef)
- * 0.2 21.04.98 Massive rework by Thomas Sailer
- * Integrated FPGA EPP modem configuration routines
- * 0.3 11.05.98 Took FPGA config out and moved it into a separate program
- * 0.4 26.07.99 Adapted to new lowlevel parport driver interface
- * 0.5 03.08.99 adapt to Linus' new __setup/__initcall
- * removed some pre-2.2 kernel compatibility cruft
- * 0.6 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.1 xx.xx.1998 Initial version by Matthias Welwarsky (dg2fef)
+ * 0.2 21.04.1998 Massive rework by Thomas Sailer
+ * Integrated FPGA EPP modem configuration routines
+ * 0.3 11.05.1998 Took FPGA config out and moved it into a separate program
+ * 0.4 26.07.1999 Adapted to new lowlevel parport driver interface
+ * 0.5 03.08.1999 adapt to Linus' new __setup/__initcall
+ * removed some pre-2.2 kernel compatibility cruft
+ * 0.6 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.7 12.02.2000 adapted to softnet driver interface
*
*/
@@ -47,8 +48,10 @@
#include <linux/tqueue.h>
#include <linux/fs.h>
#include <linux/parport.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/if_arp.h>
+#include <linux/kmod.h>
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
#include <linux/soundmodem.h>
@@ -89,8 +92,8 @@ static const char paranoia_str[] = KERN_ERR
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_epp";
-static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-1999 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_epp: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -228,8 +231,7 @@ struct baycom_state {
struct net_device_stats stats;
unsigned int ptt_keyed;
- struct sk_buff_head send_queue; /* Packets awaiting transmission */
-
+ struct sk_buff *skb; /* next transmit packet */
#ifdef BAYCOM_DEBUG
struct debug_vals {
@@ -394,15 +396,11 @@ static int exec_eppfpga(void *b)
sprintf(portarg, "%ld", bc->pdev->port->base);
printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
- for (i = 0; i < current->files->max_fds; i++ )
- if (current->files->fd[i])
- close(i);
- set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */
- current->uid = current->euid = current->fsuid = 0;
- if (execve(eppconfig_path, argv, envp) < 0) {
+ i = exec_usermodehelper(eppconfig_path, argv, envp);
+ if (i < 0) {
printk(KERN_ERR "%s: failed to exec %s -s -p %s -m %s, errno = %d\n",
- bc_drvname, eppconfig_path, portarg, modearg, errno);
- return -errno;
+ bc_drvname, eppconfig_path, portarg, modearg, i);
+ return i;
}
return 0;
}
@@ -515,71 +513,63 @@ static void encode_hdlc(struct baycom_state *bc)
if (bc->hdlctx.bufcnt > 0)
return;
- while ((skb = skb_dequeue(&bc->send_queue))) {
- if (skb->data[0] != 0) {
- do_kiss_params(bc, skb->data, skb->len);
- dev_kfree_skb(skb);
- continue;
- }
- pkt_len = skb->len-1; /* strip KISS byte */
- if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) {
- dev_kfree_skb(skb);
- continue;
- }
- wp = bc->hdlctx.buf;
- bp = skb->data+1;
- crc = calc_crc_ccitt(bp, pkt_len);
- crcarr[0] = crc;
- crcarr[1] = crc >> 8;
- *wp++ = 0x7e;
- bitstream = bitbuf = numbit = 0;
- while (pkt_len > -2) {
- bitstream >>= 8;
- bitstream |= ((unsigned int)*bp) << 8;
- bitbuf |= ((unsigned int)*bp) << numbit;
- notbitstream = ~bitstream;
- bp++;
- pkt_len--;
- if (!pkt_len)
- bp = crcarr;
- ENCODEITERA(0);
- ENCODEITERA(1);
- ENCODEITERA(2);
- ENCODEITERA(3);
- ENCODEITERA(4);
- ENCODEITERA(5);
- ENCODEITERA(6);
- ENCODEITERA(7);
- goto enditer;
- ENCODEITERB(0);
- ENCODEITERB(1);
- ENCODEITERB(2);
- ENCODEITERB(3);
- ENCODEITERB(4);
- ENCODEITERB(5);
- ENCODEITERB(6);
- ENCODEITERB(7);
- enditer:
- numbit += 8;
- while (numbit >= 8) {
- *wp++ = bitbuf;
- bitbuf >>= 8;
- numbit -= 8;
- }
- }
- bitbuf |= 0x7e7e << numbit;
- numbit += 16;
- while (numbit >= 8) {
- *wp++ = bitbuf;
- bitbuf >>= 8;
- numbit -= 8;
- }
- bc->hdlctx.bufptr = bc->hdlctx.buf;
- bc->hdlctx.bufcnt = wp - bc->hdlctx.buf;
- dev_kfree_skb(skb);
- bc->stats.tx_packets++;
+ skb = bc->skb;
+ if (!skb)
return;
+ bc->skb = NULL;
+ pkt_len = skb->len-1; /* strip KISS byte */
+ wp = bc->hdlctx.buf;
+ bp = skb->data+1;
+ crc = calc_crc_ccitt(bp, pkt_len);
+ crcarr[0] = crc;
+ crcarr[1] = crc >> 8;
+ *wp++ = 0x7e;
+ bitstream = bitbuf = numbit = 0;
+ while (pkt_len > -2) {
+ bitstream >>= 8;
+ bitstream |= ((unsigned int)*bp) << 8;
+ bitbuf |= ((unsigned int)*bp) << numbit;
+ notbitstream = ~bitstream;
+ bp++;
+ pkt_len--;
+ if (!pkt_len)
+ bp = crcarr;
+ ENCODEITERA(0);
+ ENCODEITERA(1);
+ ENCODEITERA(2);
+ ENCODEITERA(3);
+ ENCODEITERA(4);
+ ENCODEITERA(5);
+ ENCODEITERA(6);
+ ENCODEITERA(7);
+ goto enditer;
+ ENCODEITERB(0);
+ ENCODEITERB(1);
+ ENCODEITERB(2);
+ ENCODEITERB(3);
+ ENCODEITERB(4);
+ ENCODEITERB(5);
+ ENCODEITERB(6);
+ ENCODEITERB(7);
+ enditer:
+ numbit += 8;
+ while (numbit >= 8) {
+ *wp++ = bitbuf;
+ bitbuf >>= 8;
+ numbit -= 8;
+ }
}
+ bitbuf |= 0x7e7e << numbit;
+ numbit += 16;
+ while (numbit >= 8) {
+ *wp++ = bitbuf;
+ bitbuf >>= 8;
+ numbit -= 8;
+ }
+ bc->hdlctx.bufptr = bc->hdlctx.buf;
+ bc->hdlctx.bufcnt = wp - bc->hdlctx.buf;
+ dev_kfree_skb(skb);
+ bc->stats.tx_packets++;
}
/* ---------------------------------------------------------------------- */
@@ -944,6 +934,8 @@ static void epp_bh(struct net_device *dev)
bc->debug_vals.demod_cycles = time3 - time2;
#endif /* BAYCOM_DEBUG */
queue_task(&bc->run_bh, &tq_timer);
+ if (!bc->skb)
+ netif_wake_queue(dev);
return;
epptimeout:
printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname);
@@ -960,8 +952,20 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
baycom_paranoia_check(dev, "baycom_send_packet", 0);
bc = (struct baycom_state *)dev->priv;
- skb_queue_tail(&bc->send_queue, skb);
- dev->trans_start = jiffies;
+ if (skb->data[0] != 0) {
+ do_kiss_params(bc, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ if (bc->skb)
+ return -1;
+ /* strip KISS byte */
+ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ netif_stop_queue(dev);
+ bc->skb = skb;
return 0;
}
@@ -1030,8 +1034,6 @@ static int epp_open(struct net_device *dev)
baycom_paranoia_check(dev, "epp_open", -ENXIO);
bc = (struct baycom_state *)dev->priv;
- if (dev->start)
- return 0;
pp = parport_enumerate();
while (pp && pp->base != dev->base_addr)
pp = pp->next;
@@ -1122,11 +1124,9 @@ static int epp_open(struct net_device *dev)
bc->hdlctx.bufcnt = 0;
bc->hdlctx.slotcnt = bc->ch_params.slottime;
bc->hdlctx.calibrate = 0;
- dev->start = 1;
- dev->tbusy = 0;
- dev->interrupt = 0;
/* start the bottom half stuff */
queue_task(&bc->run_bh, &tq_timer);
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -1144,17 +1144,12 @@ static int epp_close(struct net_device *dev)
{
struct baycom_state *bc;
struct parport *pp;
- struct sk_buff *skb;
unsigned char tmp[1];
baycom_paranoia_check(dev, "epp_close", -EINVAL);
- if (!dev->start)
- return 0;
bc = (struct baycom_state *)dev->priv;
pp = bc->pdev->port;
bc->bh_running = 0;
- dev->start = 0;
- dev->tbusy = 1;
run_task_queue(&tq_timer); /* dequeue bottom half */
bc->stat = EPP_DCDBIT;
tmp[0] = 0;
@@ -1162,9 +1157,9 @@ static int epp_close(struct net_device *dev)
parport_write_control(pp, 0); /* reset the adapter */
parport_release(bc->pdev);
parport_unregister_device(bc->pdev);
- /* Free any buffers left in the hardware transmit queue */
- while ((skb = skb_dequeue(&bc->send_queue)))
- dev_kfree_skb(skb);
+ if (bc->skb)
+ dev_kfree_skb(bc->skb);
+ bc->skb = NULL;
printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n",
bc_drvname, dev->base_addr, dev->irq);
MOD_DEC_USE_COUNT;
@@ -1280,7 +1275,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
case HDLCDRVCTL_SETMODEMPAR:
- if ((!suser()) || dev->start)
+ if ((!suser()) || netif_running(dev))
return -EACCES;
dev->base_addr = hi.data.mp.iobase;
dev->irq = /*hi.data.mp.irq*/0;
@@ -1319,7 +1314,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
case HDLCDRVCTL_SETMODE:
- if (!suser() || dev->start)
+ if (!suser() || netif_running(dev))
return -EACCES;
hi.data.modename[sizeof(hi.data.modename)-1] = '\0';
return baycom_setmode(bc, hi.data.modename);
@@ -1385,7 +1380,7 @@ static int baycom_probe(struct net_device *dev)
/* Fill in the fields of the device structure */
dev_init_buffers(dev);
- skb_queue_head_init(&bc->send_queue);
+ bc->skb = NULL;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
dev->hard_header = ax25_encapsulate;
@@ -1402,6 +1397,7 @@ static int baycom_probe(struct net_device *dev)
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+ dev->tx_queue_len = 16;
/* New style flags */
dev->flags = 0;
@@ -1461,8 +1457,6 @@ static int __init init_baycomepp(void)
dev->name = bc->ifname;
dev->if_port = 0;
dev->init = baycom_probe;
- dev->start = 0;
- dev->tbusy = 1;
dev->base_addr = iobase[i];
dev->irq = 0;
dev->dma = 0;