patch-2.1.132 linux/drivers/net/hamradio/scc.c
Next file: linux/drivers/net/hp-plus.c
Previous file: linux/drivers/net/es3210.c
Back to the patch index
Back to the overall index
- Lines: 629
- Date:
Fri Dec 18 13:57:21 1998
- Orig file:
v2.1.131/linux/drivers/net/hamradio/scc.c
- Orig date:
Thu Feb 12 20:56:08 1998
diff -u --recursive --new-file v2.1.131/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
@@ -1,4 +1,4 @@
-#define RCS_ID "$Id: scc.c,v 1.73 1998/01/29 17:38:51 jreuter Exp jreuter $"
+#define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $"
#define VERSION "3.0"
#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
@@ -60,22 +60,22 @@
Incomplete history of z8530drv:
-------------------------------
- 940913 - started to write the driver, rescued most of my own
- code (and Hans Alblas' memory buffer pool concept) from
- an earlier project "sccdrv" which was initiated by
- Guido ten Dolle. Not much of the old driver survived,
- though. The first version I put my hands on was sccdrv1.3
- from August 1993. The memory buffer pool concept
- appeared in an unauthorized sccdrv version (1.5) from
- August 1994.
+ 1994-09-13 started to write the driver, rescued most of my own
+ code (and Hans Alblas' memory buffer pool concept) from
+ an earlier project "sccdrv" which was initiated by
+ Guido ten Dolle. Not much of the old driver survived,
+ though. The first version I put my hands on was sccdrv1.3
+ from August 1993. The memory buffer pool concept
+ appeared in an unauthorized sccdrv version (1.5) from
+ August 1994.
- 950131 - changed copyright notice to GPL without limitations.
+ 1995-01-31 changed copyright notice to GPL without limitations.
.
. <SNIP>
.
- 961005 - New semester, new driver...
+ 1996-10-05 New semester, new driver...
* KISS TNC emulator removed (TTY driver)
* Source moved to drivers/net/
@@ -88,12 +88,22 @@
The move to version number 3.0 reflects theses changes.
You can use 'kissbridge' if you need a KISS TNC emulator.
- 961213 - Fixed for Linux networking changes. (G4KLX)
- 970108 - Fixed the remaining problems.
- 970402 - Hopefully fixed the problems with the new *_timer()
- routines, added calibration code.
- 971012 - Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
- 980129 - Small fix to avoid lock-up on initialization
+ 1996-12-13 Fixed for Linux networking changes. (G4KLX)
+ 1997-01-08 Fixed the remaining problems.
+ 1997-04-02 Hopefully fixed the problems with the new *_timer()
+ routines, added calibration code.
+ 1997-10-12 Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
+ 1998-01-29 Small fix to avoid lock-up on initialization
+ 1998-09-29 Fixed the "grouping" bugs, tx_inhibit works again,
+ using dev->tx_queue_len now instead of MAXQUEUE now.
+ 1998-10-21 Postponed the spinlock changes, would need a lot of
+ testing I currently don't have the time to. Softdcd doesn't
+ work.
+ 1998-11-04 Softdcd does not work correctly in DPLL mode, in fact it
+ never did. The DPLL locks on noise, the SYNC unit sees
+ flags that aren't... Restarting the DPLL does not help
+ either, it resynchronizes too slow and the first received
+ frame gets lost.
Thanks to all who contributed to this driver with ideas and bug
reports!
@@ -119,22 +129,22 @@
Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU
Internet: jreuter@poboxes.com
- www : http://www.rat.de/jr
+ www : http://poboxes.com/jreuter/
*/
/* ----------------------------------------------------------------------- */
#undef SCC_LDELAY 1 /* slow it even a bit more down */
-#undef DONT_CHECK /* don't look if the SCCs you specified are available */
+#undef SCC_DONT_CHECK /* don't look if the SCCs you specified are available */
-#define MAXSCC 4 /* number of max. supported chips */
-#define BUFSIZE 384 /* must not exceed 4096 */
-#define MAXQUEUE 8 /* number of buffers we queue ourself */
-#undef DISABLE_ALL_INTS /* use cli()/sti() in ISR instead of */
+#define SCC_MAXCHIPS 4 /* number of max. supported chips */
+#define SCC_BUFSIZE 384 /* must not exceed 4096 */
+#undef SCC_DISABLE_ALL_INTS /* use cli()/sti() in ISR instead of */
/* enable_irq()/disable_irq() */
#undef SCC_DEBUG
-#define DEFAULT_CLOCK 4915200 /* default pclock if nothing is specified */
+#define SCC_DEFAULT_CLOCK 4915200
+ /* default pclock if nothing is specified */
/* ----------------------------------------------------------------------- */
@@ -214,13 +224,13 @@
static struct irqflags { unsigned char used : 1; } Ivec[16];
-static struct scc_channel SCC_Info[2 * MAXSCC]; /* information per channel */
+static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS]; /* information per channel */
static struct scc_ctrl {
io_port chan_A;
io_port chan_B;
int irq;
-} SCC_ctrl[MAXSCC+1];
+} SCC_ctrl[SCC_MAXCHIPS+1];
static unsigned char Driver_Initialized = 0;
static int Nchips = 0;
@@ -236,7 +246,7 @@
/* These provide interrupt save 2-step access to the Z8530 registers */
-extern __inline__ unsigned char InReg(io_port port, unsigned char reg)
+static inline unsigned char InReg(io_port port, unsigned char reg)
{
unsigned long flags;
unsigned char r;
@@ -256,7 +266,7 @@
return r;
}
-extern __inline__ void OutReg(io_port port, unsigned char reg, unsigned char val)
+static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
{
unsigned long flags;
@@ -272,31 +282,31 @@
restore_flags(flags);
}
-extern __inline__ void wr(struct scc_channel *scc, unsigned char reg,
+static inline void wr(struct scc_channel *scc, unsigned char reg,
unsigned char val)
{
OutReg(scc->ctrl, reg, (scc->wreg[reg] = val));
}
-extern __inline__ void or(struct scc_channel *scc, unsigned char reg, unsigned char val)
+static inline void or(struct scc_channel *scc, unsigned char reg, unsigned char val)
{
OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val));
}
-extern __inline__ void cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
+static inline void cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
{
OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val));
}
-#ifdef DISABLE_ALL_INTS
-extern __inline__ void scc_cli(int irq)
+#ifdef SCC_DISABLE_ALL_INTS
+static inline void scc_cli(int irq)
{ cli(); }
-extern __inline__ void scc_sti(int irq)
+static inline void scc_sti(int irq)
{ sti(); }
#else
-static __inline__ void scc_cli(int irq)
+static inline void scc_cli(int irq)
{ disable_irq(irq); }
-static __inline__ void scc_sti(int irq)
+static inline void scc_sti(int irq)
{ enable_irq(irq); }
#endif
@@ -305,17 +315,17 @@
/* ******************************************************************** */
-extern __inline__ void scc_lock_dev(struct scc_channel *scc)
+static inline void scc_lock_dev(struct scc_channel *scc)
{
scc->dev->tbusy = 1;
}
-extern __inline__ void scc_unlock_dev(struct scc_channel *scc)
+static inline void scc_unlock_dev(struct scc_channel *scc)
{
scc->dev->tbusy = 0;
}
-extern __inline__ void scc_discard_buffers(struct scc_channel *scc)
+static inline void scc_discard_buffers(struct scc_channel *scc)
{
unsigned long flags;
@@ -343,7 +353,7 @@
/* ----> subroutines for the interrupt handlers <---- */
-extern __inline__ void scc_notify(struct scc_channel *scc, int event)
+static inline void scc_notify(struct scc_channel *scc, int event)
{
struct sk_buff *skb;
char *bp;
@@ -362,7 +372,7 @@
scc->stat.nospace++;
}
-extern __inline__ void flush_rx_FIFO(struct scc_channel *scc)
+static inline void flush_rx_FIFO(struct scc_channel *scc)
{
int k;
@@ -377,12 +387,18 @@
}
}
+static void start_hunt(struct scc_channel *scc)
+{
+ if ((scc->modem.clocksrc != CLK_EXTERNAL))
+ OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
+ or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
+}
/* ----> four different interrupt handlers for Tx, Rx, changing of */
/* DCD/CTS and Rx/Tx errors */
/* Transmitter interrupt handler */
-extern __inline__ void scc_txint(struct scc_channel *scc)
+static inline void scc_txint(struct scc_channel *scc)
{
struct sk_buff *skb;
@@ -446,7 +462,7 @@
/* External/Status interrupt handler */
-extern __inline__ void scc_exint(struct scc_channel *scc)
+static inline void scc_exint(struct scc_channel *scc)
{
unsigned char status,changes,chg_and_stat;
@@ -461,35 +477,39 @@
if (chg_and_stat & BRK_ABRT) /* Received an ABORT */
flush_rx_FIFO(scc);
+ /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
+
+ if ((changes & SYNC_HUNT) && scc->kiss.softdcd)
+ {
+ if (status & SYNC_HUNT)
+ {
+ scc->dcd = 0;
+ flush_rx_FIFO(scc);
+ if ((scc->modem.clocksrc != CLK_EXTERNAL))
+ OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
+ } else {
+ scc->dcd = 1;
+ }
+
+ scc_notify(scc, scc->dcd? HWEV_DCD_OFF:HWEV_DCD_ON);
+ }
/* DCD: on = start to receive packet, off = ABORT condition */
/* (a successfully received packet generates a special condition int) */
- if(changes & DCD) /* DCD input changed state */
+ if((changes & DCD) && !scc->kiss.softdcd) /* DCD input changed state */
{
if(status & DCD) /* DCD is now ON */
{
- if (scc->modem.clocksrc != CLK_EXTERNAL)
- OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
-
- or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
+ start_hunt(scc);
+ scc->dcd = 1;
} else { /* DCD is now OFF */
cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
flush_rx_FIFO(scc);
+ scc->dcd = 0;
}
- if (!scc->kiss.softdcd)
- scc_notify(scc, (status & DCD)? HWEV_DCD_ON:HWEV_DCD_OFF);
- }
-
- /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
-
- if (changes & SYNC_HUNT)
- {
- if (scc->kiss.softdcd)
- scc_notify(scc, (status & SYNC_HUNT)? HWEV_DCD_OFF:HWEV_DCD_ON);
- else
- cl(scc,R15,SYNCIE); /* oops, we were too lazy to disable this? */
+ scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
}
#ifdef notdef
@@ -527,7 +547,7 @@
/* Receiver interrupt handler */
-extern __inline__ void scc_rxint(struct scc_channel *scc)
+static inline void scc_rxint(struct scc_channel *scc)
{
struct sk_buff *skb;
@@ -575,7 +595,7 @@
/* Receive Special Condition interrupt handler */
-extern __inline__ void scc_spint(struct scc_channel *scc)
+static inline void scc_spint(struct scc_channel *scc)
{
unsigned char status;
struct sk_buff *skb;
@@ -646,8 +666,6 @@
struct scc_ctrl *ctrl;
int k;
- scc_cli(irq);
-
if (Vector_Latch)
{
for(k=0; k < SCC_IRQTIMEOUT; k++)
@@ -665,7 +683,6 @@
OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */
}
- scc_sti(irq);
if (k == SCC_IRQTIMEOUT)
printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
@@ -718,8 +735,6 @@
} else
ctrl++;
}
-
- scc_sti(irq);
}
@@ -731,7 +746,7 @@
/* ----> set SCC channel speed <---- */
-extern __inline__ void set_brg(struct scc_channel *scc, unsigned int tc)
+static inline void set_brg(struct scc_channel *scc, unsigned int tc)
{
cl(scc,R14,BRENABL); /* disable baudrate generator */
wr(scc,R12,tc & 255); /* brg rate LOW */
@@ -739,7 +754,7 @@
or(scc,R14,BRENABL); /* enable baudrate generator */
}
-extern __inline__ void set_speed(struct scc_channel *scc)
+static inline void set_speed(struct scc_channel *scc)
{
disable_irq(scc->irq);
@@ -752,7 +767,7 @@
/* ----> initialize a SCC channel <---- */
-extern __inline__ void init_brg(struct scc_channel *scc)
+static inline void init_brg(struct scc_channel *scc)
{
wr(scc, R14, BRSRC); /* BRG source = PCLK */
OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */
@@ -875,19 +890,15 @@
wr(scc,R7,AUTOEOM);
}
- if((InReg(scc->ctrl,R0)) & DCD) /* DCD is now ON */
+ if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD))
+ /* DCD is now ON */
{
- if (scc->modem.clocksrc != CLK_EXTERNAL)
- or(scc,R14, SEARCH);
-
- or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
+ start_hunt(scc);
}
/* enable ABORT, DCD & SYNC/HUNT interrupts */
- wr(scc,R15, BRKIE|TxUIE|DCDIE);
- if (scc->kiss.softdcd)
- or(scc,R15, SYNCIE);
+ wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE));
Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */
@@ -940,14 +951,21 @@
{
#ifdef CONFIG_SCC_TRXECHO
cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */
- cl(scc, R15, DCDIE); /* No DCD changes, please */
+ cl(scc, R15, DCDIE|SYNCIE); /* No DCD changes, please */
#endif
set_brg(scc, time_const); /* reprogram baudrate generator */
/* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */
wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);
- or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
+ /* By popular demand: tx_inhibit */
+ if (scc->kiss.tx_inhibit)
+ {
+ or(scc,R5, TxENAB);
+ scc->wreg[R5] |= RTS;
+ } else {
+ or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
+ }
} else {
cl(scc,R5,RTS|TxENAB);
@@ -955,10 +973,14 @@
/* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */
wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
-#ifdef CONFIG_SCC_TRXECHO
- or(scc,R3,RxENABLE|ENT_HM);
- or(scc,R15, DCDIE);
+
+#ifndef CONFIG_SCC_TRXECHO
+ if (scc->kiss.softdcd)
#endif
+ {
+ or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE);
+ start_hunt(scc);
+ }
}
} else {
if (tx)
@@ -967,22 +989,30 @@
if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
{
cl(scc, R3, RxENABLE);
- cl(scc, R15, DCDIE);
+ cl(scc, R15, DCDIE|SYNCIE);
}
#endif
-
- or(scc,R5,RTS|TxENAB); /* enable tx */
+ if (scc->kiss.tx_inhibit)
+ {
+ or(scc,R5, TxENAB);
+ scc->wreg[R5] |= RTS;
+ } else {
+ or(scc,R5,RTS|TxENAB); /* enable tx */
+ }
} else {
cl(scc,R5,RTS|TxENAB); /* disable tx */
-#ifdef CONFIG_SCC_TRXECHO
- if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
+ if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) &&
+#ifndef CONFIG_SCC_TRXECHO
+ scc->kiss.softdcd)
+#else
+ 1)
+#endif
{
- or(scc, R3, RxENABLE|ENT_HM);
- or(scc, R15, DCDIE);
+ or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE);
+ start_hunt(scc);
}
-#endif
}
}
@@ -1088,7 +1118,7 @@
static unsigned char Rand = 17;
-extern __inline__ int is_grouped(struct scc_channel *scc)
+static inline int is_grouped(struct scc_channel *scc)
{
int k;
struct scc_channel *scc2;
@@ -1109,7 +1139,7 @@
if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
return 1;
- if ( (grp1 & RXGROUP) && (scc2->status & DCD) )
+ if ( (grp1 & RXGROUP) && scc2->dcd )
return 1;
}
}
@@ -1144,7 +1174,7 @@
{
Rand = Rand * 17 + 31;
- if ( (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)) || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
+ if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
{
scc_start_defer(scc);
scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime);
@@ -1317,8 +1347,6 @@
static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg)
{
- int dcd;
-
switch (cmd)
{
case PARAM_TXDELAY: scc->kiss.txdelay=arg; break;
@@ -1338,9 +1366,14 @@
case PARAM_SOFTDCD:
scc->kiss.softdcd=arg;
if (arg)
+ {
or(scc, R15, SYNCIE);
- else
+ cl(scc, R15, DCDIE);
+ start_hunt(scc);
+ } else {
+ or(scc, R15, DCDIE);
cl(scc, R15, SYNCIE);
+ }
break;
case PARAM_SPEED:
@@ -1369,8 +1402,7 @@
break;
case PARAM_HWEVENT:
- dcd = (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD));
- scc_notify(scc, dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
+ scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
break;
default: return -EINVAL;
@@ -1449,9 +1481,10 @@
scc->tx_wdog.data = (unsigned long) scc;
scc->tx_wdog.function = scc_stop_calibrate;
- scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
+ scc->tx_wdog.expires = jiffies + HZ*duration;
add_timer(&scc->tx_wdog);
-
+
+ /* This doesn't seem to work. Why not? */
wr(scc, R6, 0);
wr(scc, R7, pattern);
@@ -1680,6 +1713,7 @@
skb->dev = scc->dev;
skb->protocol = htons(ETH_P_AX25);
skb->mac.raw = skb->data;
+ skb->pkt_type = PACKET_HOST;
netif_rx(skb);
return;
@@ -1722,7 +1756,7 @@
save_flags(flags);
cli();
- if (skb_queue_len(&scc->tx_queue) >= MAXQUEUE-1)
+ if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len)
{
struct sk_buff *skb_del;
skb_del = __skb_dequeue(&scc->tx_queue);
@@ -1791,7 +1825,7 @@
if (!suser()) return -EPERM;
if (!arg) return -EFAULT;
- if (Nchips >= MAXSCC)
+ if (Nchips >= SCC_MAXCHIPS)
return -EINVAL;
if (copy_from_user(&hwcfg, arg, sizeof(hwcfg)))
@@ -1811,14 +1845,15 @@
Vector_Latch = hwcfg.vector_latch;
if (hwcfg.clock == 0)
- hwcfg.clock = DEFAULT_CLOCK;
+ hwcfg.clock = SCC_DEFAULT_CLOCK;
-#ifndef DONT_CHECK
+#ifndef SCC_DONT_CHECK
disable_irq(hwcfg.irq);
check_region(scc->ctrl, 1);
Outb(hwcfg.ctrl_a, 0);
- udelay(5);
+ OutReg(hwcfg.ctrl_a, R9, FHWRES);
+ udelay(100);
OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
udelay(5);
@@ -1853,7 +1888,7 @@
SCC_Info[2*Nchips+chan].option = hwcfg.option;
SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;
-#ifdef DONT_CHECK
+#ifdef SCC_DONT_CHECK
printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n",
device_name,
SCC_Info[2*Nchips+chan].data,
@@ -1903,7 +1938,7 @@
if (!suser()) return -EPERM;
if (!arg) return -EINVAL;
- scc->stat.bufsize = BUFSIZE;
+ scc->stat.bufsize = SCC_BUFSIZE;
if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem)))
return -EINVAL;
@@ -1980,7 +2015,7 @@
case SIOCSCCCAL:
if (!suser()) return -EPERM;
- if (!arg || copy_from_user(&cal, arg, sizeof(cal)))
+ if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0)
return -EINVAL;
scc_start_calibrate(scc, cal.time, cal.pattern);
@@ -2169,7 +2204,7 @@
/* pre-init channel information */
- for (chip = 0; chip < MAXSCC; chip++)
+ for (chip = 0; chip < SCC_MAXCHIPS; chip++)
{
memset((char *) &SCC_Info[2*chip ], 0, sizeof(struct scc_channel));
memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel));
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov