patch-2.1.33 linux/drivers/net/scc.c
Next file: linux/drivers/pnp/BUGS-parport
Previous file: linux/drivers/net/plip.c
Back to the patch index
Back to the overall index
- Lines: 319
- Date:
Tue Apr 8 11:37:47 1997
- Orig file:
v2.1.32/linux/drivers/net/scc.c
- Orig date:
Sun Feb 2 05:18:41 1997
diff -u --recursive --new-file v2.1.32/linux/drivers/net/scc.c linux/drivers/net/scc.c
@@ -1,4 +1,4 @@
-#define RCS_ID "$Id: scc.c,v 1.66 1997/01/08 22:56:06 jreuter Exp jreuter $"
+#define RCS_ID "$Id: scc.c,v 1.69 1997/04/06 19:22:45 jreuter Exp jreuter $"
#define VERSION "3.0"
#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
@@ -16,7 +16,7 @@
********************************************************************
- Copyright (c) 1993, 1996 Joerg Reuter DL1BKE
+ Copyright (c) 1993, 1997 Joerg Reuter DL1BKE
portions (c) 1993 Guido ten Dolle PE1NNZ
@@ -86,7 +86,9 @@
You can use 'kissbridge' if you need a KISS TNC emulator.
961213 - Fixed for Linux networking changes. (G4KLX)
- 960108 - Fixed the remaining problems.
+ 970108 - Fixed the remaining problems.
+ 970402 - Hopefully fixed the problems with the new *_timer()
+ routines, added calibration code.
Thanks to all who contributed to this driver with ideas and bug
reports!
@@ -151,8 +153,6 @@
#include <linux/if_arp.h>
#include <linux/socket.h>
-#include <linux/config.h> /* for CONFIG_PROC_FS */
-
#include <linux/scc.h>
#include "z8530.h"
@@ -222,6 +222,9 @@
static int Nchips = 0;
static io_port Vector_Latch = 0;
+MODULE_AUTHOR("Joerg Reuter <jreuter@lykos.oche.de>");
+MODULE_DESCRIPTION("Network Device Driver for Z8530 based HDLC cards for Amateur Packet Radio");
+MODULE_SUPPORTED_DEVICE("scc");
/* ******************************************************************** */
/* * Port Access Functions * */
@@ -511,7 +514,7 @@
}
or(scc,R10,ABUNDER);
- scc_start_tx_timer(scc, t_txdelay, 1); /* restart transmission */
+ scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */
}
scc->status = status;
@@ -799,10 +802,10 @@
static void init_channel(struct scc_channel *scc)
{
+ del_timer(&scc->tx_t);
+ del_timer(&scc->tx_wdog);
+
disable_irq(scc->irq);
-
- if (scc->tx_t.next) del_timer(&scc->tx_t);
- if (scc->tx_wdog.next) del_timer(&scc->tx_wdog);
wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */
wr(scc,R1,0); /* no W/REQ operation */
@@ -982,11 +985,11 @@
{
unsigned long flags;
+
save_flags(flags);
cli();
- if (scc->tx_t.next)
- del_timer(&scc->tx_t);
+ del_timer(&scc->tx_t);
if (when == 0)
{
@@ -1000,7 +1003,7 @@
add_timer(&scc->tx_t);
}
- restore_flags(flags);
+ restore_flags(flags);
}
static void scc_start_defer(struct scc_channel *scc)
@@ -1010,8 +1013,7 @@
save_flags(flags);
cli();
- if (scc->tx_wdog.next)
- del_timer(&scc->tx_wdog);
+ del_timer(&scc->tx_wdog);
if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)
{
@@ -1030,8 +1032,7 @@
save_flags(flags);
cli();
- if (scc->tx_wdog.next)
- del_timer(&scc->tx_wdog);
+ del_timer(&scc->tx_wdog);
if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)
{
@@ -1184,9 +1185,7 @@
save_flags(flags);
cli();
- if (scc->tx_wdog.next)
- del_timer(&scc->tx_wdog);
-
+ del_timer(&scc->tx_wdog);
scc_key_trx(scc, TX_OFF);
restore_flags(flags);
@@ -1215,16 +1214,8 @@
static void t_busy(unsigned long channel)
{
struct scc_channel *scc = (struct scc_channel *) channel;
- unsigned long flags;
- save_flags(flags);
- cli();
-
- if (scc->tx_t.next)
- del_timer(&scc->tx_t);
-
- restore_flags(flags);
-
+ del_timer(&scc->tx_t);
scc_lock_dev(scc);
scc_discard_buffers(scc);
@@ -1256,8 +1247,7 @@
scc_lock_dev(scc);
scc_discard_buffers(scc);
- if (scc->tx_t.next)
- del_timer(&scc->tx_t);
+ del_timer(&scc->tx_t);
cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */
cl(scc, R15, TxUIE); /* count it. */
@@ -1280,16 +1270,9 @@
static void t_idle(unsigned long channel)
{
struct scc_channel *scc = (struct scc_channel *) channel;
- unsigned long flags;
- save_flags(flags);
- cli();
-
- if (scc->tx_wdog.next)
- del_timer(&scc->tx_wdog);
+ del_timer(&scc->tx_wdog);
- restore_flags(flags);
-
scc_key_trx(scc, TX_OFF);
if (scc->kiss.mintime != TIMER_OFF)
@@ -1416,6 +1399,65 @@
#undef SVAL
/* ******************************************************************* */
+/* * Send calibration pattern * */
+/* ******************************************************************* */
+
+static void scc_stop_calibrate(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ del_timer(&scc->tx_wdog);
+ scc_key_trx(scc, TX_OFF);
+ wr(scc, R6, 0);
+ wr(scc, R7, FLAG);
+ Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
+ Outb(scc->ctrl,RES_EXT_INT);
+
+ scc_unlock_dev(scc);
+
+ restore_flags(flags);
+}
+
+
+static void
+scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ scc_lock_dev(scc);
+ scc_discard_buffers(scc);
+
+ del_timer(&scc->tx_wdog);
+
+ scc->tx_wdog.data = (unsigned long) scc;
+ scc->tx_wdog.function = scc_stop_calibrate;
+ scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
+ add_timer(&scc->tx_wdog);
+
+ wr(scc, R6, 0);
+ wr(scc, R7, pattern);
+
+ /*
+ * Don't know if this works.
+ * Damn, where is my Z8530 programming manual...?
+ */
+
+ Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
+ Outb(scc->ctrl,RES_EXT_INT);
+
+ scc_key_trx(scc, TX_ON);
+
+ restore_flags(flags);
+}
+
+/* ******************************************************************* */
/* * Init channel structures, special HW, etc... * */
/* ******************************************************************* */
@@ -1644,26 +1686,8 @@
struct scc_channel *scc = (struct scc_channel *) dev->priv;
unsigned long flags;
char kisscmd;
- long ticks;
- if (dev->tbusy)
- {
- ticks = (signed) (jiffies - dev->trans_start);
-
- if (ticks < scc->kiss.maxdefer*HZ || scc == NULL)
- return 1;
-
- /*
- * Throw away transmission queue.
- */
-
- if (scc->tx_wdog.next)
- del_timer(&scc->tx_wdog);
- t_busy((unsigned long) scc);
- dev->trans_start = jiffies;
- }
-
- if (scc == NULL || scc->magic != SCC_MAGIC)
+ if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy)
{
dev_kfree_skb(skb, FREE_WRITE);
return 0;
@@ -1692,10 +1716,13 @@
save_flags(flags);
cli();
+ if (skb_queue_len(&scc->tx_queue) >= MAXQUEUE-1)
+ {
+ struct sk_buff *skb_del;
+ skb_del = __skb_dequeue(&scc->tx_queue);
+ dev_kfree_skb(skb_del, FREE_WRITE);
+ }
__skb_queue_tail(&scc->tx_queue, skb);
-
- if (skb_queue_len(&scc->tx_queue) == MAXQUEUE)
- scc_lock_dev(scc);
dev->trans_start = jiffies;
@@ -1729,6 +1756,7 @@
* SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg
* SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg
* SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg
+ * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg
*/
static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
@@ -1736,6 +1764,7 @@
struct scc_kiss_cmd kiss_cmd;
struct scc_mem_config memcfg;
struct scc_hw_config hwcfg;
+ struct scc_calibrate cal;
int chan;
unsigned char device_name[10];
void *arg;
@@ -1942,6 +1971,14 @@
if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
return -EINVAL;
return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param);
+
+ case SIOCSCCCAL:
+ if (!suser()) return -EPERM;
+ if (!arg || copy_from_user(&cal, arg, sizeof(cal)))
+ return -EINVAL;
+
+ scc_start_calibrate(scc, cal.time, cal.pattern);
+ return 0;
default:
return -ENOIOCTLCMD;
@@ -2164,7 +2201,7 @@
result = scc_init();
if (result == 0)
- printk(KERN_INFO "Copyright 1993,1996 Joerg Reuter DL1BKE (jreuter@lykos.tng.oche.de)\n");
+ printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@lykos.tng.oche.de)\n");
return result;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov