11da177e4SLinus Torvalds #define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $"
21da177e4SLinus Torvalds
31da177e4SLinus Torvalds #define VERSION "3.0"
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds /*
61da177e4SLinus Torvalds * Please use z8530drv-utils-3.0 with this version.
71da177e4SLinus Torvalds * ------------------
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * You can find a subset of the documentation in
10d4dd87f8SMauro Carvalho Chehab * Documentation/networking/device_drivers/hamradio/z8530drv.rst.
111da177e4SLinus Torvalds */
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds /*
141da177e4SLinus Torvalds ********************************************************************
151da177e4SLinus Torvalds * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 *
161da177e4SLinus Torvalds ********************************************************************
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds ********************************************************************
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds Copyright (c) 1993, 2000 Joerg Reuter DL1BKE
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds portions (c) 1993 Guido ten Dolle PE1NNZ
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds ********************************************************************
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds The driver and the programs in the archive are UNDER CONSTRUCTION.
281da177e4SLinus Torvalds The code is likely to fail, and so your kernel could --- even
291da177e4SLinus Torvalds a whole network.
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds This driver is intended for Amateur Radio use. If you are running it
321da177e4SLinus Torvalds for commercial purposes, please drop me a note. I am nosy...
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds ...BUT:
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds ! You m u s t recognize the appropriate legislations of your country !
371da177e4SLinus Torvalds ! before you connect a radio to the SCC board and start to transmit or !
381da177e4SLinus Torvalds ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! !
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds For non-Amateur-Radio use please note that you might need a special
411da177e4SLinus Torvalds allowance/licence from the designer of the SCC Board and/or the
421da177e4SLinus Torvalds MODEM.
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify
451da177e4SLinus Torvalds it under the terms of the (modified) GNU General Public License
461da177e4SLinus Torvalds delivered with the Linux kernel source.
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds This program is distributed in the hope that it will be useful,
491da177e4SLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of
501da177e4SLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
511da177e4SLinus Torvalds GNU General Public License for more details.
521da177e4SLinus Torvalds
531da177e4SLinus Torvalds You should find a copy of the GNU General Public License in
541da177e4SLinus Torvalds /usr/src/linux/COPYING;
551da177e4SLinus Torvalds
561da177e4SLinus Torvalds ********************************************************************
571da177e4SLinus Torvalds
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds Incomplete history of z8530drv:
601da177e4SLinus Torvalds -------------------------------
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds 1994-09-13 started to write the driver, rescued most of my own
631da177e4SLinus Torvalds code (and Hans Alblas' memory buffer pool concept) from
641da177e4SLinus Torvalds an earlier project "sccdrv" which was initiated by
651da177e4SLinus Torvalds Guido ten Dolle. Not much of the old driver survived,
661da177e4SLinus Torvalds though. The first version I put my hands on was sccdrv1.3
671da177e4SLinus Torvalds from August 1993. The memory buffer pool concept
681da177e4SLinus Torvalds appeared in an unauthorized sccdrv version (1.5) from
691da177e4SLinus Torvalds August 1994.
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds 1995-01-31 changed copyright notice to GPL without limitations.
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds .
741da177e4SLinus Torvalds . <SNIP>
751da177e4SLinus Torvalds .
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds 1996-10-05 New semester, new driver...
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds * KISS TNC emulator removed (TTY driver)
801da177e4SLinus Torvalds * Source moved to drivers/net/
811da177e4SLinus Torvalds * Includes Z8530 defines from drivers/net/z8530.h
821da177e4SLinus Torvalds * Uses sk_buffer memory management
831da177e4SLinus Torvalds * Reduced overhead of /proc/net/z8530drv output
841da177e4SLinus Torvalds * Streamlined quite a lot things
851da177e4SLinus Torvalds * Invents brand new bugs... ;-)
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds The move to version number 3.0 reflects theses changes.
881da177e4SLinus Torvalds You can use 'kissbridge' if you need a KISS TNC emulator.
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds 1996-12-13 Fixed for Linux networking changes. (G4KLX)
911da177e4SLinus Torvalds 1997-01-08 Fixed the remaining problems.
921da177e4SLinus Torvalds 1997-04-02 Hopefully fixed the problems with the new *_timer()
931da177e4SLinus Torvalds routines, added calibration code.
941da177e4SLinus Torvalds 1997-10-12 Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
951da177e4SLinus Torvalds 1998-01-29 Small fix to avoid lock-up on initialization
961da177e4SLinus Torvalds 1998-09-29 Fixed the "grouping" bugs, tx_inhibit works again,
971da177e4SLinus Torvalds using dev->tx_queue_len now instead of MAXQUEUE now.
981da177e4SLinus Torvalds 1998-10-21 Postponed the spinlock changes, would need a lot of
991da177e4SLinus Torvalds testing I currently don't have the time to. Softdcd doesn't
1001da177e4SLinus Torvalds work.
1011da177e4SLinus Torvalds 1998-11-04 Softdcd does not work correctly in DPLL mode, in fact it
1021da177e4SLinus Torvalds never did. The DPLL locks on noise, the SYNC unit sees
1031da177e4SLinus Torvalds flags that aren't... Restarting the DPLL does not help
1041da177e4SLinus Torvalds either, it resynchronizes too slow and the first received
1051da177e4SLinus Torvalds frame gets lost.
1061da177e4SLinus Torvalds 2000-02-13 Fixed for new network driver interface changes, still
1071da177e4SLinus Torvalds does TX timeouts itself since it uses its own queue
1081da177e4SLinus Torvalds scheme.
1091da177e4SLinus Torvalds
1101da177e4SLinus Torvalds Thanks to all who contributed to this driver with ideas and bug
1111da177e4SLinus Torvalds reports!
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds NB -- if you find errors, change something, please let me know
1141da177e4SLinus Torvalds first before you distribute it... And please don't touch
1151da177e4SLinus Torvalds the version number. Just replace my callsign in
1161da177e4SLinus Torvalds "v3.0.dl1bke" with your own. Just to avoid confusion...
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds If you want to add your modification to the linux distribution
1191da177e4SLinus Torvalds please (!) contact me first.
1201da177e4SLinus Torvalds
1211da177e4SLinus Torvalds New versions of the driver will be announced on the linux-hams
1221da177e4SLinus Torvalds mailing list on vger.kernel.org. To subscribe send an e-mail
1231da177e4SLinus Torvalds to majordomo@vger.kernel.org with the following line in
1241da177e4SLinus Torvalds the body of the mail:
1251da177e4SLinus Torvalds
1261da177e4SLinus Torvalds subscribe linux-hams
1271da177e4SLinus Torvalds
1281da177e4SLinus Torvalds The content of the "Subject" field will be ignored.
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds vy 73,
1311da177e4SLinus Torvalds Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
1321da177e4SLinus Torvalds AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU
1331da177e4SLinus Torvalds Internet: jreuter@yaina.de
1341da177e4SLinus Torvalds www : http://yaina.de/jreuter
1351da177e4SLinus Torvalds */
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds /* ----------------------------------------------------------------------- */
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds #undef SCC_LDELAY /* slow it even a bit more down */
1401da177e4SLinus Torvalds #undef SCC_DONT_CHECK /* don't look if the SCCs you specified are available */
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds #define SCC_MAXCHIPS 4 /* number of max. supported chips */
1431da177e4SLinus Torvalds #define SCC_BUFSIZE 384 /* must not exceed 4096 */
1441da177e4SLinus Torvalds #undef SCC_DEBUG
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds #define SCC_DEFAULT_CLOCK 4915200
1471da177e4SLinus Torvalds /* default pclock if nothing is specified */
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds /* ----------------------------------------------------------------------- */
1501da177e4SLinus Torvalds
151b6459415SJakub Kicinski #include <linux/compat.h>
1521da177e4SLinus Torvalds #include <linux/module.h>
1531da177e4SLinus Torvalds #include <linux/errno.h>
1541da177e4SLinus Torvalds #include <linux/signal.h>
1551da177e4SLinus Torvalds #include <linux/timer.h>
1561da177e4SLinus Torvalds #include <linux/interrupt.h>
1571da177e4SLinus Torvalds #include <linux/ioport.h>
1581da177e4SLinus Torvalds #include <linux/string.h>
1591da177e4SLinus Torvalds #include <linux/in.h>
1601da177e4SLinus Torvalds #include <linux/fcntl.h>
1611da177e4SLinus Torvalds #include <linux/ptrace.h>
1621da177e4SLinus Torvalds #include <linux/delay.h>
1631da177e4SLinus Torvalds #include <linux/skbuff.h>
1641da177e4SLinus Torvalds #include <linux/netdevice.h>
1651da177e4SLinus Torvalds #include <linux/rtnetlink.h>
1661da177e4SLinus Torvalds #include <linux/if_ether.h>
1671da177e4SLinus Torvalds #include <linux/if_arp.h>
1681da177e4SLinus Torvalds #include <linux/socket.h>
1691da177e4SLinus Torvalds #include <linux/init.h>
1701da177e4SLinus Torvalds #include <linux/scc.h>
1711da177e4SLinus Torvalds #include <linux/ctype.h>
1721da177e4SLinus Torvalds #include <linux/kernel.h>
1731da177e4SLinus Torvalds #include <linux/proc_fs.h>
1741da177e4SLinus Torvalds #include <linux/seq_file.h>
1751da177e4SLinus Torvalds #include <linux/bitops.h>
1761da177e4SLinus Torvalds
177457c4cbcSEric W. Biederman #include <net/net_namespace.h>
1781da177e4SLinus Torvalds #include <net/ax25.h>
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds #include <asm/irq.h>
1811da177e4SLinus Torvalds #include <asm/io.h>
1827c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds #include "z8530.h"
1851da177e4SLinus Torvalds
186afa8c78bSAndi Kleen static const char banner[] __initconst = KERN_INFO \
187eb33ae24SHannes Eder "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n";
1881da177e4SLinus Torvalds
18941e9475cSKees Cook static void t_dwait(struct timer_list *t);
19041e9475cSKees Cook static void t_txdelay(struct timer_list *t);
19141e9475cSKees Cook static void t_tail(struct timer_list *t);
19241e9475cSKees Cook static void t_busy(struct timer_list *);
19341e9475cSKees Cook static void t_maxkeyup(struct timer_list *);
19441e9475cSKees Cook static void t_idle(struct timer_list *t);
1951da177e4SLinus Torvalds static void scc_tx_done(struct scc_channel *);
19641e9475cSKees Cook static void scc_start_tx_timer(struct scc_channel *,
19741e9475cSKees Cook void (*)(struct timer_list *), unsigned long);
1981da177e4SLinus Torvalds static void scc_start_maxkeyup(struct scc_channel *);
1991da177e4SLinus Torvalds static void scc_start_defer(struct scc_channel *);
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds static void z8530_init(void);
2021da177e4SLinus Torvalds
2031da177e4SLinus Torvalds static void init_channel(struct scc_channel *scc);
2041da177e4SLinus Torvalds static void scc_key_trx (struct scc_channel *scc, char tx);
2051da177e4SLinus Torvalds static void scc_init_timer(struct scc_channel *scc);
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds static int scc_net_alloc(const char *name, struct scc_channel *scc);
2081da177e4SLinus Torvalds static void scc_net_setup(struct net_device *dev);
2091da177e4SLinus Torvalds static int scc_net_open(struct net_device *dev);
2101da177e4SLinus Torvalds static int scc_net_close(struct net_device *dev);
2111da177e4SLinus Torvalds static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb);
21236e4d64aSStephen Hemminger static netdev_tx_t scc_net_tx(struct sk_buff *skb,
21336e4d64aSStephen Hemminger struct net_device *dev);
21425ec92fbSArnd Bergmann static int scc_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
21525ec92fbSArnd Bergmann void __user *data, int cmd);
2161da177e4SLinus Torvalds static int scc_net_set_mac_address(struct net_device *dev, void *addr);
2171da177e4SLinus Torvalds static struct net_device_stats * scc_net_get_stats(struct net_device *dev);
2181da177e4SLinus Torvalds
2191da177e4SLinus Torvalds static unsigned char SCC_DriverName[] = "scc";
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS];
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS]; /* information per channel */
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds static struct scc_ctrl {
2261da177e4SLinus Torvalds io_port chan_A;
2271da177e4SLinus Torvalds io_port chan_B;
2281da177e4SLinus Torvalds int irq;
2291da177e4SLinus Torvalds } SCC_ctrl[SCC_MAXCHIPS+1];
2301da177e4SLinus Torvalds
2311da177e4SLinus Torvalds static unsigned char Driver_Initialized;
2321da177e4SLinus Torvalds static int Nchips;
2331da177e4SLinus Torvalds static io_port Vector_Latch;
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds
2361da177e4SLinus Torvalds /* ******************************************************************** */
2371da177e4SLinus Torvalds /* * Port Access Functions * */
2381da177e4SLinus Torvalds /* ******************************************************************** */
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds /* These provide interrupt save 2-step access to the Z8530 registers */
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds static DEFINE_SPINLOCK(iolock); /* Guards paired accesses */
2431da177e4SLinus Torvalds
InReg(io_port port,unsigned char reg)2441da177e4SLinus Torvalds static inline unsigned char InReg(io_port port, unsigned char reg)
2451da177e4SLinus Torvalds {
2461da177e4SLinus Torvalds unsigned long flags;
2471da177e4SLinus Torvalds unsigned char r;
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds spin_lock_irqsave(&iolock, flags);
2501da177e4SLinus Torvalds #ifdef SCC_LDELAY
2511da177e4SLinus Torvalds Outb(port, reg);
2521da177e4SLinus Torvalds udelay(SCC_LDELAY);
2531da177e4SLinus Torvalds r=Inb(port);
2541da177e4SLinus Torvalds udelay(SCC_LDELAY);
2551da177e4SLinus Torvalds #else
2561da177e4SLinus Torvalds Outb(port, reg);
2571da177e4SLinus Torvalds r=Inb(port);
2581da177e4SLinus Torvalds #endif
2591da177e4SLinus Torvalds spin_unlock_irqrestore(&iolock, flags);
2601da177e4SLinus Torvalds return r;
2611da177e4SLinus Torvalds }
2621da177e4SLinus Torvalds
OutReg(io_port port,unsigned char reg,unsigned char val)2631da177e4SLinus Torvalds static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
2641da177e4SLinus Torvalds {
2651da177e4SLinus Torvalds unsigned long flags;
2661da177e4SLinus Torvalds
2671da177e4SLinus Torvalds spin_lock_irqsave(&iolock, flags);
2681da177e4SLinus Torvalds #ifdef SCC_LDELAY
2691da177e4SLinus Torvalds Outb(port, reg); udelay(SCC_LDELAY);
2701da177e4SLinus Torvalds Outb(port, val); udelay(SCC_LDELAY);
2711da177e4SLinus Torvalds #else
2721da177e4SLinus Torvalds Outb(port, reg);
2731da177e4SLinus Torvalds Outb(port, val);
2741da177e4SLinus Torvalds #endif
2751da177e4SLinus Torvalds spin_unlock_irqrestore(&iolock, flags);
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds
wr(struct scc_channel * scc,unsigned char reg,unsigned char val)2781da177e4SLinus Torvalds static inline void wr(struct scc_channel *scc, unsigned char reg,
2791da177e4SLinus Torvalds unsigned char val)
2801da177e4SLinus Torvalds {
2811da177e4SLinus Torvalds OutReg(scc->ctrl, reg, (scc->wreg[reg] = val));
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds
or(struct scc_channel * scc,unsigned char reg,unsigned char val)2841da177e4SLinus Torvalds static inline void or(struct scc_channel *scc, unsigned char reg, unsigned char val)
2851da177e4SLinus Torvalds {
2861da177e4SLinus Torvalds OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val));
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds
cl(struct scc_channel * scc,unsigned char reg,unsigned char val)2891da177e4SLinus Torvalds static inline void cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
2901da177e4SLinus Torvalds {
2911da177e4SLinus Torvalds OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val));
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds /* ******************************************************************** */
2951da177e4SLinus Torvalds /* * Some useful macros * */
2961da177e4SLinus Torvalds /* ******************************************************************** */
2971da177e4SLinus Torvalds
scc_discard_buffers(struct scc_channel * scc)2981da177e4SLinus Torvalds static inline void scc_discard_buffers(struct scc_channel *scc)
2991da177e4SLinus Torvalds {
3001da177e4SLinus Torvalds unsigned long flags;
3011da177e4SLinus Torvalds
3021da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
3031da177e4SLinus Torvalds if (scc->tx_buff != NULL)
3041da177e4SLinus Torvalds {
305*3727f742SYang Yingliang dev_kfree_skb_irq(scc->tx_buff);
3061da177e4SLinus Torvalds scc->tx_buff = NULL;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds
309b03efcfbSDavid S. Miller while (!skb_queue_empty(&scc->tx_queue))
310*3727f742SYang Yingliang dev_kfree_skb_irq(skb_dequeue(&scc->tx_queue));
3111da177e4SLinus Torvalds
3121da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds
3151da177e4SLinus Torvalds
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds /* ******************************************************************** */
3181da177e4SLinus Torvalds /* * Interrupt Service Routines * */
3191da177e4SLinus Torvalds /* ******************************************************************** */
3201da177e4SLinus Torvalds
3211da177e4SLinus Torvalds
3221da177e4SLinus Torvalds /* ----> subroutines for the interrupt handlers <---- */
3231da177e4SLinus Torvalds
scc_notify(struct scc_channel * scc,int event)3241da177e4SLinus Torvalds static inline void scc_notify(struct scc_channel *scc, int event)
3251da177e4SLinus Torvalds {
3261da177e4SLinus Torvalds struct sk_buff *skb;
3271da177e4SLinus Torvalds char *bp;
3281da177e4SLinus Torvalds
3291da177e4SLinus Torvalds if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA)
3301da177e4SLinus Torvalds return;
3311da177e4SLinus Torvalds
3321da177e4SLinus Torvalds skb = dev_alloc_skb(2);
3331da177e4SLinus Torvalds if (skb != NULL)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds bp = skb_put(skb, 2);
3361da177e4SLinus Torvalds *bp++ = PARAM_HWEVENT;
3371da177e4SLinus Torvalds *bp++ = event;
3381da177e4SLinus Torvalds scc_net_rx(scc, skb);
3391da177e4SLinus Torvalds } else
3401da177e4SLinus Torvalds scc->stat.nospace++;
3411da177e4SLinus Torvalds }
3421da177e4SLinus Torvalds
flush_rx_FIFO(struct scc_channel * scc)3431da177e4SLinus Torvalds static inline void flush_rx_FIFO(struct scc_channel *scc)
3441da177e4SLinus Torvalds {
3451da177e4SLinus Torvalds int k;
3461da177e4SLinus Torvalds
3471da177e4SLinus Torvalds for (k=0; k<3; k++)
3481da177e4SLinus Torvalds Inb(scc->data);
3491da177e4SLinus Torvalds
3501da177e4SLinus Torvalds if(scc->rx_buff != NULL) /* did we receive something? */
3511da177e4SLinus Torvalds {
3521da177e4SLinus Torvalds scc->stat.rxerrs++; /* then count it as an error */
3531da177e4SLinus Torvalds dev_kfree_skb_irq(scc->rx_buff);
3541da177e4SLinus Torvalds scc->rx_buff = NULL;
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds
start_hunt(struct scc_channel * scc)3581da177e4SLinus Torvalds static void start_hunt(struct scc_channel *scc)
3591da177e4SLinus Torvalds {
3601da177e4SLinus Torvalds if ((scc->modem.clocksrc != CLK_EXTERNAL))
3611da177e4SLinus Torvalds OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
3621da177e4SLinus Torvalds or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds
3651da177e4SLinus Torvalds /* ----> four different interrupt handlers for Tx, Rx, changing of */
3661da177e4SLinus Torvalds /* DCD/CTS and Rx/Tx errors */
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds /* Transmitter interrupt handler */
scc_txint(struct scc_channel * scc)3691da177e4SLinus Torvalds static inline void scc_txint(struct scc_channel *scc)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds struct sk_buff *skb;
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds scc->stat.txints++;
3741da177e4SLinus Torvalds skb = scc->tx_buff;
3751da177e4SLinus Torvalds
3761da177e4SLinus Torvalds /* send first octet */
3771da177e4SLinus Torvalds
3781da177e4SLinus Torvalds if (skb == NULL)
3791da177e4SLinus Torvalds {
3801da177e4SLinus Torvalds skb = skb_dequeue(&scc->tx_queue);
3811da177e4SLinus Torvalds scc->tx_buff = skb;
3821da177e4SLinus Torvalds netif_wake_queue(scc->dev);
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds if (skb == NULL)
3851da177e4SLinus Torvalds {
3861da177e4SLinus Torvalds scc_tx_done(scc);
3871da177e4SLinus Torvalds Outb(scc->ctrl, RES_Tx_P);
3881da177e4SLinus Torvalds return;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds
3911da177e4SLinus Torvalds if (skb->len == 0) /* Paranoia... */
3921da177e4SLinus Torvalds {
3931da177e4SLinus Torvalds dev_kfree_skb_irq(skb);
3941da177e4SLinus Torvalds scc->tx_buff = NULL;
3951da177e4SLinus Torvalds scc_tx_done(scc);
3961da177e4SLinus Torvalds Outb(scc->ctrl, RES_Tx_P);
3971da177e4SLinus Torvalds return;
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds
4001da177e4SLinus Torvalds scc->stat.tx_state = TXS_ACTIVE;
4011da177e4SLinus Torvalds
4021da177e4SLinus Torvalds OutReg(scc->ctrl, R0, RES_Tx_CRC);
4031da177e4SLinus Torvalds /* reset CRC generator */
4041da177e4SLinus Torvalds or(scc,R10,ABUNDER); /* re-install underrun protection */
4051da177e4SLinus Torvalds Outb(scc->data,*skb->data); /* send byte */
4061da177e4SLinus Torvalds skb_pull(skb, 1);
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds if (!scc->enhanced) /* reset EOM latch */
4091da177e4SLinus Torvalds Outb(scc->ctrl,RES_EOM_L);
4101da177e4SLinus Torvalds return;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds /* End Of Frame... */
4141da177e4SLinus Torvalds
4151da177e4SLinus Torvalds if (skb->len == 0)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds Outb(scc->ctrl, RES_Tx_P); /* reset pending int */
4181da177e4SLinus Torvalds cl(scc, R10, ABUNDER); /* send CRC */
4191da177e4SLinus Torvalds dev_kfree_skb_irq(skb);
4201da177e4SLinus Torvalds scc->tx_buff = NULL;
4211da177e4SLinus Torvalds scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */
4221da177e4SLinus Torvalds return;
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds
4251da177e4SLinus Torvalds /* send octet */
4261da177e4SLinus Torvalds
4271da177e4SLinus Torvalds Outb(scc->data,*skb->data);
4281da177e4SLinus Torvalds skb_pull(skb, 1);
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvalds /* External/Status interrupt handler */
scc_exint(struct scc_channel * scc)4331da177e4SLinus Torvalds static inline void scc_exint(struct scc_channel *scc)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds unsigned char status,changes,chg_and_stat;
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds scc->stat.exints++;
4381da177e4SLinus Torvalds
4391da177e4SLinus Torvalds status = InReg(scc->ctrl,R0);
4401da177e4SLinus Torvalds changes = status ^ scc->status;
4411da177e4SLinus Torvalds chg_and_stat = changes & status;
4421da177e4SLinus Torvalds
4431da177e4SLinus Torvalds /* ABORT: generated whenever DCD drops while receiving */
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds if (chg_and_stat & BRK_ABRT) /* Received an ABORT */
4461da177e4SLinus Torvalds flush_rx_FIFO(scc);
4471da177e4SLinus Torvalds
4481da177e4SLinus Torvalds /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
4491da177e4SLinus Torvalds
4501da177e4SLinus Torvalds if ((changes & SYNC_HUNT) && scc->kiss.softdcd)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds if (status & SYNC_HUNT)
4531da177e4SLinus Torvalds {
4541da177e4SLinus Torvalds scc->dcd = 0;
4551da177e4SLinus Torvalds flush_rx_FIFO(scc);
4561da177e4SLinus Torvalds if ((scc->modem.clocksrc != CLK_EXTERNAL))
4571da177e4SLinus Torvalds OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
4581da177e4SLinus Torvalds } else {
4591da177e4SLinus Torvalds scc->dcd = 1;
4601da177e4SLinus Torvalds }
4611da177e4SLinus Torvalds
4621da177e4SLinus Torvalds scc_notify(scc, scc->dcd? HWEV_DCD_OFF:HWEV_DCD_ON);
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds
4651da177e4SLinus Torvalds /* DCD: on = start to receive packet, off = ABORT condition */
4661da177e4SLinus Torvalds /* (a successfully received packet generates a special condition int) */
4671da177e4SLinus Torvalds
4681da177e4SLinus Torvalds if((changes & DCD) && !scc->kiss.softdcd) /* DCD input changed state */
4691da177e4SLinus Torvalds {
4701da177e4SLinus Torvalds if(status & DCD) /* DCD is now ON */
4711da177e4SLinus Torvalds {
4721da177e4SLinus Torvalds start_hunt(scc);
4731da177e4SLinus Torvalds scc->dcd = 1;
4741da177e4SLinus Torvalds } else { /* DCD is now OFF */
4751da177e4SLinus Torvalds cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
4761da177e4SLinus Torvalds flush_rx_FIFO(scc);
4771da177e4SLinus Torvalds scc->dcd = 0;
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds
4801da177e4SLinus Torvalds scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds
4831da177e4SLinus Torvalds #ifdef notdef
4841da177e4SLinus Torvalds /* CTS: use external TxDelay (what's that good for?!)
4851da177e4SLinus Torvalds * Anyway: If we _could_ use it (BayCom USCC uses CTS for
4861da177e4SLinus Torvalds * own purposes) we _should_ use the "autoenable" feature
4871da177e4SLinus Torvalds * of the Z8530 and not this interrupt...
4881da177e4SLinus Torvalds */
4891da177e4SLinus Torvalds
4901da177e4SLinus Torvalds if (chg_and_stat & CTS) /* CTS is now ON */
4911da177e4SLinus Torvalds {
4921da177e4SLinus Torvalds if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */
4931da177e4SLinus Torvalds scc_start_tx_timer(scc, t_txdelay, 0);
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds #endif
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM))
4981da177e4SLinus Torvalds {
4991da177e4SLinus Torvalds scc->stat.tx_under++; /* oops, an underrun! count 'em */
5001da177e4SLinus Torvalds Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */
5011da177e4SLinus Torvalds
5021da177e4SLinus Torvalds if (scc->tx_buff != NULL)
5031da177e4SLinus Torvalds {
5041da177e4SLinus Torvalds dev_kfree_skb_irq(scc->tx_buff);
5051da177e4SLinus Torvalds scc->tx_buff = NULL;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds
5081da177e4SLinus Torvalds or(scc,R10,ABUNDER);
5091da177e4SLinus Torvalds scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds scc->status = status;
5131da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT);
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds
5161da177e4SLinus Torvalds
5171da177e4SLinus Torvalds /* Receiver interrupt handler */
scc_rxint(struct scc_channel * scc)5181da177e4SLinus Torvalds static inline void scc_rxint(struct scc_channel *scc)
5191da177e4SLinus Torvalds {
5201da177e4SLinus Torvalds struct sk_buff *skb;
5211da177e4SLinus Torvalds
5221da177e4SLinus Torvalds scc->stat.rxints++;
5231da177e4SLinus Torvalds
5241da177e4SLinus Torvalds if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF)
5251da177e4SLinus Torvalds {
5261da177e4SLinus Torvalds Inb(scc->data); /* discard char */
5271da177e4SLinus Torvalds or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
5281da177e4SLinus Torvalds return;
5291da177e4SLinus Torvalds }
5301da177e4SLinus Torvalds
5311da177e4SLinus Torvalds skb = scc->rx_buff;
5321da177e4SLinus Torvalds
5331da177e4SLinus Torvalds if (skb == NULL)
5341da177e4SLinus Torvalds {
5351da177e4SLinus Torvalds skb = dev_alloc_skb(scc->stat.bufsize);
5361da177e4SLinus Torvalds if (skb == NULL)
5371da177e4SLinus Torvalds {
5381da177e4SLinus Torvalds scc->dev_stat.rx_dropped++;
5391da177e4SLinus Torvalds scc->stat.nospace++;
5401da177e4SLinus Torvalds Inb(scc->data);
5411da177e4SLinus Torvalds or(scc, R3, ENT_HM);
5421da177e4SLinus Torvalds return;
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds
5451da177e4SLinus Torvalds scc->rx_buff = skb;
546634fef61SJohannes Berg skb_put_u8(skb, 0); /* KISS data */
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds
5491da177e4SLinus Torvalds if (skb->len >= scc->stat.bufsize)
5501da177e4SLinus Torvalds {
5511da177e4SLinus Torvalds #ifdef notdef
5521da177e4SLinus Torvalds printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n");
5531da177e4SLinus Torvalds #endif
5541da177e4SLinus Torvalds dev_kfree_skb_irq(skb);
5551da177e4SLinus Torvalds scc->rx_buff = NULL;
5561da177e4SLinus Torvalds Inb(scc->data);
5571da177e4SLinus Torvalds or(scc, R3, ENT_HM);
5581da177e4SLinus Torvalds return;
5591da177e4SLinus Torvalds }
5601da177e4SLinus Torvalds
561634fef61SJohannes Berg skb_put_u8(skb, Inb(scc->data));
5621da177e4SLinus Torvalds }
5631da177e4SLinus Torvalds
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds /* Receive Special Condition interrupt handler */
scc_spint(struct scc_channel * scc)5661da177e4SLinus Torvalds static inline void scc_spint(struct scc_channel *scc)
5671da177e4SLinus Torvalds {
5681da177e4SLinus Torvalds unsigned char status;
5691da177e4SLinus Torvalds struct sk_buff *skb;
5701da177e4SLinus Torvalds
5711da177e4SLinus Torvalds scc->stat.spints++;
5721da177e4SLinus Torvalds
5731da177e4SLinus Torvalds status = InReg(scc->ctrl,R1); /* read receiver status */
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds Inb(scc->data); /* throw away Rx byte */
5761da177e4SLinus Torvalds skb = scc->rx_buff;
5771da177e4SLinus Torvalds
5781da177e4SLinus Torvalds if(status & Rx_OVR) /* receiver overrun */
5791da177e4SLinus Torvalds {
5801da177e4SLinus Torvalds scc->stat.rx_over++; /* count them */
5811da177e4SLinus Torvalds or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
5821da177e4SLinus Torvalds
5831da177e4SLinus Torvalds if (skb != NULL)
5841da177e4SLinus Torvalds dev_kfree_skb_irq(skb);
5851da177e4SLinus Torvalds scc->rx_buff = skb = NULL;
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds
5881da177e4SLinus Torvalds if(status & END_FR && skb != NULL) /* end of frame */
5891da177e4SLinus Torvalds {
5901da177e4SLinus Torvalds /* CRC okay, frame ends on 8 bit boundary and received something ? */
5911da177e4SLinus Torvalds
5921da177e4SLinus Torvalds if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0)
5931da177e4SLinus Torvalds {
5941da177e4SLinus Torvalds /* ignore last received byte (first of the CRC bytes) */
5951da177e4SLinus Torvalds skb_trim(skb, skb->len-1);
5961da177e4SLinus Torvalds scc_net_rx(scc, skb);
5971da177e4SLinus Torvalds scc->rx_buff = NULL;
5981da177e4SLinus Torvalds scc->stat.rxframes++;
5991da177e4SLinus Torvalds } else { /* a bad frame */
6001da177e4SLinus Torvalds dev_kfree_skb_irq(skb);
6011da177e4SLinus Torvalds scc->rx_buff = NULL;
6021da177e4SLinus Torvalds scc->stat.rxerrs++;
6031da177e4SLinus Torvalds }
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds Outb(scc->ctrl,ERR_RES);
6071da177e4SLinus Torvalds }
6081da177e4SLinus Torvalds
6091da177e4SLinus Torvalds
6101da177e4SLinus Torvalds /* ----> interrupt service routine for the Z8530 <---- */
6111da177e4SLinus Torvalds
scc_isr_dispatch(struct scc_channel * scc,int vector)6121da177e4SLinus Torvalds static void scc_isr_dispatch(struct scc_channel *scc, int vector)
6131da177e4SLinus Torvalds {
6141da177e4SLinus Torvalds spin_lock(&scc->lock);
6151da177e4SLinus Torvalds switch (vector & VECTOR_MASK)
6161da177e4SLinus Torvalds {
6171da177e4SLinus Torvalds case TXINT: scc_txint(scc); break;
6181da177e4SLinus Torvalds case EXINT: scc_exint(scc); break;
6191da177e4SLinus Torvalds case RXINT: scc_rxint(scc); break;
6201da177e4SLinus Torvalds case SPINT: scc_spint(scc); break;
6211da177e4SLinus Torvalds }
6221da177e4SLinus Torvalds spin_unlock(&scc->lock);
6231da177e4SLinus Torvalds }
6241da177e4SLinus Torvalds
6251da177e4SLinus Torvalds /* If the card has a latch for the interrupt vector (like the PA0HZP card)
6261da177e4SLinus Torvalds use it to get the number of the chip that generated the int.
6271da177e4SLinus Torvalds If not: poll all defined chips.
6281da177e4SLinus Torvalds */
6291da177e4SLinus Torvalds
6301da177e4SLinus Torvalds #define SCC_IRQTIMEOUT 30000
6311da177e4SLinus Torvalds
scc_isr(int irq,void * dev_id)6327d12e780SDavid Howells static irqreturn_t scc_isr(int irq, void *dev_id)
6331da177e4SLinus Torvalds {
6341b36efe0SJeff Garzik int chip_irq = (long) dev_id;
6351da177e4SLinus Torvalds unsigned char vector;
6361da177e4SLinus Torvalds struct scc_channel *scc;
6371da177e4SLinus Torvalds struct scc_ctrl *ctrl;
6381da177e4SLinus Torvalds int k;
6391da177e4SLinus Torvalds
6401da177e4SLinus Torvalds if (Vector_Latch)
6411da177e4SLinus Torvalds {
6421da177e4SLinus Torvalds for(k=0; k < SCC_IRQTIMEOUT; k++)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds Outb(Vector_Latch, 0); /* Generate INTACK */
6451da177e4SLinus Torvalds
6461da177e4SLinus Torvalds /* Read the vector */
6471da177e4SLinus Torvalds if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break;
6481da177e4SLinus Torvalds if (vector & 0x01) break;
6491da177e4SLinus Torvalds
6501da177e4SLinus Torvalds scc=&SCC_Info[vector >> 3 ^ 0x01];
6511da177e4SLinus Torvalds if (!scc->dev) break;
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds scc_isr_dispatch(scc, vector);
6541da177e4SLinus Torvalds
6551da177e4SLinus Torvalds OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */
6561da177e4SLinus Torvalds }
6571da177e4SLinus Torvalds
6581da177e4SLinus Torvalds if (k == SCC_IRQTIMEOUT)
6591da177e4SLinus Torvalds printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
6601da177e4SLinus Torvalds
6611da177e4SLinus Torvalds return IRQ_HANDLED;
6621da177e4SLinus Torvalds }
6631da177e4SLinus Torvalds
6641da177e4SLinus Torvalds /* Find the SCC generating the interrupt by polling all attached SCCs
6651da177e4SLinus Torvalds * reading RR3A (the interrupt pending register)
6661da177e4SLinus Torvalds */
6671da177e4SLinus Torvalds
6681da177e4SLinus Torvalds ctrl = SCC_ctrl;
6691da177e4SLinus Torvalds while (ctrl->chan_A)
6701da177e4SLinus Torvalds {
6711b36efe0SJeff Garzik if (ctrl->irq != chip_irq)
6721da177e4SLinus Torvalds {
6731da177e4SLinus Torvalds ctrl++;
6741da177e4SLinus Torvalds continue;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds scc = NULL;
6781da177e4SLinus Torvalds for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++)
6791da177e4SLinus Torvalds {
6801da177e4SLinus Torvalds vector=InReg(ctrl->chan_B,R2); /* Read the vector */
6811da177e4SLinus Torvalds if (vector & 0x01) break;
6821da177e4SLinus Torvalds
6831da177e4SLinus Torvalds scc = &SCC_Info[vector >> 3 ^ 0x01];
6841da177e4SLinus Torvalds if (!scc->dev) break;
6851da177e4SLinus Torvalds
6861da177e4SLinus Torvalds scc_isr_dispatch(scc, vector);
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds
6891da177e4SLinus Torvalds if (k == SCC_IRQTIMEOUT)
6901da177e4SLinus Torvalds {
6911da177e4SLinus Torvalds printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n");
6921da177e4SLinus Torvalds break;
6931da177e4SLinus Torvalds }
6941da177e4SLinus Torvalds
6951da177e4SLinus Torvalds /* This looks weird and it is. At least the BayCom USCC doesn't
6961da177e4SLinus Torvalds * use the Interrupt Daisy Chain, thus we'll have to start
6971da177e4SLinus Torvalds * all over again to be sure not to miss an interrupt from
6981da177e4SLinus Torvalds * (any of) the other chip(s)...
6991da177e4SLinus Torvalds * Honestly, the situation *is* braindamaged...
7001da177e4SLinus Torvalds */
7011da177e4SLinus Torvalds
7021da177e4SLinus Torvalds if (scc != NULL)
7031da177e4SLinus Torvalds {
7041da177e4SLinus Torvalds OutReg(scc->ctrl,R0,RES_H_IUS);
7051da177e4SLinus Torvalds ctrl = SCC_ctrl;
7061da177e4SLinus Torvalds } else
7071da177e4SLinus Torvalds ctrl++;
7081da177e4SLinus Torvalds }
7091da177e4SLinus Torvalds return IRQ_HANDLED;
7101da177e4SLinus Torvalds }
7111da177e4SLinus Torvalds
7121da177e4SLinus Torvalds
7131da177e4SLinus Torvalds
7141da177e4SLinus Torvalds /* ******************************************************************** */
7151da177e4SLinus Torvalds /* * Init Channel */
7161da177e4SLinus Torvalds /* ******************************************************************** */
7171da177e4SLinus Torvalds
7181da177e4SLinus Torvalds
7191da177e4SLinus Torvalds /* ----> set SCC channel speed <---- */
7201da177e4SLinus Torvalds
set_brg(struct scc_channel * scc,unsigned int tc)7211da177e4SLinus Torvalds static inline void set_brg(struct scc_channel *scc, unsigned int tc)
7221da177e4SLinus Torvalds {
7231da177e4SLinus Torvalds cl(scc,R14,BRENABL); /* disable baudrate generator */
7241da177e4SLinus Torvalds wr(scc,R12,tc & 255); /* brg rate LOW */
7251da177e4SLinus Torvalds wr(scc,R13,tc >> 8); /* brg rate HIGH */
7261da177e4SLinus Torvalds or(scc,R14,BRENABL); /* enable baudrate generator */
7271da177e4SLinus Torvalds }
7281da177e4SLinus Torvalds
set_speed(struct scc_channel * scc)7291da177e4SLinus Torvalds static inline void set_speed(struct scc_channel *scc)
7301da177e4SLinus Torvalds {
7311da177e4SLinus Torvalds unsigned long flags;
7321da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
7331da177e4SLinus Torvalds
7341da177e4SLinus Torvalds if (scc->modem.speed > 0) /* paranoia... */
7351da177e4SLinus Torvalds set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2);
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
7381da177e4SLinus Torvalds }
7391da177e4SLinus Torvalds
7401da177e4SLinus Torvalds
7411da177e4SLinus Torvalds /* ----> initialize a SCC channel <---- */
7421da177e4SLinus Torvalds
init_brg(struct scc_channel * scc)7431da177e4SLinus Torvalds static inline void init_brg(struct scc_channel *scc)
7441da177e4SLinus Torvalds {
7451da177e4SLinus Torvalds wr(scc, R14, BRSRC); /* BRG source = PCLK */
7461da177e4SLinus Torvalds OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */
7471da177e4SLinus Torvalds OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */
7481da177e4SLinus Torvalds }
7491da177e4SLinus Torvalds
7501da177e4SLinus Torvalds /*
7511da177e4SLinus Torvalds * Initialization according to the Z8530 manual (SGS-Thomson's version):
7521da177e4SLinus Torvalds *
7531da177e4SLinus Torvalds * 1. Modes and constants
7541da177e4SLinus Torvalds *
7551da177e4SLinus Torvalds * WR9 11000000 chip reset
7561da177e4SLinus Torvalds * WR4 XXXXXXXX Tx/Rx control, async or sync mode
7571da177e4SLinus Torvalds * WR1 0XX00X00 select W/REQ (optional)
7581da177e4SLinus Torvalds * WR2 XXXXXXXX program interrupt vector
7591da177e4SLinus Torvalds * WR3 XXXXXXX0 select Rx control
7601da177e4SLinus Torvalds * WR5 XXXX0XXX select Tx control
7611da177e4SLinus Torvalds * WR6 XXXXXXXX sync character
7621da177e4SLinus Torvalds * WR7 XXXXXXXX sync character
7631da177e4SLinus Torvalds * WR9 000X0XXX select interrupt control
7641da177e4SLinus Torvalds * WR10 XXXXXXXX miscellaneous control (optional)
7651da177e4SLinus Torvalds * WR11 XXXXXXXX clock control
7661da177e4SLinus Torvalds * WR12 XXXXXXXX time constant lower byte (optional)
7671da177e4SLinus Torvalds * WR13 XXXXXXXX time constant upper byte (optional)
7681da177e4SLinus Torvalds * WR14 XXXXXXX0 miscellaneous control
7691da177e4SLinus Torvalds * WR14 XXXSSSSS commands (optional)
7701da177e4SLinus Torvalds *
7711da177e4SLinus Torvalds * 2. Enables
7721da177e4SLinus Torvalds *
7731da177e4SLinus Torvalds * WR14 000SSSS1 baud rate enable
7741da177e4SLinus Torvalds * WR3 SSSSSSS1 Rx enable
7751da177e4SLinus Torvalds * WR5 SSSS1SSS Tx enable
7761da177e4SLinus Torvalds * WR0 10000000 reset Tx CRG (optional)
7771da177e4SLinus Torvalds * WR1 XSS00S00 DMA enable (optional)
7781da177e4SLinus Torvalds *
7791da177e4SLinus Torvalds * 3. Interrupt status
7801da177e4SLinus Torvalds *
7811da177e4SLinus Torvalds * WR15 XXXXXXXX enable external/status
7821da177e4SLinus Torvalds * WR0 00010000 reset external status
7831da177e4SLinus Torvalds * WR0 00010000 reset external status twice
7841da177e4SLinus Torvalds * WR1 SSSXXSXX enable Rx, Tx and Ext/status
7851da177e4SLinus Torvalds * WR9 000SXSSS enable master interrupt enable
7861da177e4SLinus Torvalds *
7871da177e4SLinus Torvalds * 1 = set to one, 0 = reset to zero
7881da177e4SLinus Torvalds * X = user defined, S = same as previous init
7891da177e4SLinus Torvalds *
7901da177e4SLinus Torvalds *
7911da177e4SLinus Torvalds * Note that the implementation differs in some points from above scheme.
7921da177e4SLinus Torvalds *
7931da177e4SLinus Torvalds */
7941da177e4SLinus Torvalds
init_channel(struct scc_channel * scc)7951da177e4SLinus Torvalds static void init_channel(struct scc_channel *scc)
7961da177e4SLinus Torvalds {
7971da177e4SLinus Torvalds del_timer(&scc->tx_t);
7981da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
7991da177e4SLinus Torvalds
8001da177e4SLinus Torvalds disable_irq(scc->irq);
8011da177e4SLinus Torvalds
8021da177e4SLinus Torvalds wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */
8031da177e4SLinus Torvalds wr(scc,R1,0); /* no W/REQ operation */
8041da177e4SLinus Torvalds wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */
8051da177e4SLinus Torvalds wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */
8061da177e4SLinus Torvalds wr(scc,R6,0); /* SDLC address zero (not used) */
8071da177e4SLinus Torvalds wr(scc,R7,FLAG); /* SDLC flag value */
8081da177e4SLinus Torvalds wr(scc,R9,VIS); /* vector includes status */
8091da177e4SLinus Torvalds wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */
8101da177e4SLinus Torvalds wr(scc,R14, 0);
8111da177e4SLinus Torvalds
8121da177e4SLinus Torvalds
8131da177e4SLinus Torvalds /* set clock sources:
8141da177e4SLinus Torvalds
8151da177e4SLinus Torvalds CLK_DPLL: normal halfduplex operation
8161da177e4SLinus Torvalds
8171da177e4SLinus Torvalds RxClk: use DPLL
8181da177e4SLinus Torvalds TxClk: use DPLL
8191da177e4SLinus Torvalds TRxC mode DPLL output
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvalds CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem)
8221da177e4SLinus Torvalds
8231da177e4SLinus Torvalds BayCom: others:
8241da177e4SLinus Torvalds
8251da177e4SLinus Torvalds TxClk = pin RTxC TxClk = pin TRxC
8261da177e4SLinus Torvalds RxClk = pin TRxC RxClk = pin RTxC
8271da177e4SLinus Torvalds
8281da177e4SLinus Torvalds
8291da177e4SLinus Torvalds CLK_DIVIDER:
8301da177e4SLinus Torvalds RxClk = use DPLL
8311da177e4SLinus Torvalds TxClk = pin RTxC
8321da177e4SLinus Torvalds
8331da177e4SLinus Torvalds BayCom: others:
8341da177e4SLinus Torvalds pin TRxC = DPLL pin TRxC = BRG
8351da177e4SLinus Torvalds (RxClk * 1) (RxClk * 32)
8361da177e4SLinus Torvalds */
8371da177e4SLinus Torvalds
8381da177e4SLinus Torvalds
8391da177e4SLinus Torvalds switch(scc->modem.clocksrc)
8401da177e4SLinus Torvalds {
8411da177e4SLinus Torvalds case CLK_DPLL:
8421da177e4SLinus Torvalds wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
8431da177e4SLinus Torvalds init_brg(scc);
8441da177e4SLinus Torvalds break;
8451da177e4SLinus Torvalds
8461da177e4SLinus Torvalds case CLK_DIVIDER:
8471da177e4SLinus Torvalds wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI);
8481da177e4SLinus Torvalds init_brg(scc);
8491da177e4SLinus Torvalds break;
8501da177e4SLinus Torvalds
8511da177e4SLinus Torvalds case CLK_EXTERNAL:
8521da177e4SLinus Torvalds wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP);
8531da177e4SLinus Torvalds OutReg(scc->ctrl, R14, DISDPLL);
8541da177e4SLinus Torvalds break;
8551da177e4SLinus Torvalds
8561da177e4SLinus Torvalds }
8571da177e4SLinus Torvalds
8581da177e4SLinus Torvalds set_speed(scc); /* set baudrate */
8591da177e4SLinus Torvalds
8601da177e4SLinus Torvalds if(scc->enhanced)
8611da177e4SLinus Torvalds {
8621da177e4SLinus Torvalds or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */
8631da177e4SLinus Torvalds wr(scc,R7,AUTOEOM);
8641da177e4SLinus Torvalds }
8651da177e4SLinus Torvalds
8661da177e4SLinus Torvalds if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD))
8671da177e4SLinus Torvalds /* DCD is now ON */
8681da177e4SLinus Torvalds {
8691da177e4SLinus Torvalds start_hunt(scc);
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds
8721da177e4SLinus Torvalds /* enable ABORT, DCD & SYNC/HUNT interrupts */
8731da177e4SLinus Torvalds
8741da177e4SLinus Torvalds wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE));
8751da177e4SLinus Torvalds
8761da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
8771da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */
8781da177e4SLinus Torvalds
8791da177e4SLinus Torvalds or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */
8801da177e4SLinus Torvalds
8811da177e4SLinus Torvalds scc->status = InReg(scc->ctrl,R0); /* read initial status */
8821da177e4SLinus Torvalds
8831da177e4SLinus Torvalds or(scc,R9,MIE); /* master interrupt enable */
8841da177e4SLinus Torvalds
8851da177e4SLinus Torvalds scc_init_timer(scc);
8861da177e4SLinus Torvalds
8871da177e4SLinus Torvalds enable_irq(scc->irq);
8881da177e4SLinus Torvalds }
8891da177e4SLinus Torvalds
8901da177e4SLinus Torvalds
8911da177e4SLinus Torvalds
8921da177e4SLinus Torvalds
8931da177e4SLinus Torvalds /* ******************************************************************** */
8941da177e4SLinus Torvalds /* * SCC timer functions * */
8951da177e4SLinus Torvalds /* ******************************************************************** */
8961da177e4SLinus Torvalds
8971da177e4SLinus Torvalds
8981da177e4SLinus Torvalds /* ----> scc_key_trx sets the time constant for the baudrate
8991da177e4SLinus Torvalds generator and keys the transmitter <---- */
9001da177e4SLinus Torvalds
scc_key_trx(struct scc_channel * scc,char tx)9011da177e4SLinus Torvalds static void scc_key_trx(struct scc_channel *scc, char tx)
9021da177e4SLinus Torvalds {
9031da177e4SLinus Torvalds unsigned int time_const;
9041da177e4SLinus Torvalds
9051da177e4SLinus Torvalds if (scc->brand & PRIMUS)
9061da177e4SLinus Torvalds Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0));
9071da177e4SLinus Torvalds
9081da177e4SLinus Torvalds if (scc->modem.speed < 300)
9091da177e4SLinus Torvalds scc->modem.speed = 1200;
9101da177e4SLinus Torvalds
9111da177e4SLinus Torvalds time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2;
9121da177e4SLinus Torvalds
9131da177e4SLinus Torvalds disable_irq(scc->irq);
9141da177e4SLinus Torvalds
9151da177e4SLinus Torvalds if (tx)
9161da177e4SLinus Torvalds {
9171da177e4SLinus Torvalds or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */
9181da177e4SLinus Torvalds or(scc, R15, TxUIE);
9191da177e4SLinus Torvalds }
9201da177e4SLinus Torvalds
9211da177e4SLinus Torvalds if (scc->modem.clocksrc == CLK_DPLL)
9221da177e4SLinus Torvalds { /* force simplex operation */
9231da177e4SLinus Torvalds if (tx)
9241da177e4SLinus Torvalds {
9251da177e4SLinus Torvalds #ifdef CONFIG_SCC_TRXECHO
9261da177e4SLinus Torvalds cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */
9271da177e4SLinus Torvalds cl(scc, R15, DCDIE|SYNCIE); /* No DCD changes, please */
9281da177e4SLinus Torvalds #endif
9291da177e4SLinus Torvalds set_brg(scc, time_const); /* reprogram baudrate generator */
9301da177e4SLinus Torvalds
9311da177e4SLinus Torvalds /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */
9321da177e4SLinus Torvalds wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);
9331da177e4SLinus Torvalds
9341da177e4SLinus Torvalds /* By popular demand: tx_inhibit */
9351da177e4SLinus Torvalds if (scc->kiss.tx_inhibit)
9361da177e4SLinus Torvalds {
9371da177e4SLinus Torvalds or(scc,R5, TxENAB);
9381da177e4SLinus Torvalds scc->wreg[R5] |= RTS;
9391da177e4SLinus Torvalds } else {
9401da177e4SLinus Torvalds or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
9411da177e4SLinus Torvalds }
9421da177e4SLinus Torvalds } else {
9431da177e4SLinus Torvalds cl(scc,R5,RTS|TxENAB);
9441da177e4SLinus Torvalds
9451da177e4SLinus Torvalds set_brg(scc, time_const); /* reprogram baudrate generator */
9461da177e4SLinus Torvalds
9471da177e4SLinus Torvalds /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */
9481da177e4SLinus Torvalds wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
9491da177e4SLinus Torvalds
9501da177e4SLinus Torvalds #ifndef CONFIG_SCC_TRXECHO
9511da177e4SLinus Torvalds if (scc->kiss.softdcd)
9521da177e4SLinus Torvalds #endif
9531da177e4SLinus Torvalds {
9541da177e4SLinus Torvalds or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE);
9551da177e4SLinus Torvalds start_hunt(scc);
9561da177e4SLinus Torvalds }
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds } else {
9591da177e4SLinus Torvalds if (tx)
9601da177e4SLinus Torvalds {
9611da177e4SLinus Torvalds #ifdef CONFIG_SCC_TRXECHO
9621da177e4SLinus Torvalds if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
9631da177e4SLinus Torvalds {
9641da177e4SLinus Torvalds cl(scc, R3, RxENABLE);
9651da177e4SLinus Torvalds cl(scc, R15, DCDIE|SYNCIE);
9661da177e4SLinus Torvalds }
9671da177e4SLinus Torvalds #endif
9681da177e4SLinus Torvalds
9691da177e4SLinus Torvalds if (scc->kiss.tx_inhibit)
9701da177e4SLinus Torvalds {
9711da177e4SLinus Torvalds or(scc,R5, TxENAB);
9721da177e4SLinus Torvalds scc->wreg[R5] |= RTS;
9731da177e4SLinus Torvalds } else {
9741da177e4SLinus Torvalds or(scc,R5,RTS|TxENAB); /* enable tx */
9751da177e4SLinus Torvalds }
9761da177e4SLinus Torvalds } else {
9771da177e4SLinus Torvalds cl(scc,R5,RTS|TxENAB); /* disable tx */
9781da177e4SLinus Torvalds
9791da177e4SLinus Torvalds if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) &&
9801da177e4SLinus Torvalds #ifndef CONFIG_SCC_TRXECHO
9811da177e4SLinus Torvalds scc->kiss.softdcd)
9821da177e4SLinus Torvalds #else
9831da177e4SLinus Torvalds 1)
9841da177e4SLinus Torvalds #endif
9851da177e4SLinus Torvalds {
9861da177e4SLinus Torvalds or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE);
9871da177e4SLinus Torvalds start_hunt(scc);
9881da177e4SLinus Torvalds }
9891da177e4SLinus Torvalds }
9901da177e4SLinus Torvalds }
9911da177e4SLinus Torvalds
9921da177e4SLinus Torvalds enable_irq(scc->irq);
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds
9951da177e4SLinus Torvalds
9961da177e4SLinus Torvalds /* ----> SCC timer interrupt handler and friends. <---- */
9971da177e4SLinus Torvalds
__scc_start_tx_timer(struct scc_channel * scc,void (* handler)(struct timer_list * t),unsigned long when)99841e9475cSKees Cook static void __scc_start_tx_timer(struct scc_channel *scc,
99941e9475cSKees Cook void (*handler)(struct timer_list *t),
100041e9475cSKees Cook unsigned long when)
10011da177e4SLinus Torvalds {
10021da177e4SLinus Torvalds del_timer(&scc->tx_t);
10031da177e4SLinus Torvalds
10041da177e4SLinus Torvalds if (when == 0)
10051da177e4SLinus Torvalds {
100641e9475cSKees Cook handler(&scc->tx_t);
10071da177e4SLinus Torvalds } else
10081da177e4SLinus Torvalds if (when != TIMER_OFF)
10091da177e4SLinus Torvalds {
1010841b86f3SKees Cook scc->tx_t.function = handler;
10111da177e4SLinus Torvalds scc->tx_t.expires = jiffies + (when*HZ)/100;
10121da177e4SLinus Torvalds add_timer(&scc->tx_t);
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds }
10151da177e4SLinus Torvalds
scc_start_tx_timer(struct scc_channel * scc,void (* handler)(struct timer_list * t),unsigned long when)101641e9475cSKees Cook static void scc_start_tx_timer(struct scc_channel *scc,
101741e9475cSKees Cook void (*handler)(struct timer_list *t),
101841e9475cSKees Cook unsigned long when)
10191da177e4SLinus Torvalds {
10201da177e4SLinus Torvalds unsigned long flags;
10211da177e4SLinus Torvalds
10221da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
10231da177e4SLinus Torvalds __scc_start_tx_timer(scc, handler, when);
10241da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds
scc_start_defer(struct scc_channel * scc)10271da177e4SLinus Torvalds static void scc_start_defer(struct scc_channel *scc)
10281da177e4SLinus Torvalds {
10291da177e4SLinus Torvalds unsigned long flags;
10301da177e4SLinus Torvalds
10311da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
10321da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
10331da177e4SLinus Torvalds
10341da177e4SLinus Torvalds if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)
10351da177e4SLinus Torvalds {
1036841b86f3SKees Cook scc->tx_wdog.function = t_busy;
10371da177e4SLinus Torvalds scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer;
10381da177e4SLinus Torvalds add_timer(&scc->tx_wdog);
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds
scc_start_maxkeyup(struct scc_channel * scc)10431da177e4SLinus Torvalds static void scc_start_maxkeyup(struct scc_channel *scc)
10441da177e4SLinus Torvalds {
10451da177e4SLinus Torvalds unsigned long flags;
10461da177e4SLinus Torvalds
10471da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
10481da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
10491da177e4SLinus Torvalds
10501da177e4SLinus Torvalds if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)
10511da177e4SLinus Torvalds {
1052841b86f3SKees Cook scc->tx_wdog.function = t_maxkeyup;
10531da177e4SLinus Torvalds scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
10541da177e4SLinus Torvalds add_timer(&scc->tx_wdog);
10551da177e4SLinus Torvalds }
10561da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
10571da177e4SLinus Torvalds }
10581da177e4SLinus Torvalds
10591da177e4SLinus Torvalds /*
10601da177e4SLinus Torvalds * This is called from scc_txint() when there are no more frames to send.
10611da177e4SLinus Torvalds * Not exactly a timer function, but it is a close friend of the family...
10621da177e4SLinus Torvalds */
10631da177e4SLinus Torvalds
scc_tx_done(struct scc_channel * scc)10641da177e4SLinus Torvalds static void scc_tx_done(struct scc_channel *scc)
10651da177e4SLinus Torvalds {
10661da177e4SLinus Torvalds /*
10671da177e4SLinus Torvalds * trx remains keyed in fulldup mode 2 until t_idle expires.
10681da177e4SLinus Torvalds */
10691da177e4SLinus Torvalds
10701da177e4SLinus Torvalds switch (scc->kiss.fulldup)
10711da177e4SLinus Torvalds {
10721da177e4SLinus Torvalds case KISS_DUPLEX_LINK:
10731da177e4SLinus Torvalds scc->stat.tx_state = TXS_IDLE2;
10741da177e4SLinus Torvalds if (scc->kiss.idletime != TIMER_OFF)
10751f1d47efSJulia Lawall scc_start_tx_timer(scc, t_idle,
10761f1d47efSJulia Lawall scc->kiss.idletime*100);
10771da177e4SLinus Torvalds break;
10781da177e4SLinus Torvalds case KISS_DUPLEX_OPTIMA:
10791da177e4SLinus Torvalds scc_notify(scc, HWEV_ALL_SENT);
10801da177e4SLinus Torvalds break;
10811da177e4SLinus Torvalds default:
10821da177e4SLinus Torvalds scc->stat.tx_state = TXS_BUSY;
10831da177e4SLinus Torvalds scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
10841da177e4SLinus Torvalds }
10851da177e4SLinus Torvalds
10861da177e4SLinus Torvalds netif_wake_queue(scc->dev);
10871da177e4SLinus Torvalds }
10881da177e4SLinus Torvalds
10891da177e4SLinus Torvalds
10901da177e4SLinus Torvalds static unsigned char Rand = 17;
10911da177e4SLinus Torvalds
is_grouped(struct scc_channel * scc)10921da177e4SLinus Torvalds static inline int is_grouped(struct scc_channel *scc)
10931da177e4SLinus Torvalds {
10941da177e4SLinus Torvalds int k;
10951da177e4SLinus Torvalds struct scc_channel *scc2;
10961da177e4SLinus Torvalds unsigned char grp1, grp2;
10971da177e4SLinus Torvalds
10981da177e4SLinus Torvalds grp1 = scc->kiss.group;
10991da177e4SLinus Torvalds
11001da177e4SLinus Torvalds for (k = 0; k < (Nchips * 2); k++)
11011da177e4SLinus Torvalds {
11021da177e4SLinus Torvalds scc2 = &SCC_Info[k];
11031da177e4SLinus Torvalds grp2 = scc2->kiss.group;
11041da177e4SLinus Torvalds
11051da177e4SLinus Torvalds if (scc2 == scc || !(scc2->dev && grp2))
11061da177e4SLinus Torvalds continue;
11071da177e4SLinus Torvalds
11081da177e4SLinus Torvalds if ((grp1 & 0x3f) == (grp2 & 0x3f))
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
11111da177e4SLinus Torvalds return 1;
11121da177e4SLinus Torvalds
11131da177e4SLinus Torvalds if ( (grp1 & RXGROUP) && scc2->dcd )
11141da177e4SLinus Torvalds return 1;
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds return 0;
11181da177e4SLinus Torvalds }
11191da177e4SLinus Torvalds
11201da177e4SLinus Torvalds /* DWAIT and SLOTTIME expired
11211da177e4SLinus Torvalds *
11221da177e4SLinus Torvalds * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer
11231da177e4SLinus Torvalds * else key trx and start txdelay
11241da177e4SLinus Torvalds * fulldup == 1: key trx and start txdelay
11251da177e4SLinus Torvalds * fulldup == 2: mintime expired, reset status or key trx and start txdelay
11261da177e4SLinus Torvalds */
11271da177e4SLinus Torvalds
t_dwait(struct timer_list * t)112841e9475cSKees Cook static void t_dwait(struct timer_list *t)
11291da177e4SLinus Torvalds {
113041e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_t);
11311da177e4SLinus Torvalds
11321da177e4SLinus Torvalds if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */
11331da177e4SLinus Torvalds {
1134b03efcfbSDavid S. Miller if (skb_queue_empty(&scc->tx_queue)) { /* nothing to send */
11351da177e4SLinus Torvalds scc->stat.tx_state = TXS_IDLE;
11361da177e4SLinus Torvalds netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */
11371da177e4SLinus Torvalds return;
11381da177e4SLinus Torvalds }
11391da177e4SLinus Torvalds
11401da177e4SLinus Torvalds scc->stat.tx_state = TXS_BUSY;
11411da177e4SLinus Torvalds }
11421da177e4SLinus Torvalds
11431da177e4SLinus Torvalds if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
11441da177e4SLinus Torvalds {
11451da177e4SLinus Torvalds Rand = Rand * 17 + 31;
11461da177e4SLinus Torvalds
11471da177e4SLinus Torvalds if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
11481da177e4SLinus Torvalds {
11491da177e4SLinus Torvalds scc_start_defer(scc);
11501da177e4SLinus Torvalds scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime);
11511da177e4SLinus Torvalds return ;
11521da177e4SLinus Torvalds }
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds
11551da177e4SLinus Torvalds if ( !(scc->wreg[R5] & RTS) )
11561da177e4SLinus Torvalds {
11571da177e4SLinus Torvalds scc_key_trx(scc, TX_ON);
11581da177e4SLinus Torvalds scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
11591da177e4SLinus Torvalds } else {
11601da177e4SLinus Torvalds scc_start_tx_timer(scc, t_txdelay, 0);
11611da177e4SLinus Torvalds }
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds
11641da177e4SLinus Torvalds
11651da177e4SLinus Torvalds /* TXDELAY expired
11661da177e4SLinus Torvalds *
11671da177e4SLinus Torvalds * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog.
11681da177e4SLinus Torvalds */
11691da177e4SLinus Torvalds
t_txdelay(struct timer_list * t)117041e9475cSKees Cook static void t_txdelay(struct timer_list *t)
11711da177e4SLinus Torvalds {
117241e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_t);
11731da177e4SLinus Torvalds
11741da177e4SLinus Torvalds scc_start_maxkeyup(scc);
11751da177e4SLinus Torvalds
11761da177e4SLinus Torvalds if (scc->tx_buff == NULL)
11771da177e4SLinus Torvalds {
11781da177e4SLinus Torvalds disable_irq(scc->irq);
11791da177e4SLinus Torvalds scc_txint(scc);
11801da177e4SLinus Torvalds enable_irq(scc->irq);
11811da177e4SLinus Torvalds }
11821da177e4SLinus Torvalds }
11831da177e4SLinus Torvalds
11841da177e4SLinus Torvalds
11851da177e4SLinus Torvalds /* TAILTIME expired
11861da177e4SLinus Torvalds *
11871da177e4SLinus Torvalds * switch off transmitter. If we were stopped by Maxkeyup restart
11881da177e4SLinus Torvalds * transmission after 'mintime' seconds
11891da177e4SLinus Torvalds */
11901da177e4SLinus Torvalds
t_tail(struct timer_list * t)119141e9475cSKees Cook static void t_tail(struct timer_list *t)
11921da177e4SLinus Torvalds {
119341e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_t);
11941da177e4SLinus Torvalds unsigned long flags;
11951da177e4SLinus Torvalds
11961da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
11971da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
11981da177e4SLinus Torvalds scc_key_trx(scc, TX_OFF);
11991da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
12001da177e4SLinus Torvalds
12011da177e4SLinus Torvalds if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
12021da177e4SLinus Torvalds {
12031da177e4SLinus Torvalds scc->stat.tx_state = TXS_WAIT;
12041da177e4SLinus Torvalds scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
12051da177e4SLinus Torvalds return;
12061da177e4SLinus Torvalds }
12071da177e4SLinus Torvalds
12081da177e4SLinus Torvalds scc->stat.tx_state = TXS_IDLE;
12091da177e4SLinus Torvalds netif_wake_queue(scc->dev);
12101da177e4SLinus Torvalds }
12111da177e4SLinus Torvalds
12121da177e4SLinus Torvalds
12131da177e4SLinus Torvalds /* BUSY timeout
12141da177e4SLinus Torvalds *
12151da177e4SLinus Torvalds * throw away send buffers if DCD remains active too long.
12161da177e4SLinus Torvalds */
12171da177e4SLinus Torvalds
t_busy(struct timer_list * t)121841e9475cSKees Cook static void t_busy(struct timer_list *t)
12191da177e4SLinus Torvalds {
122041e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_wdog);
12211da177e4SLinus Torvalds
12221da177e4SLinus Torvalds del_timer(&scc->tx_t);
12231da177e4SLinus Torvalds netif_stop_queue(scc->dev); /* don't pile on the wabbit! */
12241da177e4SLinus Torvalds
12251da177e4SLinus Torvalds scc_discard_buffers(scc);
12261da177e4SLinus Torvalds scc->stat.txerrs++;
12271da177e4SLinus Torvalds scc->stat.tx_state = TXS_IDLE;
12281da177e4SLinus Torvalds
12291da177e4SLinus Torvalds netif_wake_queue(scc->dev);
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds
12321da177e4SLinus Torvalds /* MAXKEYUP timeout
12331da177e4SLinus Torvalds *
12341da177e4SLinus Torvalds * this is our watchdog.
12351da177e4SLinus Torvalds */
12361da177e4SLinus Torvalds
t_maxkeyup(struct timer_list * t)123741e9475cSKees Cook static void t_maxkeyup(struct timer_list *t)
12381da177e4SLinus Torvalds {
123941e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_wdog);
12401da177e4SLinus Torvalds unsigned long flags;
12411da177e4SLinus Torvalds
12421da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
12431da177e4SLinus Torvalds /*
12441da177e4SLinus Torvalds * let things settle down before we start to
12451da177e4SLinus Torvalds * accept new data.
12461da177e4SLinus Torvalds */
12471da177e4SLinus Torvalds
12481da177e4SLinus Torvalds netif_stop_queue(scc->dev);
12491da177e4SLinus Torvalds scc_discard_buffers(scc);
12501da177e4SLinus Torvalds
12511da177e4SLinus Torvalds del_timer(&scc->tx_t);
12521da177e4SLinus Torvalds
12531da177e4SLinus Torvalds cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */
12541da177e4SLinus Torvalds cl(scc, R15, TxUIE); /* count it. */
12551da177e4SLinus Torvalds OutReg(scc->ctrl, R0, RES_Tx_P);
12561da177e4SLinus Torvalds
12571da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
12581da177e4SLinus Torvalds
12591da177e4SLinus Torvalds scc->stat.txerrs++;
12601da177e4SLinus Torvalds scc->stat.tx_state = TXS_TIMEOUT;
12611da177e4SLinus Torvalds scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds
12641da177e4SLinus Torvalds /* IDLE timeout
12651da177e4SLinus Torvalds *
12661da177e4SLinus Torvalds * in fulldup mode 2 it keys down the transmitter after 'idle' seconds
12671da177e4SLinus Torvalds * of inactivity. We will not restart transmission before 'mintime'
12681da177e4SLinus Torvalds * expires.
12691da177e4SLinus Torvalds */
12701da177e4SLinus Torvalds
t_idle(struct timer_list * t)127141e9475cSKees Cook static void t_idle(struct timer_list *t)
12721da177e4SLinus Torvalds {
127341e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_t);
12741da177e4SLinus Torvalds
12751da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
12761da177e4SLinus Torvalds
12771da177e4SLinus Torvalds scc_key_trx(scc, TX_OFF);
12781da177e4SLinus Torvalds if(scc->kiss.mintime)
12791da177e4SLinus Torvalds scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
12801da177e4SLinus Torvalds scc->stat.tx_state = TXS_WAIT;
12811da177e4SLinus Torvalds }
12821da177e4SLinus Torvalds
scc_init_timer(struct scc_channel * scc)12831da177e4SLinus Torvalds static void scc_init_timer(struct scc_channel *scc)
12841da177e4SLinus Torvalds {
12851da177e4SLinus Torvalds unsigned long flags;
12861da177e4SLinus Torvalds
12871da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
12881da177e4SLinus Torvalds scc->stat.tx_state = TXS_IDLE;
12891da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
12901da177e4SLinus Torvalds }
12911da177e4SLinus Torvalds
12921da177e4SLinus Torvalds
12931da177e4SLinus Torvalds /* ******************************************************************** */
12941da177e4SLinus Torvalds /* * Set/get L1 parameters * */
12951da177e4SLinus Torvalds /* ******************************************************************** */
12961da177e4SLinus Torvalds
12971da177e4SLinus Torvalds
12981da177e4SLinus Torvalds /*
12991da177e4SLinus Torvalds * this will set the "hardware" parameters through KISS commands or ioctl()
13001da177e4SLinus Torvalds */
13011da177e4SLinus Torvalds
13021da177e4SLinus Torvalds #define CAST(x) (unsigned long)(x)
13031da177e4SLinus Torvalds
scc_set_param(struct scc_channel * scc,unsigned int cmd,unsigned int arg)13041da177e4SLinus Torvalds static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg)
13051da177e4SLinus Torvalds {
13061da177e4SLinus Torvalds switch (cmd)
13071da177e4SLinus Torvalds {
13081da177e4SLinus Torvalds case PARAM_TXDELAY: scc->kiss.txdelay=arg; break;
13091da177e4SLinus Torvalds case PARAM_PERSIST: scc->kiss.persist=arg; break;
13101da177e4SLinus Torvalds case PARAM_SLOTTIME: scc->kiss.slottime=arg; break;
13111da177e4SLinus Torvalds case PARAM_TXTAIL: scc->kiss.tailtime=arg; break;
13121da177e4SLinus Torvalds case PARAM_FULLDUP: scc->kiss.fulldup=arg; break;
13131da177e4SLinus Torvalds case PARAM_DTR: break; /* does someone need this? */
13141da177e4SLinus Torvalds case PARAM_GROUP: scc->kiss.group=arg; break;
13151da177e4SLinus Torvalds case PARAM_IDLE: scc->kiss.idletime=arg; break;
13161da177e4SLinus Torvalds case PARAM_MIN: scc->kiss.mintime=arg; break;
13171da177e4SLinus Torvalds case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break;
13181da177e4SLinus Torvalds case PARAM_WAIT: scc->kiss.waittime=arg; break;
13191da177e4SLinus Torvalds case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break;
13201da177e4SLinus Torvalds case PARAM_TX: scc->kiss.tx_inhibit=arg; break;
13211da177e4SLinus Torvalds
13221da177e4SLinus Torvalds case PARAM_SOFTDCD:
13231da177e4SLinus Torvalds scc->kiss.softdcd=arg;
13241da177e4SLinus Torvalds if (arg)
13251da177e4SLinus Torvalds {
13261da177e4SLinus Torvalds or(scc, R15, SYNCIE);
13271da177e4SLinus Torvalds cl(scc, R15, DCDIE);
13281da177e4SLinus Torvalds start_hunt(scc);
13291da177e4SLinus Torvalds } else {
13301da177e4SLinus Torvalds or(scc, R15, DCDIE);
13311da177e4SLinus Torvalds cl(scc, R15, SYNCIE);
13321da177e4SLinus Torvalds }
13331da177e4SLinus Torvalds break;
13341da177e4SLinus Torvalds
13351da177e4SLinus Torvalds case PARAM_SPEED:
13361da177e4SLinus Torvalds if (arg < 256)
13371da177e4SLinus Torvalds scc->modem.speed=arg*100;
13381da177e4SLinus Torvalds else
13391da177e4SLinus Torvalds scc->modem.speed=arg;
13401da177e4SLinus Torvalds
13411da177e4SLinus Torvalds if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */
13421da177e4SLinus Torvalds set_speed(scc);
13431da177e4SLinus Torvalds break;
13441da177e4SLinus Torvalds
13451da177e4SLinus Torvalds case PARAM_RTS:
13461da177e4SLinus Torvalds if ( !(scc->wreg[R5] & RTS) )
13471da177e4SLinus Torvalds {
13486941727aSIlpo Järvinen if (arg != TX_OFF) {
13491da177e4SLinus Torvalds scc_key_trx(scc, TX_ON);
13501da177e4SLinus Torvalds scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
13516941727aSIlpo Järvinen }
13521da177e4SLinus Torvalds } else {
13531da177e4SLinus Torvalds if (arg == TX_OFF)
13541da177e4SLinus Torvalds {
13551da177e4SLinus Torvalds scc->stat.tx_state = TXS_BUSY;
13561da177e4SLinus Torvalds scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
13571da177e4SLinus Torvalds }
13581da177e4SLinus Torvalds }
13591da177e4SLinus Torvalds break;
13601da177e4SLinus Torvalds
13611da177e4SLinus Torvalds case PARAM_HWEVENT:
13621da177e4SLinus Torvalds scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
13631da177e4SLinus Torvalds break;
13641da177e4SLinus Torvalds
13651da177e4SLinus Torvalds default: return -EINVAL;
13661da177e4SLinus Torvalds }
13671da177e4SLinus Torvalds
13681da177e4SLinus Torvalds return 0;
13691da177e4SLinus Torvalds }
13701da177e4SLinus Torvalds
13711da177e4SLinus Torvalds
13721da177e4SLinus Torvalds
scc_get_param(struct scc_channel * scc,unsigned int cmd)13731da177e4SLinus Torvalds static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd)
13741da177e4SLinus Torvalds {
13751da177e4SLinus Torvalds switch (cmd)
13761da177e4SLinus Torvalds {
13771da177e4SLinus Torvalds case PARAM_TXDELAY: return CAST(scc->kiss.txdelay);
13781da177e4SLinus Torvalds case PARAM_PERSIST: return CAST(scc->kiss.persist);
13791da177e4SLinus Torvalds case PARAM_SLOTTIME: return CAST(scc->kiss.slottime);
13801da177e4SLinus Torvalds case PARAM_TXTAIL: return CAST(scc->kiss.tailtime);
13811da177e4SLinus Torvalds case PARAM_FULLDUP: return CAST(scc->kiss.fulldup);
13821da177e4SLinus Torvalds case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd);
13831da177e4SLinus Torvalds case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0);
13841da177e4SLinus Torvalds case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0);
13851da177e4SLinus Torvalds case PARAM_SPEED: return CAST(scc->modem.speed);
13861da177e4SLinus Torvalds case PARAM_GROUP: return CAST(scc->kiss.group);
13871da177e4SLinus Torvalds case PARAM_IDLE: return CAST(scc->kiss.idletime);
13881da177e4SLinus Torvalds case PARAM_MIN: return CAST(scc->kiss.mintime);
13891da177e4SLinus Torvalds case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup);
13901da177e4SLinus Torvalds case PARAM_WAIT: return CAST(scc->kiss.waittime);
13911da177e4SLinus Torvalds case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer);
13921da177e4SLinus Torvalds case PARAM_TX: return CAST(scc->kiss.tx_inhibit);
13931da177e4SLinus Torvalds default: return NO_SUCH_PARAM;
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds
13961da177e4SLinus Torvalds }
13971da177e4SLinus Torvalds
13981da177e4SLinus Torvalds #undef CAST
13991da177e4SLinus Torvalds
14001da177e4SLinus Torvalds /* ******************************************************************* */
14011da177e4SLinus Torvalds /* * Send calibration pattern * */
14021da177e4SLinus Torvalds /* ******************************************************************* */
14031da177e4SLinus Torvalds
scc_stop_calibrate(struct timer_list * t)140441e9475cSKees Cook static void scc_stop_calibrate(struct timer_list *t)
14051da177e4SLinus Torvalds {
140641e9475cSKees Cook struct scc_channel *scc = from_timer(scc, t, tx_wdog);
14071da177e4SLinus Torvalds unsigned long flags;
14081da177e4SLinus Torvalds
14091da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
14101da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
14111da177e4SLinus Torvalds scc_key_trx(scc, TX_OFF);
14121da177e4SLinus Torvalds wr(scc, R6, 0);
14131da177e4SLinus Torvalds wr(scc, R7, FLAG);
14141da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
14151da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT);
14161da177e4SLinus Torvalds
14171da177e4SLinus Torvalds netif_wake_queue(scc->dev);
14181da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds
14211da177e4SLinus Torvalds
14221da177e4SLinus Torvalds static void
scc_start_calibrate(struct scc_channel * scc,int duration,unsigned char pattern)14231da177e4SLinus Torvalds scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern)
14241da177e4SLinus Torvalds {
14251da177e4SLinus Torvalds unsigned long flags;
14261da177e4SLinus Torvalds
14271da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
14281da177e4SLinus Torvalds netif_stop_queue(scc->dev);
14291da177e4SLinus Torvalds scc_discard_buffers(scc);
14301da177e4SLinus Torvalds
14311da177e4SLinus Torvalds del_timer(&scc->tx_wdog);
14321da177e4SLinus Torvalds
1433841b86f3SKees Cook scc->tx_wdog.function = scc_stop_calibrate;
14341da177e4SLinus Torvalds scc->tx_wdog.expires = jiffies + HZ*duration;
14351da177e4SLinus Torvalds add_timer(&scc->tx_wdog);
14361da177e4SLinus Torvalds
14371da177e4SLinus Torvalds /* This doesn't seem to work. Why not? */
14381da177e4SLinus Torvalds wr(scc, R6, 0);
14391da177e4SLinus Torvalds wr(scc, R7, pattern);
14401da177e4SLinus Torvalds
14411da177e4SLinus Torvalds /*
14421da177e4SLinus Torvalds * Don't know if this works.
14431da177e4SLinus Torvalds * Damn, where is my Z8530 programming manual...?
14441da177e4SLinus Torvalds */
14451da177e4SLinus Torvalds
14461da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
14471da177e4SLinus Torvalds Outb(scc->ctrl,RES_EXT_INT);
14481da177e4SLinus Torvalds
14491da177e4SLinus Torvalds scc_key_trx(scc, TX_ON);
14501da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
14511da177e4SLinus Torvalds }
14521da177e4SLinus Torvalds
14531da177e4SLinus Torvalds /* ******************************************************************* */
14541da177e4SLinus Torvalds /* * Init channel structures, special HW, etc... * */
14551da177e4SLinus Torvalds /* ******************************************************************* */
14561da177e4SLinus Torvalds
14571da177e4SLinus Torvalds /*
14581da177e4SLinus Torvalds * Reset the Z8530s and setup special hardware
14591da177e4SLinus Torvalds */
14601da177e4SLinus Torvalds
z8530_init(void)14611da177e4SLinus Torvalds static void z8530_init(void)
14621da177e4SLinus Torvalds {
14631da177e4SLinus Torvalds struct scc_channel *scc;
14641da177e4SLinus Torvalds int chip, k;
14651da177e4SLinus Torvalds unsigned long flags;
14661da177e4SLinus Torvalds char *flag;
14671da177e4SLinus Torvalds
14681da177e4SLinus Torvalds
14691da177e4SLinus Torvalds printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
14701da177e4SLinus Torvalds
14711da177e4SLinus Torvalds flag=" ";
147260e4ad7aSYinghai Lu for (k = 0; k < nr_irqs; k++)
14731da177e4SLinus Torvalds if (Ivec[k].used)
14741da177e4SLinus Torvalds {
14751da177e4SLinus Torvalds printk("%s%d", flag, k);
14761da177e4SLinus Torvalds flag=",";
14771da177e4SLinus Torvalds }
14781da177e4SLinus Torvalds printk("\n");
14791da177e4SLinus Torvalds
14801da177e4SLinus Torvalds
14811da177e4SLinus Torvalds /* reset and pre-init all chips in the system */
14821da177e4SLinus Torvalds for (chip = 0; chip < Nchips; chip++)
14831da177e4SLinus Torvalds {
14841da177e4SLinus Torvalds scc=&SCC_Info[2*chip];
14851da177e4SLinus Torvalds if (!scc->ctrl) continue;
14861da177e4SLinus Torvalds
14871da177e4SLinus Torvalds /* Special SCC cards */
14881da177e4SLinus Torvalds
14891da177e4SLinus Torvalds if(scc->brand & EAGLE) /* this is an EAGLE card */
14901da177e4SLinus Torvalds Outb(scc->special,0x08); /* enable interrupt on the board */
14911da177e4SLinus Torvalds
14921da177e4SLinus Torvalds if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */
14931da177e4SLinus Torvalds Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */
14941da177e4SLinus Torvalds
14951da177e4SLinus Torvalds
14961da177e4SLinus Torvalds /* Reset and pre-init Z8530 */
14971da177e4SLinus Torvalds
14981da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
14991da177e4SLinus Torvalds
15001da177e4SLinus Torvalds Outb(scc->ctrl, 0);
15011da177e4SLinus Torvalds OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */
15021da177e4SLinus Torvalds udelay(100); /* give it 'a bit' more time than required */
15031da177e4SLinus Torvalds wr(scc, R2, chip*16); /* interrupt vector */
15041da177e4SLinus Torvalds wr(scc, R9, VIS); /* vector includes status */
15051da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
15061da177e4SLinus Torvalds }
15071da177e4SLinus Torvalds
15081da177e4SLinus Torvalds
15091da177e4SLinus Torvalds Driver_Initialized = 1;
15101da177e4SLinus Torvalds }
15111da177e4SLinus Torvalds
15121da177e4SLinus Torvalds /*
15131da177e4SLinus Torvalds * Allocate device structure, err, instance, and register driver
15141da177e4SLinus Torvalds */
15151da177e4SLinus Torvalds
scc_net_alloc(const char * name,struct scc_channel * scc)15161da177e4SLinus Torvalds static int scc_net_alloc(const char *name, struct scc_channel *scc)
15171da177e4SLinus Torvalds {
15181da177e4SLinus Torvalds int err;
15191da177e4SLinus Torvalds struct net_device *dev;
15201da177e4SLinus Torvalds
1521c835a677STom Gundersen dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, scc_net_setup);
15221da177e4SLinus Torvalds if (!dev)
15231da177e4SLinus Torvalds return -ENOMEM;
15241da177e4SLinus Torvalds
1525f4bdd264SWang Chen dev->ml_priv = scc;
15261da177e4SLinus Torvalds scc->dev = dev;
15271da177e4SLinus Torvalds spin_lock_init(&scc->lock);
152841e9475cSKees Cook timer_setup(&scc->tx_t, NULL, 0);
152941e9475cSKees Cook timer_setup(&scc->tx_wdog, NULL, 0);
15301da177e4SLinus Torvalds
15311da177e4SLinus Torvalds err = register_netdevice(dev);
15321da177e4SLinus Torvalds if (err) {
15331da177e4SLinus Torvalds printk(KERN_ERR "%s: can't register network device (%d)\n",
15341da177e4SLinus Torvalds name, err);
15351da177e4SLinus Torvalds free_netdev(dev);
15361da177e4SLinus Torvalds scc->dev = NULL;
15371da177e4SLinus Torvalds return err;
15381da177e4SLinus Torvalds }
15391da177e4SLinus Torvalds
15401da177e4SLinus Torvalds return 0;
15411da177e4SLinus Torvalds }
15421da177e4SLinus Torvalds
15431da177e4SLinus Torvalds
15441da177e4SLinus Torvalds
15451da177e4SLinus Torvalds /* ******************************************************************** */
15461da177e4SLinus Torvalds /* * Network driver methods * */
15471da177e4SLinus Torvalds /* ******************************************************************** */
15481da177e4SLinus Torvalds
1549ff908cf8SStephen Hemminger static const struct net_device_ops scc_netdev_ops = {
1550ff908cf8SStephen Hemminger .ndo_open = scc_net_open,
1551ff908cf8SStephen Hemminger .ndo_stop = scc_net_close,
1552ff908cf8SStephen Hemminger .ndo_start_xmit = scc_net_tx,
1553ff908cf8SStephen Hemminger .ndo_set_mac_address = scc_net_set_mac_address,
1554ff908cf8SStephen Hemminger .ndo_get_stats = scc_net_get_stats,
155525ec92fbSArnd Bergmann .ndo_siocdevprivate = scc_net_siocdevprivate,
1556ff908cf8SStephen Hemminger };
1557ff908cf8SStephen Hemminger
15581da177e4SLinus Torvalds /* ----> Initialize device <----- */
15591da177e4SLinus Torvalds
scc_net_setup(struct net_device * dev)15601da177e4SLinus Torvalds static void scc_net_setup(struct net_device *dev)
15611da177e4SLinus Torvalds {
15621da177e4SLinus Torvalds dev->tx_queue_len = 16; /* should be enough... */
15631da177e4SLinus Torvalds
1564ff908cf8SStephen Hemminger dev->netdev_ops = &scc_netdev_ops;
15653b04dddeSStephen Hemminger dev->header_ops = &ax25_header_ops;
15663b04dddeSStephen Hemminger
15671da177e4SLinus Torvalds dev->flags = 0;
15681da177e4SLinus Torvalds
15691da177e4SLinus Torvalds dev->type = ARPHRD_AX25;
15701da177e4SLinus Torvalds dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
15711da177e4SLinus Torvalds dev->mtu = AX25_DEF_PACLEN;
15721da177e4SLinus Torvalds dev->addr_len = AX25_ADDR_LEN;
15731da177e4SLinus Torvalds
157420c3d9e4SJakub Kicinski memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
157520c3d9e4SJakub Kicinski dev_addr_set(dev, (u8 *)&ax25_defaddr);
15761da177e4SLinus Torvalds }
15771da177e4SLinus Torvalds
15781da177e4SLinus Torvalds /* ----> open network device <---- */
15791da177e4SLinus Torvalds
scc_net_open(struct net_device * dev)15801da177e4SLinus Torvalds static int scc_net_open(struct net_device *dev)
15811da177e4SLinus Torvalds {
1582f4bdd264SWang Chen struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
15831da177e4SLinus Torvalds
15841da177e4SLinus Torvalds if (!scc->init)
15851da177e4SLinus Torvalds return -EINVAL;
15861da177e4SLinus Torvalds
15871da177e4SLinus Torvalds scc->tx_buff = NULL;
15881da177e4SLinus Torvalds skb_queue_head_init(&scc->tx_queue);
15891da177e4SLinus Torvalds
15901da177e4SLinus Torvalds init_channel(scc);
15911da177e4SLinus Torvalds
15921da177e4SLinus Torvalds netif_start_queue(dev);
15931da177e4SLinus Torvalds return 0;
15941da177e4SLinus Torvalds }
15951da177e4SLinus Torvalds
15961da177e4SLinus Torvalds /* ----> close network device <---- */
15971da177e4SLinus Torvalds
scc_net_close(struct net_device * dev)15981da177e4SLinus Torvalds static int scc_net_close(struct net_device *dev)
15991da177e4SLinus Torvalds {
1600f4bdd264SWang Chen struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
16011da177e4SLinus Torvalds unsigned long flags;
16021da177e4SLinus Torvalds
16031da177e4SLinus Torvalds netif_stop_queue(dev);
16041da177e4SLinus Torvalds
16051da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
16061da177e4SLinus Torvalds Outb(scc->ctrl,0); /* Make sure pointer is written */
16071da177e4SLinus Torvalds wr(scc,R1,0); /* disable interrupts */
16081da177e4SLinus Torvalds wr(scc,R3,0);
16091da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
16101da177e4SLinus Torvalds
16111da177e4SLinus Torvalds del_timer_sync(&scc->tx_t);
16121da177e4SLinus Torvalds del_timer_sync(&scc->tx_wdog);
16131da177e4SLinus Torvalds
16141da177e4SLinus Torvalds scc_discard_buffers(scc);
16151da177e4SLinus Torvalds
16161da177e4SLinus Torvalds return 0;
16171da177e4SLinus Torvalds }
16181da177e4SLinus Torvalds
16191da177e4SLinus Torvalds /* ----> receive frame, called from scc_rxint() <---- */
16201da177e4SLinus Torvalds
scc_net_rx(struct scc_channel * scc,struct sk_buff * skb)16211da177e4SLinus Torvalds static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
16221da177e4SLinus Torvalds {
16231da177e4SLinus Torvalds if (skb->len == 0) {
16241da177e4SLinus Torvalds dev_kfree_skb_irq(skb);
16251da177e4SLinus Torvalds return;
16261da177e4SLinus Torvalds }
16271da177e4SLinus Torvalds
16281da177e4SLinus Torvalds scc->dev_stat.rx_packets++;
16291da177e4SLinus Torvalds scc->dev_stat.rx_bytes += skb->len;
16301da177e4SLinus Torvalds
163156cb5156SArnaldo Carvalho de Melo skb->protocol = ax25_type_trans(skb, scc->dev);
16321da177e4SLinus Torvalds
16331da177e4SLinus Torvalds netif_rx(skb);
16341da177e4SLinus Torvalds }
16351da177e4SLinus Torvalds
16361da177e4SLinus Torvalds /* ----> transmit frame <---- */
16371da177e4SLinus Torvalds
scc_net_tx(struct sk_buff * skb,struct net_device * dev)163836e4d64aSStephen Hemminger static netdev_tx_t scc_net_tx(struct sk_buff *skb, struct net_device *dev)
16391da177e4SLinus Torvalds {
1640f4bdd264SWang Chen struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
16411da177e4SLinus Torvalds unsigned long flags;
16421da177e4SLinus Torvalds char kisscmd;
16431da177e4SLinus Torvalds
16441d5da757SEric W. Biederman if (skb->protocol == htons(ETH_P_IP))
16451d5da757SEric W. Biederman return ax25_ip_xmit(skb);
16461d5da757SEric W. Biederman
16471da177e4SLinus Torvalds if (skb->len > scc->stat.bufsize || skb->len < 2) {
16481da177e4SLinus Torvalds scc->dev_stat.tx_dropped++; /* bogus frame */
16491da177e4SLinus Torvalds dev_kfree_skb(skb);
16506ed10654SPatrick McHardy return NETDEV_TX_OK;
16511da177e4SLinus Torvalds }
16521da177e4SLinus Torvalds
16531da177e4SLinus Torvalds scc->dev_stat.tx_packets++;
16541da177e4SLinus Torvalds scc->dev_stat.tx_bytes += skb->len;
16551da177e4SLinus Torvalds scc->stat.txframes++;
16561da177e4SLinus Torvalds
16571da177e4SLinus Torvalds kisscmd = *skb->data & 0x1f;
16581da177e4SLinus Torvalds skb_pull(skb, 1);
16591da177e4SLinus Torvalds
16601da177e4SLinus Torvalds if (kisscmd) {
16611da177e4SLinus Torvalds scc_set_param(scc, kisscmd, *skb->data);
16621da177e4SLinus Torvalds dev_kfree_skb(skb);
16636ed10654SPatrick McHardy return NETDEV_TX_OK;
16641da177e4SLinus Torvalds }
16651da177e4SLinus Torvalds
16661da177e4SLinus Torvalds spin_lock_irqsave(&scc->lock, flags);
16671da177e4SLinus Torvalds
16681da177e4SLinus Torvalds if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) {
16691da177e4SLinus Torvalds struct sk_buff *skb_del;
16701da177e4SLinus Torvalds skb_del = skb_dequeue(&scc->tx_queue);
1671*3727f742SYang Yingliang dev_kfree_skb_irq(skb_del);
16721da177e4SLinus Torvalds }
16731da177e4SLinus Torvalds skb_queue_tail(&scc->tx_queue, skb);
1674860e9538SFlorian Westphal netif_trans_update(dev);
16751da177e4SLinus Torvalds
16761da177e4SLinus Torvalds
16771da177e4SLinus Torvalds /*
16781da177e4SLinus Torvalds * Start transmission if the trx state is idle or
16791da177e4SLinus Torvalds * t_idle hasn't expired yet. Use dwait/persistence/slottime
16801da177e4SLinus Torvalds * algorithm for normal halfduplex operation.
16811da177e4SLinus Torvalds */
16821da177e4SLinus Torvalds
16831da177e4SLinus Torvalds if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) {
16841da177e4SLinus Torvalds scc->stat.tx_state = TXS_BUSY;
16851da177e4SLinus Torvalds if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
16861da177e4SLinus Torvalds __scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime);
16871da177e4SLinus Torvalds else
16881da177e4SLinus Torvalds __scc_start_tx_timer(scc, t_dwait, 0);
16891da177e4SLinus Torvalds }
16901da177e4SLinus Torvalds spin_unlock_irqrestore(&scc->lock, flags);
16916ed10654SPatrick McHardy return NETDEV_TX_OK;
16921da177e4SLinus Torvalds }
16931da177e4SLinus Torvalds
16941da177e4SLinus Torvalds /* ----> ioctl functions <---- */
16951da177e4SLinus Torvalds
16961da177e4SLinus Torvalds /*
16971da177e4SLinus Torvalds * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg
16981da177e4SLinus Torvalds * SIOCSCCINI - initialize driver arg: ---
16991da177e4SLinus Torvalds * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg
17001da177e4SLinus Torvalds * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg
17011da177e4SLinus Torvalds * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg
17021da177e4SLinus Torvalds * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg
17031da177e4SLinus Torvalds * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg
17041da177e4SLinus Torvalds * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg
17051da177e4SLinus Torvalds */
17061da177e4SLinus Torvalds
scc_net_siocdevprivate(struct net_device * dev,struct ifreq * ifr,void __user * arg,int cmd)170725ec92fbSArnd Bergmann static int scc_net_siocdevprivate(struct net_device *dev,
170825ec92fbSArnd Bergmann struct ifreq *ifr, void __user *arg, int cmd)
17091da177e4SLinus Torvalds {
17101da177e4SLinus Torvalds struct scc_kiss_cmd kiss_cmd;
17111da177e4SLinus Torvalds struct scc_mem_config memcfg;
17121da177e4SLinus Torvalds struct scc_hw_config hwcfg;
17131da177e4SLinus Torvalds struct scc_calibrate cal;
1714f4bdd264SWang Chen struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
17151da177e4SLinus Torvalds int chan;
17161da177e4SLinus Torvalds unsigned char device_name[IFNAMSIZ];
17171da177e4SLinus Torvalds
17181da177e4SLinus Torvalds if (!Driver_Initialized)
17191da177e4SLinus Torvalds {
17201da177e4SLinus Torvalds if (cmd == SIOCSCCCFG)
17211da177e4SLinus Torvalds {
17221da177e4SLinus Torvalds int found = 1;
17231da177e4SLinus Torvalds
17241da177e4SLinus Torvalds if (!capable(CAP_SYS_RAWIO)) return -EPERM;
172525ec92fbSArnd Bergmann if (in_compat_syscall())
172625ec92fbSArnd Bergmann return -EOPNOTSUPP;
172725ec92fbSArnd Bergmann
17281da177e4SLinus Torvalds if (!arg) return -EFAULT;
17291da177e4SLinus Torvalds
17301da177e4SLinus Torvalds if (Nchips >= SCC_MAXCHIPS)
17311da177e4SLinus Torvalds return -EINVAL;
17321da177e4SLinus Torvalds
17331da177e4SLinus Torvalds if (copy_from_user(&hwcfg, arg, sizeof(hwcfg)))
17341da177e4SLinus Torvalds return -EFAULT;
17351da177e4SLinus Torvalds
17361da177e4SLinus Torvalds if (hwcfg.irq == 2) hwcfg.irq = 9;
17371da177e4SLinus Torvalds
173860e4ad7aSYinghai Lu if (hwcfg.irq < 0 || hwcfg.irq >= nr_irqs)
17391da177e4SLinus Torvalds return -EINVAL;
17401da177e4SLinus Torvalds
17411da177e4SLinus Torvalds if (!Ivec[hwcfg.irq].used && hwcfg.irq)
17421da177e4SLinus Torvalds {
17431b36efe0SJeff Garzik if (request_irq(hwcfg.irq, scc_isr,
17449714481eSMichael Opdenacker 0, "AX.25 SCC",
17451b36efe0SJeff Garzik (void *)(long) hwcfg.irq))
17461da177e4SLinus Torvalds printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq);
17471da177e4SLinus Torvalds else
17481da177e4SLinus Torvalds Ivec[hwcfg.irq].used = 1;
17491da177e4SLinus Torvalds }
17501da177e4SLinus Torvalds
17511da177e4SLinus Torvalds if (hwcfg.vector_latch && !Vector_Latch) {
17521da177e4SLinus Torvalds if (!request_region(hwcfg.vector_latch, 1, "scc vector latch"))
17531da177e4SLinus Torvalds printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch);
17541da177e4SLinus Torvalds else
17551da177e4SLinus Torvalds Vector_Latch = hwcfg.vector_latch;
17561da177e4SLinus Torvalds }
17571da177e4SLinus Torvalds
17581da177e4SLinus Torvalds if (hwcfg.clock == 0)
17591da177e4SLinus Torvalds hwcfg.clock = SCC_DEFAULT_CLOCK;
17601da177e4SLinus Torvalds
17611da177e4SLinus Torvalds #ifndef SCC_DONT_CHECK
17621da177e4SLinus Torvalds
17631da177e4SLinus Torvalds if(request_region(hwcfg.ctrl_a, 1, "scc-probe"))
17641da177e4SLinus Torvalds {
17651da177e4SLinus Torvalds disable_irq(hwcfg.irq);
17661da177e4SLinus Torvalds Outb(hwcfg.ctrl_a, 0);
17671da177e4SLinus Torvalds OutReg(hwcfg.ctrl_a, R9, FHWRES);
17681da177e4SLinus Torvalds udelay(100);
17691da177e4SLinus Torvalds OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
17701da177e4SLinus Torvalds udelay(5);
17711da177e4SLinus Torvalds
17721da177e4SLinus Torvalds if (InReg(hwcfg.ctrl_a,R13) != 0x55)
17731da177e4SLinus Torvalds found = 0;
17741da177e4SLinus Torvalds enable_irq(hwcfg.irq);
17751da177e4SLinus Torvalds release_region(hwcfg.ctrl_a, 1);
17761da177e4SLinus Torvalds }
17771da177e4SLinus Torvalds else
17781da177e4SLinus Torvalds found = 0;
17791da177e4SLinus Torvalds #endif
17801da177e4SLinus Torvalds
17811da177e4SLinus Torvalds if (found)
17821da177e4SLinus Torvalds {
17831da177e4SLinus Torvalds SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a;
17841da177e4SLinus Torvalds SCC_Info[2*Nchips ].data = hwcfg.data_a;
17851da177e4SLinus Torvalds SCC_Info[2*Nchips ].irq = hwcfg.irq;
17861da177e4SLinus Torvalds SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b;
17871da177e4SLinus Torvalds SCC_Info[2*Nchips+1].data = hwcfg.data_b;
17881da177e4SLinus Torvalds SCC_Info[2*Nchips+1].irq = hwcfg.irq;
17891da177e4SLinus Torvalds
17901da177e4SLinus Torvalds SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a;
17911da177e4SLinus Torvalds SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b;
17921da177e4SLinus Torvalds SCC_ctrl[Nchips].irq = hwcfg.irq;
17931da177e4SLinus Torvalds }
17941da177e4SLinus Torvalds
17951da177e4SLinus Torvalds
17961da177e4SLinus Torvalds for (chan = 0; chan < 2; chan++)
17971da177e4SLinus Torvalds {
17981da177e4SLinus Torvalds sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan);
17991da177e4SLinus Torvalds
18001da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].special = hwcfg.special;
18011da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].clock = hwcfg.clock;
18021da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].brand = hwcfg.brand;
18031da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].option = hwcfg.option;
18041da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;
18051da177e4SLinus Torvalds
18061da177e4SLinus Torvalds #ifdef SCC_DONT_CHECK
18071da177e4SLinus Torvalds printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n",
18081da177e4SLinus Torvalds device_name,
18091da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].data,
18101da177e4SLinus Torvalds SCC_Info[2*Nchips+chan].ctrl);
18111da177e4SLinus Torvalds
18121da177e4SLinus Torvalds #else
18131da177e4SLinus Torvalds printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n",
18141da177e4SLinus Torvalds device_name,
18151da177e4SLinus Torvalds chan? hwcfg.data_b : hwcfg.data_a,
18161da177e4SLinus Torvalds chan? hwcfg.ctrl_b : hwcfg.ctrl_a,
18171da177e4SLinus Torvalds found? "found" : "missing");
18181da177e4SLinus Torvalds #endif
18191da177e4SLinus Torvalds
18201da177e4SLinus Torvalds if (found)
18211da177e4SLinus Torvalds {
18221da177e4SLinus Torvalds request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");
18231da177e4SLinus Torvalds request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");
18241da177e4SLinus Torvalds if (Nchips+chan != 0 &&
18251da177e4SLinus Torvalds scc_net_alloc(device_name,
18261da177e4SLinus Torvalds &SCC_Info[2*Nchips+chan]))
18271da177e4SLinus Torvalds return -EINVAL;
18281da177e4SLinus Torvalds }
18291da177e4SLinus Torvalds }
18301da177e4SLinus Torvalds
18311da177e4SLinus Torvalds if (found) Nchips++;
18321da177e4SLinus Torvalds
18331da177e4SLinus Torvalds return 0;
18341da177e4SLinus Torvalds }
18351da177e4SLinus Torvalds
18361da177e4SLinus Torvalds if (cmd == SIOCSCCINI)
18371da177e4SLinus Torvalds {
18381da177e4SLinus Torvalds if (!capable(CAP_SYS_RAWIO))
18391da177e4SLinus Torvalds return -EPERM;
18401da177e4SLinus Torvalds
18411da177e4SLinus Torvalds if (Nchips == 0)
18421da177e4SLinus Torvalds return -EINVAL;
18431da177e4SLinus Torvalds
18441da177e4SLinus Torvalds z8530_init();
18451da177e4SLinus Torvalds return 0;
18461da177e4SLinus Torvalds }
18471da177e4SLinus Torvalds
18481da177e4SLinus Torvalds return -EINVAL; /* confuse the user */
18491da177e4SLinus Torvalds }
18501da177e4SLinus Torvalds
18511da177e4SLinus Torvalds if (!scc->init)
18521da177e4SLinus Torvalds {
18531da177e4SLinus Torvalds if (cmd == SIOCSCCCHANINI)
18541da177e4SLinus Torvalds {
18551da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) return -EPERM;
18561da177e4SLinus Torvalds if (!arg) return -EINVAL;
18571da177e4SLinus Torvalds
18581da177e4SLinus Torvalds scc->stat.bufsize = SCC_BUFSIZE;
18591da177e4SLinus Torvalds
18601da177e4SLinus Torvalds if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem)))
18611da177e4SLinus Torvalds return -EINVAL;
18621da177e4SLinus Torvalds
18631da177e4SLinus Torvalds /* default KISS Params */
18641da177e4SLinus Torvalds
18651da177e4SLinus Torvalds if (scc->modem.speed < 4800)
18661da177e4SLinus Torvalds {
18671da177e4SLinus Torvalds scc->kiss.txdelay = 36; /* 360 ms */
18681da177e4SLinus Torvalds scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */
18691da177e4SLinus Torvalds scc->kiss.slottime = 16; /* 160 ms */
18701da177e4SLinus Torvalds scc->kiss.tailtime = 4; /* minimal reasonable value */
18711da177e4SLinus Torvalds scc->kiss.fulldup = 0; /* CSMA */
18721da177e4SLinus Torvalds scc->kiss.waittime = 50; /* 500 ms */
18731da177e4SLinus Torvalds scc->kiss.maxkeyup = 10; /* 10 s */
18741da177e4SLinus Torvalds scc->kiss.mintime = 3; /* 3 s */
18751da177e4SLinus Torvalds scc->kiss.idletime = 30; /* 30 s */
18761da177e4SLinus Torvalds scc->kiss.maxdefer = 120; /* 2 min */
18771da177e4SLinus Torvalds scc->kiss.softdcd = 0; /* hardware dcd */
18781da177e4SLinus Torvalds } else {
18791da177e4SLinus Torvalds scc->kiss.txdelay = 10; /* 100 ms */
18801da177e4SLinus Torvalds scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */
18811da177e4SLinus Torvalds scc->kiss.slottime = 8; /* 160 ms */
18821da177e4SLinus Torvalds scc->kiss.tailtime = 1; /* minimal reasonable value */
18831da177e4SLinus Torvalds scc->kiss.fulldup = 0; /* CSMA */
18841da177e4SLinus Torvalds scc->kiss.waittime = 50; /* 500 ms */
18851da177e4SLinus Torvalds scc->kiss.maxkeyup = 7; /* 7 s */
18861da177e4SLinus Torvalds scc->kiss.mintime = 3; /* 3 s */
18871da177e4SLinus Torvalds scc->kiss.idletime = 30; /* 30 s */
18881da177e4SLinus Torvalds scc->kiss.maxdefer = 120; /* 2 min */
18891da177e4SLinus Torvalds scc->kiss.softdcd = 0; /* hardware dcd */
18901da177e4SLinus Torvalds }
18911da177e4SLinus Torvalds
18921da177e4SLinus Torvalds scc->tx_buff = NULL;
18931da177e4SLinus Torvalds skb_queue_head_init(&scc->tx_queue);
18941da177e4SLinus Torvalds scc->init = 1;
18951da177e4SLinus Torvalds
18961da177e4SLinus Torvalds return 0;
18971da177e4SLinus Torvalds }
18981da177e4SLinus Torvalds
18991da177e4SLinus Torvalds return -EINVAL;
19001da177e4SLinus Torvalds }
19011da177e4SLinus Torvalds
19021da177e4SLinus Torvalds switch(cmd)
19031da177e4SLinus Torvalds {
19041da177e4SLinus Torvalds case SIOCSCCRESERVED:
19051da177e4SLinus Torvalds return -ENOIOCTLCMD;
19061da177e4SLinus Torvalds
19071da177e4SLinus Torvalds case SIOCSCCSMEM:
19081da177e4SLinus Torvalds if (!capable(CAP_SYS_RAWIO)) return -EPERM;
19091da177e4SLinus Torvalds if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg)))
19101da177e4SLinus Torvalds return -EINVAL;
19111da177e4SLinus Torvalds scc->stat.bufsize = memcfg.bufsize;
19121da177e4SLinus Torvalds return 0;
19131da177e4SLinus Torvalds
19141da177e4SLinus Torvalds case SIOCSCCGSTAT:
19151da177e4SLinus Torvalds if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat)))
19161da177e4SLinus Torvalds return -EINVAL;
19171da177e4SLinus Torvalds return 0;
19181da177e4SLinus Torvalds
19191da177e4SLinus Torvalds case SIOCSCCGKISS:
19201da177e4SLinus Torvalds if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
19211da177e4SLinus Torvalds return -EINVAL;
19221da177e4SLinus Torvalds kiss_cmd.param = scc_get_param(scc, kiss_cmd.command);
19231da177e4SLinus Torvalds if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd)))
19241da177e4SLinus Torvalds return -EINVAL;
19251da177e4SLinus Torvalds return 0;
19261da177e4SLinus Torvalds
19271da177e4SLinus Torvalds case SIOCSCCSKISS:
19281da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) return -EPERM;
19291da177e4SLinus Torvalds if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
19301da177e4SLinus Torvalds return -EINVAL;
19311da177e4SLinus Torvalds return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param);
19321da177e4SLinus Torvalds
19331da177e4SLinus Torvalds case SIOCSCCCAL:
19341da177e4SLinus Torvalds if (!capable(CAP_SYS_RAWIO)) return -EPERM;
19351da177e4SLinus Torvalds if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0)
19361da177e4SLinus Torvalds return -EINVAL;
19371da177e4SLinus Torvalds
19381da177e4SLinus Torvalds scc_start_calibrate(scc, cal.time, cal.pattern);
19391da177e4SLinus Torvalds return 0;
19401da177e4SLinus Torvalds
19411da177e4SLinus Torvalds default:
19421da177e4SLinus Torvalds return -ENOIOCTLCMD;
19431da177e4SLinus Torvalds
19441da177e4SLinus Torvalds }
19451da177e4SLinus Torvalds
19461da177e4SLinus Torvalds return -EINVAL;
19471da177e4SLinus Torvalds }
19481da177e4SLinus Torvalds
19491da177e4SLinus Torvalds /* ----> set interface callsign <---- */
19501da177e4SLinus Torvalds
scc_net_set_mac_address(struct net_device * dev,void * addr)19511da177e4SLinus Torvalds static int scc_net_set_mac_address(struct net_device *dev, void *addr)
19521da177e4SLinus Torvalds {
19531da177e4SLinus Torvalds struct sockaddr *sa = (struct sockaddr *) addr;
1954ea52a0b5SJakub Kicinski dev_addr_set(dev, sa->sa_data);
19551da177e4SLinus Torvalds return 0;
19561da177e4SLinus Torvalds }
19571da177e4SLinus Torvalds
19581da177e4SLinus Torvalds /* ----> get statistics <---- */
19591da177e4SLinus Torvalds
scc_net_get_stats(struct net_device * dev)19601da177e4SLinus Torvalds static struct net_device_stats *scc_net_get_stats(struct net_device *dev)
19611da177e4SLinus Torvalds {
1962f4bdd264SWang Chen struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
19631da177e4SLinus Torvalds
19641da177e4SLinus Torvalds scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over;
19651da177e4SLinus Torvalds scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under;
19661da177e4SLinus Torvalds scc->dev_stat.rx_fifo_errors = scc->stat.rx_over;
19671da177e4SLinus Torvalds scc->dev_stat.tx_fifo_errors = scc->stat.tx_under;
19681da177e4SLinus Torvalds
19691da177e4SLinus Torvalds return &scc->dev_stat;
19701da177e4SLinus Torvalds }
19711da177e4SLinus Torvalds
19721da177e4SLinus Torvalds /* ******************************************************************** */
19731da177e4SLinus Torvalds /* * dump statistics to /proc/net/z8530drv * */
19741da177e4SLinus Torvalds /* ******************************************************************** */
19751da177e4SLinus Torvalds
19761da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
19771da177e4SLinus Torvalds
scc_net_seq_idx(loff_t pos)19781da177e4SLinus Torvalds static inline struct scc_channel *scc_net_seq_idx(loff_t pos)
19791da177e4SLinus Torvalds {
19801da177e4SLinus Torvalds int k;
19811da177e4SLinus Torvalds
19821da177e4SLinus Torvalds for (k = 0; k < Nchips*2; ++k) {
19831da177e4SLinus Torvalds if (!SCC_Info[k].init)
19841da177e4SLinus Torvalds continue;
19851da177e4SLinus Torvalds if (pos-- == 0)
19861da177e4SLinus Torvalds return &SCC_Info[k];
19871da177e4SLinus Torvalds }
19881da177e4SLinus Torvalds return NULL;
19891da177e4SLinus Torvalds }
19901da177e4SLinus Torvalds
scc_net_seq_start(struct seq_file * seq,loff_t * pos)19911da177e4SLinus Torvalds static void *scc_net_seq_start(struct seq_file *seq, loff_t *pos)
19921da177e4SLinus Torvalds {
19931da177e4SLinus Torvalds return *pos ? scc_net_seq_idx(*pos - 1) : SEQ_START_TOKEN;
19941da177e4SLinus Torvalds
19951da177e4SLinus Torvalds }
19961da177e4SLinus Torvalds
scc_net_seq_next(struct seq_file * seq,void * v,loff_t * pos)19971da177e4SLinus Torvalds static void *scc_net_seq_next(struct seq_file *seq, void *v, loff_t *pos)
19981da177e4SLinus Torvalds {
19991da177e4SLinus Torvalds unsigned k;
20001da177e4SLinus Torvalds struct scc_channel *scc = v;
20011da177e4SLinus Torvalds ++*pos;
20021da177e4SLinus Torvalds
20031da177e4SLinus Torvalds for (k = (v == SEQ_START_TOKEN) ? 0 : (scc - SCC_Info)+1;
20041da177e4SLinus Torvalds k < Nchips*2; ++k) {
20051da177e4SLinus Torvalds if (SCC_Info[k].init)
20061da177e4SLinus Torvalds return &SCC_Info[k];
20071da177e4SLinus Torvalds }
20081da177e4SLinus Torvalds return NULL;
20091da177e4SLinus Torvalds }
20101da177e4SLinus Torvalds
scc_net_seq_stop(struct seq_file * seq,void * v)20111da177e4SLinus Torvalds static void scc_net_seq_stop(struct seq_file *seq, void *v)
20121da177e4SLinus Torvalds {
20131da177e4SLinus Torvalds }
20141da177e4SLinus Torvalds
scc_net_seq_show(struct seq_file * seq,void * v)20151da177e4SLinus Torvalds static int scc_net_seq_show(struct seq_file *seq, void *v)
20161da177e4SLinus Torvalds {
20171da177e4SLinus Torvalds if (v == SEQ_START_TOKEN) {
20181da177e4SLinus Torvalds seq_puts(seq, "z8530drv-"VERSION"\n");
20191da177e4SLinus Torvalds } else if (!Driver_Initialized) {
20201da177e4SLinus Torvalds seq_puts(seq, "not initialized\n");
20211da177e4SLinus Torvalds } else if (!Nchips) {
20221da177e4SLinus Torvalds seq_puts(seq, "chips missing\n");
20231da177e4SLinus Torvalds } else {
20241da177e4SLinus Torvalds const struct scc_channel *scc = v;
20251da177e4SLinus Torvalds const struct scc_stat *stat = &scc->stat;
20261da177e4SLinus Torvalds const struct scc_kiss *kiss = &scc->kiss;
20271da177e4SLinus Torvalds
20281da177e4SLinus Torvalds
20291da177e4SLinus Torvalds /* dev data ctrl irq clock brand enh vector special option
20301da177e4SLinus Torvalds * baud nrz clocksrc softdcd bufsize
20311da177e4SLinus Torvalds * rxints txints exints spints
20321da177e4SLinus Torvalds * rcvd rxerrs over / xmit txerrs under / nospace bufsize
20331da177e4SLinus Torvalds * txd pers slot tail ful wait min maxk idl defr txof grp
20341da177e4SLinus Torvalds * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
20351da177e4SLinus Torvalds * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ##
20361da177e4SLinus Torvalds */
20371da177e4SLinus Torvalds
20381da177e4SLinus Torvalds seq_printf(seq, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n",
20391da177e4SLinus Torvalds scc->dev->name,
20401da177e4SLinus Torvalds scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand,
20411da177e4SLinus Torvalds scc->enhanced, Vector_Latch, scc->special,
20421da177e4SLinus Torvalds scc->option);
20431da177e4SLinus Torvalds seq_printf(seq, "\t%lu %d %d %d %d\n",
20441da177e4SLinus Torvalds scc->modem.speed, scc->modem.nrz,
20451da177e4SLinus Torvalds scc->modem.clocksrc, kiss->softdcd,
20461da177e4SLinus Torvalds stat->bufsize);
20471da177e4SLinus Torvalds seq_printf(seq, "\t%lu %lu %lu %lu\n",
20481da177e4SLinus Torvalds stat->rxints, stat->txints, stat->exints, stat->spints);
20491da177e4SLinus Torvalds seq_printf(seq, "\t%lu %lu %d / %lu %lu %d / %d %d\n",
20501da177e4SLinus Torvalds stat->rxframes, stat->rxerrs, stat->rx_over,
20511da177e4SLinus Torvalds stat->txframes, stat->txerrs, stat->tx_under,
20521da177e4SLinus Torvalds stat->nospace, stat->tx_state);
20531da177e4SLinus Torvalds
20541da177e4SLinus Torvalds #define K(x) kiss->x
20551da177e4SLinus Torvalds seq_printf(seq, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n",
20561da177e4SLinus Torvalds K(txdelay), K(persist), K(slottime), K(tailtime),
20571da177e4SLinus Torvalds K(fulldup), K(waittime), K(mintime), K(maxkeyup),
20581da177e4SLinus Torvalds K(idletime), K(maxdefer), K(tx_inhibit), K(group));
20591da177e4SLinus Torvalds #undef K
20601da177e4SLinus Torvalds #ifdef SCC_DEBUG
20611da177e4SLinus Torvalds {
20621da177e4SLinus Torvalds int reg;
20631da177e4SLinus Torvalds
20641da177e4SLinus Torvalds seq_printf(seq, "\tW ");
20651da177e4SLinus Torvalds for (reg = 0; reg < 16; reg++)
20661da177e4SLinus Torvalds seq_printf(seq, "%2.2x ", scc->wreg[reg]);
20671da177e4SLinus Torvalds seq_printf(seq, "\n");
20681da177e4SLinus Torvalds
20691da177e4SLinus Torvalds seq_printf(seq, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1));
20701da177e4SLinus Torvalds for (reg = 3; reg < 8; reg++)
20711da177e4SLinus Torvalds seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg));
20721da177e4SLinus Torvalds seq_printf(seq, "XX ");
20731da177e4SLinus Torvalds for (reg = 9; reg < 16; reg++)
20741da177e4SLinus Torvalds seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg));
20751da177e4SLinus Torvalds seq_printf(seq, "\n");
20761da177e4SLinus Torvalds }
20771da177e4SLinus Torvalds #endif
20781da177e4SLinus Torvalds seq_putc(seq, '\n');
20791da177e4SLinus Torvalds }
20801da177e4SLinus Torvalds
20811da177e4SLinus Torvalds return 0;
20821da177e4SLinus Torvalds }
20831da177e4SLinus Torvalds
20844101dec9SJan Engelhardt static const struct seq_operations scc_net_seq_ops = {
20851da177e4SLinus Torvalds .start = scc_net_seq_start,
20861da177e4SLinus Torvalds .next = scc_net_seq_next,
20871da177e4SLinus Torvalds .stop = scc_net_seq_stop,
20881da177e4SLinus Torvalds .show = scc_net_seq_show,
20891da177e4SLinus Torvalds };
20901da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
20911da177e4SLinus Torvalds
20921da177e4SLinus Torvalds
20931da177e4SLinus Torvalds /* ******************************************************************** */
20941da177e4SLinus Torvalds /* * Init SCC driver * */
20951da177e4SLinus Torvalds /* ******************************************************************** */
20961da177e4SLinus Torvalds
scc_init_driver(void)20971da177e4SLinus Torvalds static int __init scc_init_driver (void)
20981da177e4SLinus Torvalds {
20991da177e4SLinus Torvalds char devname[IFNAMSIZ];
21001da177e4SLinus Torvalds
21011da177e4SLinus Torvalds printk(banner);
21021da177e4SLinus Torvalds
21031da177e4SLinus Torvalds sprintf(devname,"%s0", SCC_DriverName);
21041da177e4SLinus Torvalds
21051da177e4SLinus Torvalds rtnl_lock();
21061da177e4SLinus Torvalds if (scc_net_alloc(devname, SCC_Info)) {
21071da177e4SLinus Torvalds rtnl_unlock();
21081da177e4SLinus Torvalds printk(KERN_ERR "z8530drv: cannot initialize module\n");
21091da177e4SLinus Torvalds return -EIO;
21101da177e4SLinus Torvalds }
21111da177e4SLinus Torvalds rtnl_unlock();
21121da177e4SLinus Torvalds
2113fddda2b7SChristoph Hellwig proc_create_seq("z8530drv", 0, init_net.proc_net, &scc_net_seq_ops);
21141da177e4SLinus Torvalds
21151da177e4SLinus Torvalds return 0;
21161da177e4SLinus Torvalds }
21171da177e4SLinus Torvalds
scc_cleanup_driver(void)21181da177e4SLinus Torvalds static void __exit scc_cleanup_driver(void)
21191da177e4SLinus Torvalds {
21201da177e4SLinus Torvalds io_port ctrl;
21211da177e4SLinus Torvalds int k;
21221da177e4SLinus Torvalds struct scc_channel *scc;
21231da177e4SLinus Torvalds struct net_device *dev;
21241da177e4SLinus Torvalds
21251da177e4SLinus Torvalds if (Nchips == 0 && (dev = SCC_Info[0].dev))
21261da177e4SLinus Torvalds {
21271da177e4SLinus Torvalds unregister_netdev(dev);
21281da177e4SLinus Torvalds free_netdev(dev);
21291da177e4SLinus Torvalds }
21301da177e4SLinus Torvalds
21311da177e4SLinus Torvalds /* Guard against chip prattle */
21321da177e4SLinus Torvalds local_irq_disable();
21331da177e4SLinus Torvalds
21341da177e4SLinus Torvalds for (k = 0; k < Nchips; k++)
21351da177e4SLinus Torvalds if ( (ctrl = SCC_ctrl[k].chan_A) )
21361da177e4SLinus Torvalds {
21371da177e4SLinus Torvalds Outb(ctrl, 0);
21381da177e4SLinus Torvalds OutReg(ctrl,R9,FHWRES); /* force hardware reset */
21391da177e4SLinus Torvalds udelay(50);
21401da177e4SLinus Torvalds }
21411da177e4SLinus Torvalds
21421da177e4SLinus Torvalds /* To unload the port must be closed so no real IRQ pending */
214360e4ad7aSYinghai Lu for (k = 0; k < nr_irqs ; k++)
21441da177e4SLinus Torvalds if (Ivec[k].used) free_irq(k, NULL);
21451da177e4SLinus Torvalds
21461da177e4SLinus Torvalds local_irq_enable();
21471da177e4SLinus Torvalds
21481da177e4SLinus Torvalds /* Now clean up */
21491da177e4SLinus Torvalds for (k = 0; k < Nchips*2; k++)
21501da177e4SLinus Torvalds {
21511da177e4SLinus Torvalds scc = &SCC_Info[k];
21521da177e4SLinus Torvalds if (scc->ctrl)
21531da177e4SLinus Torvalds {
21541da177e4SLinus Torvalds release_region(scc->ctrl, 1);
21551da177e4SLinus Torvalds release_region(scc->data, 1);
21561da177e4SLinus Torvalds }
21571da177e4SLinus Torvalds if (scc->dev)
21581da177e4SLinus Torvalds {
21591da177e4SLinus Torvalds unregister_netdev(scc->dev);
21601da177e4SLinus Torvalds free_netdev(scc->dev);
21611da177e4SLinus Torvalds }
21621da177e4SLinus Torvalds }
21631da177e4SLinus Torvalds
21641da177e4SLinus Torvalds
21651da177e4SLinus Torvalds if (Vector_Latch)
21661da177e4SLinus Torvalds release_region(Vector_Latch, 1);
21671da177e4SLinus Torvalds
2168ece31ffdSGao feng remove_proc_entry("z8530drv", init_net.proc_net);
21691da177e4SLinus Torvalds }
21701da177e4SLinus Torvalds
21711da177e4SLinus Torvalds MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
21721da177e4SLinus Torvalds MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards");
21731da177e4SLinus Torvalds MODULE_LICENSE("GPL");
21741da177e4SLinus Torvalds module_init(scc_init_driver);
21751da177e4SLinus Torvalds module_exit(scc_cleanup_driver);
2176