diff options
Diffstat (limited to 'drivers/net/hamradio/baycom_epp.c')
-rw-r--r-- | drivers/net/hamradio/baycom_epp.c | 202 |
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; |