patch-2.3.44 linux/drivers/net/hamradio/baycom_epp.c

Next file: linux/drivers/net/hamradio/baycom_par.c
Previous file: linux/drivers/net/fmv18x.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.43/linux/drivers/net/hamradio/baycom_epp.c linux/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 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 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 @@
 	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 @@
 	
 	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 @@
 	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 @@
 
 	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 @@
 	
 	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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 		break;
 
 	case HDLCDRVCTL_SETMODEMPAR:
-		if ((!suser()) || dev->start)
+		if ((!suser()) || test_bit(LINK_STATE_START, &dev->state))
 			return -EACCES;
 		dev->base_addr = hi.data.mp.iobase;
 		dev->irq = /*hi.data.mp.irq*/0;
@@ -1319,7 +1314,7 @@
 		break;
 
 	case HDLCDRVCTL_SETMODE:
-		if (!suser() || dev->start)
+		if (!suser() || test_bit(LINK_STATE_START, &dev->state))
 			return -EACCES;
 		hi.data.modename[sizeof(hi.data.modename)-1] = '\0';
 		return baycom_setmode(bc, hi.data.modename);
@@ -1385,7 +1380,7 @@
 	/* 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 @@
 	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 @@
 		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;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)