]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.25 2.1.25
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:12:55 +0000 (15:12 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:12:55 +0000 (15:12 -0500)
208 files changed:
CREDITS
Documentation/Configure.help
Documentation/filesystems/vfs.txt [new file with mode: 0644]
Documentation/ioctl-number.txt
Documentation/magic-number.txt
Documentation/networking/00-INDEX
Documentation/networking/ax25.txt
Documentation/networking/cs89x0.txt [new file with mode: 0644]
Documentation/networking/wan-router.txt [new file with mode: 0644]
Documentation/serial-console.txt [new file with mode: 0644]
Documentation/smp [new file with mode: 0644]
Documentation/watchdog.txt
MAINTAINERS
Makefile
arch/alpha/kernel/bios32.c
arch/alpha/kernel/traps.c
arch/i386/boot/setup.S
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/i386/kernel/vm86.c
arch/i386/lib/checksum.c
drivers/cdrom/isp16.c
drivers/cdrom/sjcd.c
drivers/char/apm_bios.c
drivers/char/console.c
drivers/char/softdog.c
drivers/net/3c501.c
drivers/net/3c505.c
drivers/net/3c505.h
drivers/net/3c507.c
drivers/net/3c509.c
drivers/net/3c523.c
drivers/net/3c59x.c
drivers/net/8390.c
drivers/net/8390.h
drivers/net/CONFIG
drivers/net/Config.in
drivers/net/Makefile
drivers/net/README.de4x5
drivers/net/README.ltpc [new file with mode: 0644]
drivers/net/README.multicast
drivers/net/README.wanpipe [new file with mode: 0644]
drivers/net/Space.c
drivers/net/a2065.c
drivers/net/apricot.c
drivers/net/arcnet.c
drivers/net/ariadne.c
drivers/net/at1700.c
drivers/net/atari_bionet.c
drivers/net/atari_pamsnet.c
drivers/net/atarilance.c
drivers/net/atp.c
drivers/net/atp.h
drivers/net/bpqether.c
drivers/net/cs89x0.c [new file with mode: 0644]
drivers/net/cs89x0.h [new file with mode: 0644]
drivers/net/de4x5.c
drivers/net/de4x5.h
drivers/net/de600.c
drivers/net/de620.c
drivers/net/defxx.c
drivers/net/depca.c
drivers/net/dgrs.c
drivers/net/dlci.c
drivers/net/dummy.c
drivers/net/eepro.c
drivers/net/eexpress.c
drivers/net/eql.c
drivers/net/eth16i.c
drivers/net/ewrk3.c
drivers/net/fmv18x.c
drivers/net/hdlcdrv.c
drivers/net/hp100.c
drivers/net/hydra.c
drivers/net/ibmtr.c
drivers/net/lance.c
drivers/net/lance32.c
drivers/net/lapbether.c
drivers/net/loopback.c
drivers/net/ltpc.c [new file with mode: 0644]
drivers/net/ltpc.h [new file with mode: 0644]
drivers/net/mkiss.c
drivers/net/myri_sbus.c
drivers/net/myri_sbus.h
drivers/net/net_init.c
drivers/net/ni52.c
drivers/net/ni65.c
drivers/net/pi2.c
drivers/net/pi2.h
drivers/net/plip.c
drivers/net/ppp.c
drivers/net/pt.c
drivers/net/pt.h
drivers/net/scc.c
drivers/net/sdla.c
drivers/net/sdla_fr.c [new file with mode: 0644]
drivers/net/sdla_ppp.c [new file with mode: 0644]
drivers/net/sdla_x25.c [new file with mode: 0644]
drivers/net/sdladrv.c [new file with mode: 0644]
drivers/net/sdlamain.c [new file with mode: 0644]
drivers/net/seeq8005.c
drivers/net/shaper.c
drivers/net/shaper.h
drivers/net/sk_g16.c
drivers/net/skeleton.c
drivers/net/slip.c
drivers/net/slip.h
drivers/net/smc9194.c
drivers/net/strip.c
drivers/net/sunhme.c
drivers/net/sunhme.h
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/sunqe.h
drivers/net/tulip.c
drivers/net/tunnel.c
drivers/net/wavelan.p.h
drivers/net/wic.c [deleted file]
drivers/net/znet.c
drivers/scsi/Config.in
drivers/scsi/qlogicfas.c
drivers/scsi/qlogicisp.c
drivers/scsi/qlogicisp_asm.c
drivers/scsi/scsi.c
drivers/scsi/wd7000.c
fs/proc/procfs_syms.c
fs/proc/root.c
fs/smbfs/sock.c
include/asm-i386/checksum.h
include/asm-i386/smp_lock.h
include/linux/ax25.h
include/linux/if_arp.h
include/linux/if_ether.h
include/linux/if_ltalk.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/rose.h
include/linux/sdla_fr.h [new file with mode: 0644]
include/linux/sdla_ppp.h [new file with mode: 0644]
include/linux/sdla_x25.h [new file with mode: 0644]
include/linux/sdladrv.h [new file with mode: 0644]
include/linux/sdlasfm.h [new file with mode: 0644]
include/linux/socket.h
include/linux/sysctl.h
include/linux/tty_ldisc.h
include/linux/wanpipe.h [new file with mode: 0644]
include/linux/wanrouter.h [new file with mode: 0644]
include/net/ax25.h
include/net/netrom.h
include/net/rose.h
init/main.c
kernel/module.c
kernel/sched.c
kernel/sys.c
net/Config.in
net/Makefile
net/README
net/appletalk/aarp.c
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/ax25/ax25_in.c
net/ax25/ax25_out.c
net/ax25/ax25_route.c
net/ax25/ax25_subr.c
net/ax25/ax25_timer.c
net/ax25/sysctl_net_ax25.c
net/core/dev.c
net/core/firewall.c
net/core/iovec.c
net/ipv4/Config.in
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/fib.c
net/ipv4/ip_forward.c
net/ipv4/ip_fw.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/ipv6/tcp_ipv6.c
net/lapb/lapb_iface.c
net/lapb/lapb_in.c
net/lapb/lapb_timer.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_in.c
net/netrom/nr_out.c
net/netrom/nr_route.c
net/netrom/nr_subr.c
net/netrom/nr_timer.c
net/netrom/sysctl_net_netrom.c
net/netsyms.c
net/rose/af_rose.c
net/rose/rose_dev.c
net/rose/rose_in.c
net/rose/rose_link.c
net/rose/rose_out.c
net/rose/rose_route.c
net/rose/rose_timer.c
net/rose/sysctl_net_rose.c
net/socket.c
net/wanrouter/Makefile [new file with mode: 0644]
net/wanrouter/patchlevel [new file with mode: 0644]
net/wanrouter/wanmain.c [new file with mode: 0644]
net/wanrouter/wanproc.c [new file with mode: 0644]
net/x25/af_x25.c
net/x25/x25_link.c
net/x25/x25_timer.c

diff --git a/CREDITS b/CREDITS
index e407541715252b836458746209410fd2b7299852..e9d51d7b1c9338beee413ae66ebf6c8275d30f0e 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -757,6 +757,16 @@ S: Kruislaan 419
 S: 1098 VA Amsterdam 
 S: The Netherlands
 
+N: Gene Kozin
+E: 74604.152@compuserve.com
+W: http://www.sangoma.com
+D: WAN Router & Sangoma WAN drivers
+S: Sangoma Technologies Inc.
+S: 7170 Warden Avenue, Unit 2
+S: Markham, Ontario
+S: L3R 8B2
+S: Canada
+
 N: Gero Kuhlmann
 E: gero@gkminix.han.de
 D: mounting root via NFS
index 2553c8020726228b11e4c76a1c24cfbcf3e0273f..07886728a2f53c618ed75f3e4bb830bffda0e05d 100644 (file)
@@ -841,41 +841,6 @@ CONFIG_INET
   on sunsite.unc.edu:/pub/Linux/docs/HOWTO).  Short answer:
   say Y.
 
-IP: forwarding/gatewaying
-CONFIG_IP_FORWARD
-  People who want to use their Linux box as the router for a local
-  network (i.e. the computer responsible for distributing Internet
-  traffic to and from the machines in the local network and the
-  subnetworks) should say Y here (thereby enlarging their kernel by
-  about 5 kB). Note that in this case, you possibly have two ethernet
-  devices in your computer: one for the "outside world" and one for
-  your local net. The kernel is not able to recognize both at boot
-  time without help; for details read the
-  Multiple-Ethernet-mini-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.  If your box is
-  connected to two networks, it may still make sense to say N here,
-  namely if you want to turn your box into a firewall protecting a
-  local network from the internet. The Firewall-HOWTO tells you how to
-  do this. If your setup is more complex, say you are connected to
-  three networks and you want to act as a firewall between two of them
-  and route traffic for the others, you need to say Y here and Y to 
-  "IP firewalling" below. If you intend to use IP masquerading (i.e. IP
-  traffic from one of the local computers and destined for an outside
-  host is changed by your box so that it appears to come from you),
-  you'll have to say Y here and also to IP firewalling and IP
-  masquerading below. You should also say Y here if you want to
-  configure your box as a SLIP (the protocol for sending internet
-  traffic over telephone lines) or PPP (a better SLIP) server for
-  other people to dial into and your box is connected to a local
-  network at the same time. You would then most likely use proxy-ARP
-  (Address Resolution Protocol), explained in the Proxy-Arp mini howto
-  on sunsite in /pub/Linux/docs/HOWTO/mini. You also need to say Y
-  here if you want to run mrouted in order to do multicast routing as
-  used on the MBONE (a high bandwidth network on top of the internet
-  which carries audio and video broadcasts) for example. In this case,
-  say Y to "IP: multicasting" and "IP: multicast routing" as well. If
-  unsure, say N.
-
 IP: multicasting
 CONFIG_IP_MULTICAST
   This is code for addressing several networked computers at once,
@@ -1249,6 +1214,23 @@ CONFIG_ATALK
   all you will need to do is download and install the localtalk
   driver.
 
+IP-over-DDP support
+CONFIG_IPDDP
+  This allows IP networking for users who only have Appletalk
+  networking available.  It doesn't work yet in 2.1.xx, so you
+  should say N.
+
+LocalTalk PC card support
+CONFIG_LTPC
+  This allows you to use the AppleTalk PC card to connect to LocalTalk
+  networks.  The card is also known as the Farallon PhoneNet PC card.
+  If you are in doubt, this card is the one with the 65C02 chip on it.
+  You also need version 1.3.3 or later of the netatalk package.
+  This driver is experimental, which means that it may not work.
+  In particular the module support is not yet working for the 2.1.xx
+  kernels, so choose Y or N, but not M for now.
+  See README.ltpc in the drivers/net directory.
+
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
   This is the protocol used for computer communication over amateur
@@ -2156,14 +2138,6 @@ CONFIG_STRIP
   the running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called strip.o.
 
-WIC (Radio IP bridge)
-CONFIG_WIC
-  Support for the WIC parallel port radio bridge. You'll probably want
-  to say N.  If you want to compile this driver as a module though ( =
-  code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
-  The module will be called wic.o.
-  
 CONFIG_LAPBETHER
 LAPB over Ethernet driver
   This is a driver for a pseudo device (usually called /dev/lapb0)
@@ -2383,6 +2357,75 @@ CONFIG_SDLA
   sdla.o. If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+WAN Router
+CONFIG_WAN_ROUTER
+      Wide Area Networks (WANs), such as X.25, frame relay and leased
+  lines, are used to interconnect Local Area Networks (LANs) over vast
+  distances with data transfer rates significantly higher than those
+  achievable with commonly used asynchronous modem connections.
+  Usually, a quite expensive external device called `WAN router' is
+  needed to connect to WAN.
+      As an alternative, WAN router can be build into Linux kernel.
+  With relatively inexpensive WAN interface cards available on the
+  market, a perfectly usable router can be built for less than half a
+  price of an external router.  If you have one of those cards (with
+  appropriate WAN Link Driver) and wish to use your Linux box as a WAN
+  router, you may say 'Y' to this option.  You will also need a
+  wan-tools package available via FTP (user: anonymous) from
+  ftp.sangoma.com.  Read Documentation/networking/wan-router.txt for
+  more information.
+      WAN router is always built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  For general information about modules read Documentation/modules.txt.
+
+WAN Drivers
+CONFIG_WAN_DRIVERS
+      Say 'Y' to this option if you are planning to use your Linux box
+  as a WAN router ( = device used to interconnect local area networks
+  over wide area communication links, such as leased lines and public
+  data networks, e.g. X.25 and frame relay) and you will be offered a
+  list of WAN drivers currently available.  For more information, read
+  Documentation/networking/wan-router.txt.
+
+Sangoma WANPIPE(tm) multiprotocol cards
+CONFIG_VENDOR_SANGOMA
+      WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com)
+  is a family of intelligent multiprotocol WAN adapter with data
+  transfer rates up to T1 (1.544 Mbps).  They are also known as
+  Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
+  or S508.  If you have one of these cards, say 'Y' to this option.
+      WANPIPE driver is always built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  For general information about modules read Documentation/modules.txt.
+
+Maximum number of cards
+CONFIG_WANPIPE_CARDS
+      Enter number of WANPIPE adapters installed in your machine.  The
+  driver can support up to 8 cards.  You may enter more that you
+  actually have if you plan to add more cards in the future without
+  re-compiling the driver, but remember that in this case you'll waste
+  some kernel memory (about 1K per card).
+
+WANPIPE X.25 support
+CONFIG_WANPIPE_X25
+      Say 'Y' to this option, if you are planning to connect WANPIPE
+  card to an X.25 network.  If you say 'N', the X.25 support will not
+  be included in the driver (saves about 16K of kernel memory).
+
+WANPIPE Frame Relay support
+CONFIG_WANPIPE_FR
+      Say 'Y' to this option, if you are planning to connect WANPIPE
+  card to a frame relay network.  If you say 'N', the frame relay
+  support will not be included in the driver (saves about 16K of
+  kernel memory).
+
+WANPIPE PPP support
+CONFIG_WANPIPE_PPP
+      Say 'Y' to this option, if you are planning to connect WANPIPE
+  card to a leased line using Point-to-Point protocol (PPP).  If you
+  say 'N', the PPP support will not be included in the driver (saves
+  about 16K of kernel memory).
+
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
   This is support for lance ethernet cards on Sun workstations such as
@@ -2659,6 +2702,20 @@ CONFIG_E2100
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+CS89x0 support
+CONFIG_CS89x0
+  Support for CS89x0 chipset based ethernet cards. 
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO as well as
+  drivers/net/depca.c.  If you want to compile this as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. If you plan to use
+  more than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
 DEPCA support
 CONFIG_DEPCA
   If you have a network (ethernet) card of this type, say Y and read
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
new file mode 100644 (file)
index 0000000..e4922c3
--- /dev/null
@@ -0,0 +1,173 @@
+A Brief Overview of the Virtual File System
+===========================================
+       by Benjamin LaHaise (blah@dot.superaje.com)
+
+Noone else seems to be writing this, so here's a quick description of what
+I've learned while writing lofs...
+
+The VFS relatively simple, but it is nice not to have to browse through
+pages of code to determine what is expected when writing a filesystem.
+Hopefully this helps anyone attempting such a feat, as well as clearing up
+a few important points/dependancies.
+
+
+register_filesystem (struct file_system_type *fstype)
+=====================================================
+
+All filesystems are created equal... or at least they start out that way.
+A filesystem, be it in module form, or linked into the kernel, needs to add
+itself to the table of filesystems by calling register_filesystem with an
+initialized file_system_type structure.  Any further functions of the
+filesystem are accessed through the following function tables...
+
+
+struct file_system_type
+=======================
+
+       struct super_block *(*read_super) (struct super_block *sb, void *options, int silent);
+
+               This is the entry point of all filesystems.  If the filesystem succeeds
+               in mounting itself, sb should be returned, otherwise NULL.  options is
+               a pointer to a maximum of PAGE_SIZE-1 bytes of options, typically a zero
+               terminated string passed from mount.  This page is freed after read_super
+               returns, so do not use any pointers into it.
+
+               This routine _must_ set the s_op member of sb to point to a valid
+               super_operations structure.
+
+       const char *name;
+
+               Name points to a string that the system will know the filesystem by.
+
+       int requires_dev;
+
+               Set this flag to 1 if the filesystem requires a block device to be mounted
+               on.
+
+       struct file_system_type * next;
+
+               This field points to the next file_system_type that is present in the system,
+               and should be initialized to NULL.
+
+struct super_operations
+=======================
+
+The super_operations structure is found through the s_op member of the
+super_block structure.
+
+       void (*read_inode) (struct inode *inode);
+       [optional - doesn't quite make sense]
+               read_inode is called by the VFS when iget is called requesting an inode
+               not already present in the inode table.  i_ino is set to the number of the
+               inode requested.
+
+               The i_op member of inode should be set to a valid inode_operations
+               structure.  Typically filesystems have separate inode_operations for
+               directories, files and symlinks.  i_op can be NULL.
+
+       int (*notify_change) (struct inode *, struct iattr *);
+       [optional]
+       void (*write_inode) (struct inode *);
+       [optional]
+
+       int (*put_inode) (struct inode *inode);
+       [optional]
+               put_inode is called by the VFS when the last instance of inode is released
+               with a call to iput.  The only special consideration that should be made
+               is that iget may reuse inode without calling read_inode unless clear_inode
+               is called.  put_inode MUST return 1 if it called clear_inode on the inode,
+               otherwise zero.
+
+       void (*put_super) (struct super_block *);
+       [optional]
+       void (*write_super) (struct super_block *);
+       [optional]
+       void (*statfs) (struct super_block *, struct statfs *, int);
+       [optional]
+       int (*remount_fs) (struct super_block *, int *, char *);
+       [optional]
+
+
+struct inode_operations
+=======================
+
+       struct file_operations * default_file_ops;
+       [mandatory]
+               All inode_operations structures must have default_file_ops pointing to
+               a valid file_operations structure.
+
+       int (*create) (struct inode *,const char *,int,int,struct inode **);
+       [optional]
+
+       int (*lookup) (struct inode *dir, const char *name, int len, struct inode **result);
+       [optional]
+               lookup is called when the VFS wishes to have the filesystem resolve a name
+               into an inode.  Dir is a directory on the filesystem that [hopefully] contains
+               the zero terminated string name (length len).  A return value of zero indicates
+               that there is a valid inode stored in *result.
+
+***            Note: lofs assumes that any filesystem returns an inode within the filesystem
+               for all directory inodes.  Therefore, __iget(sb,ino,0) should be used to fetch
+               the inode in a filesystem's lookup routine.
+
+       int (*link) (struct inode *,struct inode *,const char *,int);
+       [optional]
+       int (*unlink) (struct inode *,const char *,int);
+       [optional]
+       int (*symlink) (struct inode *,const char *,int,const char *);
+       [optional]
+       int (*mkdir) (struct inode *,const char *,int,int);
+       [optional]
+       int (*rmdir) (struct inode *,const char *,int);
+       [optional]
+       int (*mknod) (struct inode *,const char *,int,int,int);
+       [optional]
+       int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int);
+       [optional]
+
+       int (*readlink) (struct inode *inode, char *buf, int len);
+       [optional]
+               readlink is called by the VFS to read the contents of a symbolic link.
+               inode is an inode that meets the S_ISLNK test, and buf points to a buffer
+               of len bytes.
+
+       int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
+       [optional]
+               The follow_link function is only nescessary if a filesystem uses a really
+               twisted form of symbolic links - namely if the symbolic link comes from a
+               foriegn filesystem that makes no sense....
+               I threw this one out - too much redundant code!
+
+       int (*readpage) (struct inode *, struct page *);        [optional]
+       int (*writepage) (struct inode *, struct page *);       [mandatory with readpage]
+
+               In order for files to be mmap'd, readpage and writepage are required.
+               A filesystem can use generic_readpage/writepage if it supports the bmap
+               function.  Otherwise, a custom version must be written. 
+
+       int (*bmap) (struct inode *,int);
+       [optional]
+       void (*truncate) (struct inode *);
+       [optional]
+       int (*permission) (struct inode *, int);
+       [optional]
+       int (*smap) (struct inode *,int);
+       [optional]
+
+struct file_operations
+======================
+
+       int (*lseek) (struct inode *, struct file *, off_t, int);
+       int (*read) (struct inode *, struct file *, char *, int);
+       int (*write) (struct inode *, struct file *, const char *, int);
+       int (*readdir) (struct inode *, struct file *, void *, filldir_t);
+       unsigned int (*poll) (struct file *, poll_table *);
+       int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+       int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
+       int (*open) (struct inode *, struct file *);
+       void (*release) (struct inode *, struct file *);
+       int (*fsync) (struct inode *, struct file *);
+       int (*fasync) (struct inode *, struct file *, int);
+       int (*check_media_change) (kdev_t dev);
+       int (*revalidate) (kdev_t dev);
+
index 9168db466e18c3dd83aab126fbfb75470a71b496..52f399775555c3a1708e47569c4d7c76980bc240 100644 (file)
@@ -81,6 +81,7 @@ Code  Seq#    Include File            Comments
 'T'    all     linux/soundcard.h       conflict!
 'T'    all     asm-i386/ioctls.h       conflict!
 'V'    all     linux/vt.h
+'W'    00-1F   linux/router.h          conflict [Please reallocate]
 'W'    00-1F   linux/watchdog.h
 'W'    20-27   linux/octal-relay.h     in development
 'W'    28-2F   linux/iso16-relay.h     in development
index 1c28f155fac5026ab624cd845ca8ac869506996a..c8ea597f4ae976803608be1ab2ca1b6693711481 100644 (file)
@@ -54,6 +54,7 @@ SCC_MAGIC           0x8530      struct scc_channel   include/linux/scc.h
 ISDN_ASYNC_MAGIC    0x49344C01  modem_info           include/linux/isdn.h
 ISDN_NET_MAGIC      0x49344C02  isdn_net_ndev        include/linux/isdn.h
 STLI_BOARDMAGIC     0x4bc6c825  stlibrd_t            include/linux/istallion.h
+ROUTER_MAGIC        0x524d4157  wanlink_t            include/linux/router.h
 STLI_PORTMAGIC      0xe671c7a1  stliport_t           include/linux/istallion.h
 STL_PANELMAGIC      0x7ef621a1  stlpanel_t           include/linux/stallion.h
 STL_BOARDMAGIC      0xa2267f52  stlbrd_t             include/linux/stallion.h
index de4382f0d0b87159eeb782c093be7bbd1b4150f0..6bc7c31ace8b1cd185ecc89cb1a0469aac55f4a5 100644 (file)
@@ -30,6 +30,8 @@ tulip.txt
        - info on using DEC 21040/21041/21140 based PCI ethernet cards.
 vortex.txt
        - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards.
+wan-router.txt
+       - Wan router documentation
 x25.txt
        - general info on X.25 development.
 x25-iface.txt
index bcce0ff6babc1f94fbf059e43c3bc339d72e9412..e4519ad3a2bf46c483d0d31dcf9d8ba9261d133a 100644 (file)
@@ -12,7 +12,7 @@ No.   Name                    Meaning                         Default
 1      IP Default Mode         0=DG 1=VC                       0
 2      AX.25 Default Mode      0=Normal 1=Extended             0
 3      Allow Vanilla Connects  0=No 1=Yes                      1
-4      Backoff                 0=Linear 1=Exponential          1
+4      Backoff                 0=None 1=Linear 2=Exponential   1
 5      Connected Mode          0=No 1=Yes                      1
 6      Standard Window         1  <= N <= 7                    2
 7      Extended Window         1  <= N <= 63                   32
diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt
new file mode 100644 (file)
index 0000000..ab89d64
--- /dev/null
@@ -0,0 +1,651 @@
+CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
+Linux Network Interface Driver ver. 1.02
+===============================================================================
+
+TABLE OF CONTENTS
+
+1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
+    1.1 Product Overview 
+    1.2 Driver Description
+       1.2.1 Driver Name
+       1.2.2 File in the Driver Package
+    1.3 System Requirements
+    1.4 Licensing Information
+
+2.0 ADAPTER INSTALLATION and CONFIGURATION
+    2.1 CS8900-based Adapter Configuration
+    2.2 CS8920-based Adapter Configuration 
+
+3.0 LOADING THE DRIVER AS A MODULE
+
+4.0 COMPILING THE DRIVER
+    4.1 Compiling the Driver As a Loadable Module
+    4.2 Compiling the Driver Into the Kernel
+    4.3 Compiling the Driver for a Linux v1.2.13 Kernel
+
+5.0 TESTING AND TROUBLESHOOTING
+    5.1 Known Defects and Limitations
+    5.2 Testing the Adapter
+        5.2.1 Diagnostic Self-Test
+        5.2.2 Diagnostic Network Test
+    5.3 Using the Adapter's LEDs
+    5.4 Resolving I/O Conflicts
+
+6.0 TECHNICAL SUPPORT
+    6.1 Contacting Crystal's Technical Support
+    6.2 Information Required Before Contacting Technical Support
+    6.3 Obtaining the Latest Driver Version
+        6.3.1 Crystal's Web Site
+        6.3.2 Crystal's Bulletin Board Service
+
+
+8.3 OBTAINING THE LATEST DRIVER VERSION
+
+You can obtain the latest CS89XX drivers and support software from Crystal's 
+BBS or Web site.
+
+
+8.3.1 CRYSTAL'S WEB SITE
+
+Crystal Semiconductor maintains a web page at http://www.crystal.com with the
+the latest drivers and technical publications.
+
+
+8.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
+
+
+
+
+1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
+===============================================================================
+
+
+1.1 PRODUCT OVERVIEW
+
+The CS8900-based ISA Ethernet Adapters from Crystal Semiconductor follow 
+IEEE 802.3 standards and support half or full-duplex operation in ISA bus 
+computers on 10 Mbps Ethernet networks.  The adapters are designed for 
+operation in 16-bit ISA or EISA bus expansion slots and are available in 
+10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5
+or fiber networks).  
+
+CS8920-based adapters are similar to the CS8900-based adapter with additional 
+features for Plug and Play (PnP) support and Wakeup Frame recognition.  As 
+such, the configuration procedures differ somewhat between the two types of 
+adapters.  Refer to the "Adapter Configuration" section for details on 
+configuring both types of adapters.
+
+
+1.2 DRIVER DESCRIPTION
+
+The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux v1.2.13 
+and v2.0 (or greater) kernels.  It can be compiled directly into the kernel or 
+loaded at run-time as a device driver module.
+
+1.2.1 Driver Name: cs89x0
+
+1.2.2 Files in the Driver Archive:
+
+  readme.txt  - this file
+  release.txt - known defects and modifcation log
+  cs89x0.c    - driver C code
+  cs89x0.h    - driver header file
+  cs89x0.o    - pre-compiled module (for v2.0 kernel)
+
+
+
+1.3 SYSTEM REQUIREMENTS
+
+The following hardware is required:
+
+   * Crystal LAN (CS8900/20-based) Ethernet ISA Adapter   
+
+   * IBM or IBM-compatible PC with:
+     * An 80386 or higher processor
+     * 16 bytes of contiguous IO space available between 210h - 370h
+     * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920).
+
+   * Appropriate cable (and connector for AUI, 10BASE-2) for your network
+     topology.
+
+The following software is required:
+
+   * LINUX kernel version 1.2.13 or 2.X
+
+   * CS8900/20 Setup Utility (DOS-based)
+
+   * LINUX kernel sources for your kernel (if compiling into kernel)
+
+   * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel 
+     or a module)   
+
+
+
+1.4 LICENSING INFORMATION
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, version 1.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+more details.
+
+For a full copy of the GNU General Public License, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+
+2.0 ADAPTER INSTALLATION and CONFIGURATION
+===============================================================================
+
+Both the CS8900 and CS8920-based adapters can be configured using parameters 
+stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup 
+Utility if you want to change the adapter's configuration in EEPROM.  
+
+When loading the driver as a module, you can specify many of the adapter's 
+configuration parameters on the command-line to override the EEPROM's settings 
+or for interface configuration when an EEPROM is not used. (CS8920-based 
+adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE.
+
+Since the CS8900/20 Setup Utility is a DOS-based application, you must install 
+and configure the adapter in a DOS-based system using the CS8900/20 Setup 
+Utility before installation in the target LINUX system.  (Not required if 
+installing a CS8900-based adapter and the default configuration is acceptable.)
+     
+
+2.1 CS8900-BASED ADAPTER CONFIGURATION
+
+CS8900-based adapters shipped from Crystal Semiconductor have been configured 
+with the following "default" settings:
+
+  Operation Mode:      Memory Mode
+  IRQ:                 10
+  Base I/O Address:    300
+  Memory Base Address: D0000
+  Optimization:               DOS Client
+  Transmission Mode:   Half-duplex
+  BootProm:            None
+  Media Type:         Autodetect (3-media cards) or 
+                       10BASE-T (10BASE-T only adapter)
+
+You should only change the default configuration settings if conflicts with 
+another adapter exists. To change the adapter's configuration, run the 
+CS8900/20 Setup Utility. 
+
+
+2.2 CS8920-BASED ADAPTER CONFIGURATION
+
+CS8920-based adapters are shipped from Crystal Semiconductor configured as Plug
+and Play (PnP) enabled.  However, since Linux is not currently a PnP compatible 
+operating system, you must install the CS8920 adapter in a DOS-based PC and 
+run the CS8900/20 Setup Utility to disable PnP and configure the adapter before
+installation in the target Linux system.  Failure to do this will leave the 
+adapter inactive and the driver will be unable to communicate with the
+adapter.
+
+
+        **************************************************************** 
+        *                    CS8920-BASED ADAPTERS:                    *
+        *                                                              * 
+        * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT.  * 
+        * SCO UNIX IS NOT A PnP OPERATING SYSTEM. THEREFORE, YOU MUST  *
+        * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND   *
+        * TO ACTIVATE THE ADAPTER.                                     *
+        ****************************************************************
+
+
+
+
+3.0 LOADING THE DRIVER AS A MODULE
+===============================================================================
+
+If the driver is compiled as a loadable module, you can load the driver module
+with the 'insmod' command.  Many of the adapter's configuration parameters can 
+be specified as command-line arguments to the load command.  This facility 
+provides a means to override the EEPROM's settings or for interface 
+configuration when an EEPROM is not used.
+
+Example:
+
+    insmod cs89x0.o io=0x200 irq=0xA media=aui
+
+This exmaple loads the module and configures the adapter to use an IO port base
+address of 200h, interrupt 10, and use the AUI media connection.  The following
+configuration options are available on the command line:
+
+* io=###              - specify IO address (200h-360h)
+* irq=##              - specify interrupt level
+* mmode=#####         - specify memory base address
+* dma=#               - specify dma channel
+* media=rj45          - specify media type
+   or media=2
+   or media=aui
+   or medai=auto
+* duplex=f            - specify forced half/full/autonegotiate duplex
+   or duplex=h
+   or duplex=auto
+* debug=#             - debug level
+
+NOTES:
+* If an EEPROM is present, any specified command-line parameter will override
+the corresponding configuration value stored in EEPROM.
+
+* If no "io" or "mmode" parameter is specified on the command-line, the driver
+will scan for the adapter.  When scanning, the driver only reads I/O ports.  
+This sometimes is not sufficient, (e.g. after a warm boot).  If you wish to 
+allow the driver to perform a more aggressive scan (one write to the IO base 
+addresses to reset the data port pointer) you can specify an I/O address with 
+an address value one greater than the configured address.  Example, to scan for
+an adapter located at IO base 0x300, specify an IO address of 0x301.  Only 
+ports between 200h and 360h at 20h intervals are scanned.  
+
+* The "duplex=auto" parameter is only supported for the CS8920.
+
+* The minimum command-line configuration required if an EEPROM is not present
+is:
+
+  * io or mmode base address
+  * irq 
+  * media type (no autodetect)
+
+The following addtional parameters are CS89XX defaults (values used with no 
+EEPROM or command-line argument).
+
+  * DMA Burst = enabled
+  * IOCHRDY Enabled = enabled
+  * UseSA = enabled
+  * CS8900 defaults to half-duplex if not specified on command-line
+  * CS8920 defaults to autoneg if not specified on command-line
+  * Use reset defaults for other config parameters
+
+* You can use ifconfig to set the adapter's Ethernet address.
+
+
+
+
+4.0 COMPILING THE DRIVER
+===============================================================================
+
+The cs89x0 driver can be compiled directly into the kernel or compiled into
+a loadable device driver module.
+
+NOTE: This part of the description relates to adding the driver to a kernel
+not containing the cs89x0 driver. This kernel already contains it.
+
+4.1 COMPILING THE DRIVER AS A LOADABLE MODULE
+
+To compile the driver into a loadable module, use the following command 
+(single command line, without quotes):
+
+"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall 
+-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS 
+-c cs89x0.c"
+
+
+4.2 COMPILING THE DRIVER INTO THE KERNEL
+
+To compile the driver directly into the kernel requires editing four 
+configuration files, copying the source file to the /linux/drivers/net
+directory and then running the make utility to rebuild the kernel.
+
+1. Edit the following configuration files by adding the statements as
+indicated.  (When possible, try to locate the added text to the section of the
+file containing similar statements).
+
+a.) In /usr/src/linux/drivers/net/CONFIG, add
+
+CS89x0_OPTS   =
+
+Example:
+
+ WD_OPTS       = #-DWD_SHMEM=0xDD000
+ EL2_OPTS      = #-DEL2_AUI
+ CS89x0_OPTS   =                
+ NE_OPTS       =
+ HP_OPTS       =
+ PLIP_OPTS     =
+
+
+b.) In /usr/src/linux/drivers/net/Config.in, add:
+
+tristate 'CS89x0 support' CONFIG_CS89x0
+
+Example:
+
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
+     fi
+
+     tristate 'CS89x0 support' CONFIG_CS89x0
+
+     tristate 'NE2000/NE1000 support' CONFIG_NE2000
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       tristate 'NI5210 support' CONFIG_NI52
+
+
+c.) In /usr/src/linux/drivers/net/Makefile, add the following lines: 
+
+ifeq ($(CONFIG_CS89x0),y)
+L_OBJS += cs89x0.o
+else
+  ifeq ($(CONFIG_CS89x0),m)
+  M_OBJS += cs89x0.o
+  endif
+endif
+
+
+d.) In /linux/drivers/net/Space.c file, add the line:
+
+extern int cs89x0_probe(struct device *dev);
+
+
+Example:
+
+ extern int ultra_probe(struct device *dev);
+ extern int wd_probe(struct device *dev);
+ extern int el2_probe(struct device *dev);
+
+ extern int cs89x0_probe(struct device *dev);
+
+ extern int ne_probe(struct device *dev);
+ extern int hp_probe(struct device *dev);
+ extern int hp_plus_probe(struct device *dev);
+
+
+Also add:
+
+ #ifdef CONFIG_CS89x0
+       && cs89x0_probe(dev)
+ #endif
+
+
+2.) Copy the driver source files (cs89x0.c and cs89x0.h) and this README file 
+into the /usr/src/linux/drivers/net directory.
+
+
+3.) Run 'make config' followed by 'make dep' and finally 'make' to rebuild 
+the kernel. 
+
+
+4.3 COMPILING THE DRIVER FOR A LINUX v1.2.13 KERNEL
+
+To compile the driver for Linux v1.2.13 (into the kernel or as a module), 
+change the "SUPPORTS" define at the beginning of the cs89x0.c file.  
+Example:
+
+#define SUPPORTS_1_2_13 1   /* supports Linux kernel v1.2.13 */
+   or
+#define SUPPORTS_1_2_13 0   /* supports Linux kernel v2.0 (default) */
+
+
+
+5.0 TESTING AND TROUBLESHOOTING
+===============================================================================
+
+5.1 KNOWN DEFECTS and LIMITATIONS
+
+Refer to the RELEASE.TXT file distributed as part of this archive for a list of 
+know defects, driver limitations, and work arounds.
+
+
+5.2 TESTING THE ADAPTER
+
+Once the adapter has been installed and configured, the diagnostic option of 
+the CS8900/20 Setup Utility can be used to test the functionality of the 
+adapter and its network connection.  Use the diagnostics 'Self Test' option to
+test the functionality of the adapter with the hardware configuration you have
+assigned. You can use the diagnostics 'Network Test' to test the ability of the
+adapter to communicate across the Ethernet with another PC equipped with a 
+CS8900/20-based adapter card (it must also be running the CS8900/20 Setup 
+Utility).
+
+         NOTE: The Setup Utility's diagnostics are designed to run in a
+         DOS-only operating system environment.  DO NOT run the diagnostics 
+         from a DOS or command prompt session under Windows 95, Windows NT, 
+         OS/2, or other operating system.
+
+       [AC - Question : Do they work in DOSEMU ?]
+
+To run the diagnostics tests on the CS8900/20 adapter:
+
+   1.) Boot DOS on the PC and start the CS8900/20 Setup Utility.
+
+   2.) The adapter's current configuration is displayed.  Hit the ENTER key to
+       get to the main menu.
+
+   4.) Select 'Diagnostics' (ALT-G) from the main menu.  
+       * Select 'Self-Test' to test the adapter's basic functionality.
+       * Select 'Network Test' to test the network connection and cabling.
+
+
+5.2.1 DIAGNOSTIC SELF-TEST
+
+The diagnostic self-test checks the adapter's basic functionality as well as 
+its ability to communicate across the ISA bus based on the system resources 
+assigned during hardware configuration.  The following tests are performed:
+
+   * IO Register Read/Write Test
+     The IO Register Read/Write test insures that the CS8900/20 can be 
+     accessed in IO mode, and that the IO base address is correct.
+
+   * Shared Memory Test
+     The Shared Memory test insures the CS8900/20 can be accessed in memory 
+     mode and that the range of memory addresses assigned does not conflict 
+     with other devices in the system.
+
+   * Interrupt Test
+     The Interrupt test insures there are no conflicts with the assigned IRQ
+     signal.
+
+   * EEPROM Test
+     The EEPROM test insures the EEPROM can be read.
+
+   * Chip RAM Test
+     The Chip RAM test insures the 4K of memory internal to the CS8900/20 is
+     working properly.
+
+   * Internal Loop-back Test
+     The Internal Loop Back test insures the adapter's transmitter and 
+     receiver are operating properly.  If this test fails, make sure the 
+     adapter's cable is connected to the network (check for LED activity for 
+     example).
+
+   * Boot PROM Test
+     The Boot PROM  test insures the Boot PROM is present, and can be read.
+     Failure indicates the Boot PROM  was not successfully read due to a
+     hardware problem or due to a conflicts on the Boot PROM address
+     assignment. (Test only applies if the adapter is configured to use the
+     Boot PROM option.)
+
+Failure of a test item indicates a possible system resource conflict with 
+another device on the ISA bus.  In this case, you should use the Manual Setup 
+option to reconfigure the adapter by selecting a different value for the system
+resource that failed.
+
+
+5.2.2 DIAGNOSTIC NETWORK TEST
+
+The Diagnostic Network Test verifies a working network connection by 
+transferring data between two CS8900/20 adapters installed in different PCs 
+on the same network. (Note: the diagnostic network test should not be run 
+between two nodes across a router.) 
+
+This test requires that each of the two PCs have a CS8900/20-based adapter
+installed and have the CS8900/20 Setup Utility running.  The first PC is 
+configured as a Responder and the other PC is configured as an Initiator.  
+Once the Initiator is started, it sends data frames to the Responder which 
+returns the frames to the Initiator.
+
+The total number of frames received and transmitted are displayed on the 
+Initiator's display, along with a count of the number of frames received and 
+transmitted OK or in error.  The test can be terminated anytime by the user at 
+either PC.
+
+To setup the Diagnostic Network Test:
+
+    1.) Select a PC with a CS8900/20-based adapter and a known working network
+        connection to act as the Responder.  Run the CS8900/20 Setup Utility 
+        and select 'Diagnostics -> Network Test -> Responder' from the main 
+        menu.  Hit ENTER to start the Responder.
+
+    2.) Return to the PC with the CS8900/20-based adapter you want to test and
+        start the CS8900/20 Setup Utility. 
+
+    3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'.
+        Hit ENTER to start the test.
+You may stop the test on the Initiator at any time while allowing the Responder
+to continue running.  In this manner, you can move to additional PCs and test 
+them by starting the Initiator on another PC without having to stop/start the 
+Responder.
+
+
+5.3 USING THE ADAPTER'S LEDs
+
+The 2 and 3-media adapters have two LEDs visible on the back end of the board 
+located near the 10Base-T connector.  
+
+Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T 
+connection.  (Only applies to 10Base-T.  The green LED has no significance for
+a 10Base-2 or AUI connection.)
+
+TX/RX LED: The yellow LED lights briefly each time the adapter transmits or 
+receives data. (The yellow LED will appear to "flicker" on a typical network.)
+
+
+5.4 RESOLVING I/O CONFLICTS
+
+An IO conflict occurs when two or more adapter use the same ISA resource (IO 
+address, memory address or IRQ).  You can usually detect an IO conflict in one 
+of four ways after installing and or configuring the CS8900/20-based adapter:
+
+    1.) The system does not boot properly (or at all).
+
+    2.) The driver can not communicate with the adapter, reporting an "Adapter
+        not found" error message.
+
+    3.) You cannot connect to the network or the driver will not load.
+
+    4.) If you have configured the adapter to run in memory mode but the driver
+        reports it is using IO mode when loading, this is an indication of a
+        memory address conflict.
+
+If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a 
+diagnostic self-test.  Normally, the ISA resource in conflict will fail the 
+self-test.  If so, reconfigure the adapter selecting another choice for the 
+resource in conflict.  Run the diagnostics again to check for further IO 
+conflicts.
+
+In some cases, such as when the PC will not boot, it may be necessary to remove
+the adapter and reconfigure it by installing it in another PC to run the 
+CS8900/20 Setup Utility.  Once reinstalled in the target system, run the 
+diagnostics self-test to ensure the new configuration is free of conflicts 
+before loading the driver again.
+
+When manually configuring the adapter, keep in mind the typical ISA system 
+resource usage as indicated in the tables below.
+
+I/O Address            Device                        IRQ      Device
+-----------            --------                      ---      --------
+ 200-20F               Game I/O adapter               3       COM2, Bus Mouse
+ 230-23F               Bus Mouse                      4       COM1
+ 270-27F               LPT3: third parallel port      5       LPT2
+ 2F0-2FF               COM2: second serial port       6       Floppy Disk controller
+ 320-32F               Fixed disk controller          7       LPT1
+                                              8       Real-time Clock
+                                               9       EGA/VGA display adapter    
+                                              12       Mouse (PS/2)                              
+Memory Address  Device                        13       Math Coprocessor
+--------------  ---------------------         14       Hard Disk controller
+A000-BFFF      EGA Graphics Adpater
+A000-C7FF      VGA Graphics Adpater
+B000-BFFF      Mono Graphics Adapter
+B800-BFFF      Color Graphics Adapter
+E000-FFFF      AT BIOS
+
+
+
+
+6.0 TECHNICAL SUPPORT
+===============================================================================
+
+6.1 CONTACTING CRYSTAL'S TECHNICAL SUPPORT
+
+Crystal's CS89XX Technical Application Support can be reached at:
+
+Telephone  :(800) 888-5016 (from inside U.S. and Canada)
+           :(512) 442-7555 (from outside the U.S. and Canada)
+Fax       :(512) 912-3871
+Email     :ethernet@crystal.cirrus.com
+WWW        :http://www.crystal.com
+
+
+6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT
+
+Before contacting Crystal for technical support, be prepared to provide as much
+of the following information as possible. 
+
+1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.)
+
+2.) Adapter configuration
+
+    * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel
+    * Plug and Play enabled/disabled (CS8920-based adapters only)
+    * Configured for media auto-detect or specific media type (which type).    
+
+3.) PC System's Configuration
+
+    * Plug and Play system (yes/no)
+    * BIOS (make and version)
+    * System make and model
+    * CPU (type and speed)
+    * System RAM
+    * SCSI Adapter
+
+4.) Software
+
+    * CS89XX driver and version
+    * Your network operating system and version
+    * Your system's OS version 
+    * Version of all protocol support files
+
+5.) Any Error Message displayed.
+
+
+
+6.3 OBTAINING THE LATEST DRIVER VERSION
+
+You can obtain the latest CS89XX drivers and support software from Crystal's 
+BBS or Web site.  You can also contact Crystal's Technical Support (email:
+ethernet@crystal.cirrus.com) and request that you be registered for automatic 
+software-update notification.
+
+
+6.3.1 CRYSTAL'S WEB SITE
+
+Crystal Semiconductor maintains a web page at http://www.crystal.com with the
+the latest drivers and technical publications.
+
+
+6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
+
+Access to the BBS is available 24 hours a day, seven days a week. Baud 
+rates from 300K to 14.4K are supported as well as most common file transfer 
+protocols.  
+
+To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, 
+and no parity.  Dial (512) 441-3265 and press <ENTER> after connection is made.
+Login using your account name and password.  (If you do not have an account, 
+you may login as "GUEST".  No password is required for the Guest account.)
+
+From the main system menu, select the "Enter Public File Area" menu option.  
+From the Public File Area menu, select the "LAN (Local Area Network)" file
+area.  A list of the latest drivers and support utilities available for the
+CS89XX ISA Ethernet adapter will be presented along with the option to download
+the file(s) of your choice.
+
+
diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt
new file mode 100644 (file)
index 0000000..f95bc9f
--- /dev/null
@@ -0,0 +1,130 @@
+------------------------------------------------------------------------------
+WAN Router for Linux Operating System
+------------------------------------------------------------------------------
+Version 1.0.0
+December 31, 1996
+Author: Gene Kozin <genek@compuserve.com>
+Copyright (c) 1995-1996 Sangoma Technologies Inc.
+------------------------------------------------------------------------------
+
+INTRODUCTION
+
+Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs)
+and/or stand-alone hosts over vast distances with data transfer rates
+significantly higher than those achievable with commonly used dial-up
+connections.
+
+Usually an external device called `WAN router' sitting on your local network
+or connected to your machine's serial port provides physical connection to
+WAN.  Although router's job may be as simple as taking your local network
+traffic, converting it to WAN format and piping it through the WAN link, these
+devices are notoriously expensive, with prices as much as 2 - 5 times higher
+then the price of a typical PC box.
+
+Alternatively, considering robustness and multitasking capabilities of Linux,
+an internal router can be build (most routers use some sort of stripped down
+Unix-like operating system anyway).  With number of relatively inexpensive WAN
+interface cards available on the market, a perfectly usable router can be
+built for less than half a price of an external router.  Yet a Linux box
+acting as a router can still be used for other purposes, such as firewalling,
+running FTP, WWW or DNS server, etc.
+
+This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux
+operating system and provides generic hardware-independent services for such
+drivers.  Why existing Linux network device interface can not be used for
+this purpose?  Well, it can.  However, there are few key differences between
+typical network interface (i.e. ethernet) and WAN link.
+
+Many WAN protocols, such as X.25 and frame relay, allow for multiple logical
+connections (known as `virtual circuits' in X.25 terminology) over a single
+physical link.  Each such virtual circuit may (and almost always does) lead
+to diffrent geographical location and, therefore, different network.  As a
+result, it is the virtual circuit, not the physical link, that represents a
+route and, therefore, a network interface in Linux terms.
+
+To further complicate things, virtual cuircits are usually volatile in nature
+(excluding so called `permanent' virtual circuits or PVCs).  With almost no
+time required to set up and tear down virtual circuit, it is highly desirable
+to implement on-demand connections in order to minimize network charges.  So
+unlike typical network driver, the WAN driver must be able to handle multiple
+network interfaces and cope with multiple virtual circuits come into existance
+and go away dynamically.
+Last, but not least, WAN configuration is much more complex than that of say
+ethernet and may well amount to several dozens of parameters.  Some of them
+are "link-wide"  while others are virtual circuit-specific.  The same holds
+true for WAN statistics which is by far more extensive and extremely useful
+when troubleshooting WAN connections.  Extending ifconfig utility to suite
+these needs may be possible, but does not seem quite reasonable.  Therefore, a
+WAN configuration utility and corresponding application programmer's interface
+is needed for this purpose.
+
+Most of these problems are taken care of by this module.  It's goal is to
+provide user with more-or-less standard look and feel for all WAN devices and
+assist WAN device driver writer by providing common services, such as:
+
+ o User-level interface via /proc filesystem
+ o Centralized configuration
+ o Device managenent (setup, shutdown, etc.)
+ o Network interface management (dynamic creation/destruction)
+ o Protocol encapsulation/decapsulation
+
+To ba able to use Linux WAN Router you will also need a WAN Tools package
+available from
+
+       ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz
+
+For technical questions and/or comments regarding this product please e-mail
+to genek@compuserve.com or dm@sangoma.com.
+
+
+
+COPYRIGHT AND LICENSING INFORMATION
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+
+
+
+KNOWN BUGS AND LIMITATIONS
+
+/proc user interface is not complete yet.
+
+
+
+ACKNOLEGEMENTS
+
+This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
+by Sangoma Technologies Inc. for Linux 1.2.x.  Release of Linux 2.0 in summer
+1996 commanded adequate changes to the WANPIPE code to take full advantage of
+new Linux features.  Instead of continuing developing proprietory interface
+specific to Sangoma WAN cards, we decided to put all hardware-independent code
+into a separate module and define two levels of interfaces - one for user-
+level applications and another for kernel-level WAN drivers.
+
+Many usefull ideas concerning hardware-independent interface implementation
+were given by Mike McLagan <mike.mclagan@linux.org> and his implementation
+of the Frame Relay router and drivers for Sangoma cards (dlci/sdla).
+
+Special thanks to all the WANPIPE users who performed field-testing, reported
+bugs and made valuable comments and suggestions that help us to improve this
+product.
+
+
+
+REVISION HISTORY
+
+1.0.0   December 31, 1996
+--------------------------
+ o Initial version.
+
+>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
diff --git a/Documentation/serial-console.txt b/Documentation/serial-console.txt
new file mode 100644 (file)
index 0000000..22f02e2
--- /dev/null
@@ -0,0 +1,78 @@
+                       Linux Serial Console
+
+These examples are valid if you want to use /dev/ttyS1 (COM2)
+as the serial console. Replace as needed.
+
+1. Tell LILO to use the serial port.
+   In lilo.conf (global section): 
+
+   serial  = 1,9600n8 (ttyS1, 9600 bd, no parity, 8 bits)
+
+2. Adjust to kernel flags for the new kernel,
+   again in lilo.conf (kernel section)
+
+   append = "console=1,9600,n8" 
+
+   (Note the extra comma needed if you want to supply parity/framing 
+   information.)
+
+3. Link /dev/console to the serial port.
+
+   Your probably want to save your old /dev/console (the "master" virtual
+   console). Check if it is a symbolic link first. If not, `mv' it to
+   `/dev/tty0':
+
+   ls -l /dev/console
+   mv /dev/console /dev/tty0
+
+   Now link the serial port you are going to use as the console to
+   /dev/console, for example ttyS1:
+
+   ln -s /dev/ttyS1 /dev/console
+
+   On some systems you might want to edit your bootup scripts to make sure
+   they don't reset this arrangement on boot. (On Debian, check
+   /etc/rc.boot/console and /etc/default/console). You probably also want
+   to put a getty on either /dev/console or /dev/ttyS1.
+
+4. Init and /dev/console.
+   Sysvinit will open /dev/console on boot. If this does not point
+   to the serial console device, the startup messages will be printed
+   to the wrong device. The kernel also passes the environment variable
+   "CONSOLE" to the init program. sysvinit-2.64 reckognizes this, and
+   opens that device instead. Boot scripts as mentioned in (3) can
+   also check this variable to see what device the system console is.
+   If CONSOLE is not set you can assume the console is /dev/tty0.
+
+   Sysvinit remembers its stty settings in a file in /etc, called
+   `/etc/ioctl.save'. REMOVE THIS FILE before using the serial
+   console for the first time, because otherwise init will probably
+   set the baudrate to 38400 (bausdrate of the virtual console).
+
+5. /dev/console and X
+   Programs that want to do something with the virtual console usually
+   open /dev/console. XF86 does this, and probably SVGALIB as well.
+   IMO this is wrong; they should open /dev/tty0.
+   I have binary patched /usr/bin/X11/XF86_SVGA to use "tty0"
+   instead of "console".
+
+6. Notes.
+
+   If you compile the next little program, you will be able
+   to really "halt" the system. It will enter a little
+   monitor :)
+
+   main() { reboot(0xfee1dead, 672274793, 0xCDEF0123); }
+
+   This is just a call to the new "halt" function that later
+   kernels have. This is included the "halt" command of
+   the recent sysvinit versions.
+
+   The monitor will also be entered at a kernel panic, or
+   when you press "break". That last function does not
+   work at the moment I think, but it would be useful for
+   kernel debugging.  You don't have alt-scrollock on a serial
+   console to find out the current EIP...
+
+Miquel van Smoorenburg <miquels@cistron.nl>, 21-Jun-1996
+Stephen C. Tweedie <sct@dcs.ed.ac.uk>, 23-Dec-1996
diff --git a/Documentation/smp b/Documentation/smp
new file mode 100644 (file)
index 0000000..a0c4ab7
--- /dev/null
@@ -0,0 +1,23 @@
+To set up SMP
+
+Edit linux/Makefile and uncomment SMP=1, then compile and install
+as usual.
+
+If you are using LILO, it is handy to have both SMP and non-SMP
+kernel images on hand. Edit /etc/lilo.conf to create an entry
+for another kernel image called "linux-smp" or something.
+
+The next time you compile the kernel, when running a SMP kernel,
+edit linux/Makefile and change "MAKE=make" "MAKE=make -jN"
+(where N = number of CPU + 1, or if you have tons of memory/swap
+ you can just use "-j" without a number). Feel free to experiment
+with this one.
+
+Of course you should time how long each build takes :-)
+Example:
+   make config
+   time -v sh -c 'make dep ; make clean install modules modules_install'
+
+If you are using some Compaq MP compliant machines you will need to set
+the operating system in the BIOS settings to "Unixware" - don't ask me
+why Compaq's dont work otherwise.
index 1a398dc4b4c6d25dd8dbe347475f84a8155456ad..caf7adf244b8466c864d2d04ff3ba0aa50d46ef2 100644 (file)
@@ -87,6 +87,8 @@ Industrial Computer Source
 9950 Barnes Canyon Road 
 San Diego, CA     
 
+http://www.industry.net/indcompsrc
+
 and please mention Linux when enquiring.
 
 For full information about the PCWD cards see the pcwd-watchdog.txt document.
index 6b523a9b9c752ee59552d99ea6514f3072dc8f36..e18c29a0b20d212756c9c66d5b59a7116618475a 100644 (file)
@@ -277,6 +277,13 @@ M: cheshire@cs.stanford.edu
 W:     http://mosquitonet.Stanford.EDU/strip.html
 S:     Maintained
 
+WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP)
+P:     Gene Kozin
+M:     genek@compuserve.com
+M:     dm@sangoma.com
+W:     http://www.sangoma.com
+S:     Supported
+
 SMB FILESYSTEM:
 P:     Volker Lendecke
 M:     lendecke@namu01.Num.Math.Uni-Goettingen.de
index 542627995d27595cab37b0152e1c62f21b72602a..ccc0309417c097c2e1bf3c447d970064a86f11b2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 24
+SUBLEVEL = 25
 
 ARCH = i386
 
index a85071b7134f4a71f2b383710d8265001469c1c9..16d7474d1f64e869f08d827298fbf1844b2ca3aa 100644 (file)
@@ -24,6 +24,7 @@
  * within the United States, $35 abroad.
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
@@ -50,7 +51,6 @@ asmlinkage int sys_pciconfig_write()
 
 #else /* CONFIG_PCI */
 
-#include <linux/kernel.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/malloc.h>
index 7fd0f641720816ddc0b50ad38333093c74c8d918..eb4ce5cbd745115592f4a0e21848bff80165d288 100644 (file)
@@ -426,13 +426,13 @@ static inline unsigned long s_mem_to_reg (unsigned long s_mem)
        exp = (exp_msb << 10) | exp_low;        /* common case */
        if (exp_msb) {
                if (exp_low == 0x7f) {
-                       exp = 0x3ff;
+                       exp = 0x7ff;
                }
        } else {
                if (exp_low == 0x00) {
                        exp = 0x000;
                } else {
-                       exp |= (0x7 << 8);
+                       exp |= (0x7 << 7);
                }
        }
        return (sign << 63) | (exp << 52) | (frac << 29);
index 3ded0974b8ad9d8ee1cc075044673d871dc8309b..5cb68b91091ec2f3b5284c2ae23a9ae9498830f3 100644 (file)
@@ -240,6 +240,16 @@ loader_ok:
        push    ax
        push    cx
        push    dx
+                               ! which bootloader ?
+       seg cs
+       mov     al,byte ptr type_of_loader
+       and     al,#0xf0
+       cmp     al,#0x10
+       jne     try_xe801       ! not Loadlin
+       seg cs
+       cmp     byte ptr type_of_loader,#0x16
+       jbe     oldstylemem     ! Loadlin <= 1.6 don't like that
+try_xe801:
        mov     ax,#0xe801
        int     0x15
        jc      oldstylemem
@@ -257,6 +267,9 @@ loader_ok:
 oldstylemem:
        mov     ah,#0x88
        int     0x15
+       or      ax,ax           ! some BIOSes report ZERO for 64meg
+       mov     word ptr [2],#0x400
+       jz      gotmem
        mov     cx,#64          ! got memory size in kbytes, so we need to
        xor     dx,dx           ! adjust to 64k chunks for the system.
        div     cx
index 950a4ff66d32d82114695abdf2098223c40627f8..69b07d40dc249b4e85ee150e5bb0a4bcbdf7004a 100644 (file)
@@ -235,7 +235,8 @@ static const char * i486model(unsigned int nr)
 static const char * i586model(unsigned int nr)
 {
        static const char *model[] = {
-               "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83"
+               "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83",
+               "Pentium MMX"
        };
        if (nr < sizeof(model)/sizeof(char *))
                return model[nr];
index 4ac12ceade85834ca8ad6be6de7f8f98f468a3d9..6e595055fc42dde7bef8308e11036df47478f05f 100644 (file)
@@ -22,6 +22,7 @@
  *     Matthias Sattler        :       Changes for 2.1 kernel map.
  *     Michel Lespinasse       :       Changes for 2.1 kernel map.
  *     Michael Chastain        :       Change trampoline.S to gnu as.
+ *             Alan Cox        :       Dumb bug: 'B' step PPro's are fine
  *
  */
 
@@ -573,8 +574,11 @@ void smp_store_cpu_info(int id)
        c->x86=x86;
        c->x86_model=x86_model;
        c->x86_mask=x86_mask;
-       if(x86_mask>=1 && x86_mask<=4)
-               smp_b_stepping=1;               /* Remember we have B step CPUs */
+       /*
+        *      Mask B, Pentium, but not Pentium MMX
+        */
+       if(x86_mask>=1 && x86_mask<=4 && x86==5 && (x86_model>=0&&x86_model<=3))
+               smp_b_stepping=1;               /* Remember we have B step Pentia with bugs */
        c->x86_capability=x86_capability;
        c->fdiv_bug=fdiv_bug;
        c->wp_works_ok=wp_works_ok;             /* Always assumed the same currently */
index e964fb98713a6002b2294c504af56fb836974514..d5a2010b9901b73f8fbd9f25b8d2046cb8c339b6 100644 (file)
@@ -427,34 +427,26 @@ cannot_handle:
        return_to_32bit(regs, VM86_INTx + (i << 8));
 }
 
-
-
+/* This must be called with the kernel lock held. */
 int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno)
 {
-       int ret;
-
-       lock_kernel();
        if (VMPI.is_vm86pus) {
                if ( (trapno==3) || (trapno==1) )
                        return_to_32bit(regs, VM86_TRAP + (trapno << 8));
                do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs));
-               ret = 1;
-               goto out;
+               return  1;
        }
-       ret = 0;
        if (trapno !=1)
-               goto out; /* we let this handle by the calling routine */
+               return 0; /* we let this handle by the calling routine */
        if (current->flags & PF_PTRACED)
                current->blocked &= ~(1 << (SIGTRAP-1));
        send_sig(SIGTRAP, current, 1);
        current->tss.trap_no = trapno;
        current->tss.error_code = error_code;
-out:
-       unlock_kernel();
-       return ret;
+       return 0;
 }
 
-
+/* This must be called with the kernel lock held. */
 void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
 {
        unsigned char *csp, *ssp;
@@ -466,9 +458,8 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
 #define VM86_FAULT_RETURN \
        if (VMPI.force_return_for_pic  && (VEFLAGS & IF_MASK)) \
                return_to_32bit(regs, VM86_PICRETURN); \
-       goto out;
+       return;
                                           
-       lock_kernel();
        csp = (unsigned char *) (regs->cs << 4);
        ssp = (unsigned char *) (regs->ss << 4);
        sp = SP(regs);
@@ -532,7 +523,7 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
                                return_to_32bit(regs, VM86_INTx + (intno << 8));
                }
                do_int(regs, intno, ssp, sp);
-               goto out;
+               return;
        }
 
        /* iret */
@@ -565,8 +556,6 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
        default:
                return_to_32bit(regs, VM86_UNKNOWN);
        }
-out:
-       unlock_kernel();
 }
 
 /* ---------------- vm86 special IRQ passing stuff ----------------- */
index e9a3b6a9c977471a98cc6514c94957518c9ef07e..0ad0c47be4a266256cd2a7796c7f1d4ab81144c9 100644 (file)
@@ -11,6 +11,9 @@
  *             Lots of code moved from tcp.c and ip.c; see those files
  *             for more names.
  *
+ * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ *                          handling.
+ *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
  *             as published by the Free Software Foundation; either version
@@ -86,7 +89,7 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
            shll $16,%%ecx
 5:         movb (%%esi),%%cl
 6:         addl %%ecx,%%eax
-           adcl $0, %%eax
+           adcl $0, %%eax 
 7:         "
        : "=a"(sum)
        : "0"(sum), "c"(len), "S"(buff)
@@ -94,96 +97,228 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
        return(sum);
 }
 
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify wether there should be exception handling
+ * for the source and/or the destination addresses.
+ *
+ * FIXME: could someone double check wether i havent mixed up some SRC and
+ *       DST definitions? It's damn hard to trigger all cases, i hope i got
+ *       them all but theres no guarantee ...
+ */
 
+#define csum_partial_copy_type(type) \
+unsigned int csum_partial_copy ##type (int * __csum_err, const char *src, char *dst,   \
+                                 int len, int sum) {  \
+    __asm__(                                                                     \
+"              testl $2, %%edi         # Check alignment.                      \n" \
+"              jz 2f                   # Jump if alignment is ok.              \n" \
+"              subl $2, %%ecx          # Alignment uses up two bytes.          \n" \
+"              jae 1f                  # Jump if we had at least two bytes.    \n" \
+"              addl $2, %%ecx          # ecx was < 2.  Deal with it.           \n" \
+"              jmp 4f                                                          \n" \
+"      1000:                                                                   \n" \
+"       1:     movw (%%esi), %%bx                                              \n" \
+"              addl $2, %%esi                                                  \n" \
+"      1001:                                                                   \n" \
+"              movw %%bx, (%%edi)                                              \n" \
+"              addl $2, %%edi                                                  \n" \
+"              addw %%bx, %%ax                                                 \n" \
+"              adcl $0, %%eax                                                  \n" \
+"      2:                                                                      \n" \
+"              pushl %%ecx                                                     \n" \
+"              shrl $5, %%ecx                                                  \n" \
+"              jz 2f                                                           \n" \
+"              testl %%esi, %%esi                                              \n" \
+"      1002:                                                                   \n" \
+"      1:      movl (%%esi), %%ebx                                             \n" \
+"      1003:                                                                   \n" \
+"              movl 4(%%esi), %%edx                                            \n" \
+"              adcl %%ebx, %%eax                                               \n" \
+"      1004:                                                                   \n" \
+"              movl %%ebx, (%%edi)                                             \n" \
+"              adcl %%edx, %%eax                                               \n" \
+"      1005:                                                                   \n" \
+"              movl %%edx, 4(%%edi)                                            \n" \
+"                                                                              \n" \
+"      1006:                                                                   \n" \
+"              movl 8(%%esi), %%ebx                                            \n" \
+"      1007:                                                                   \n" \
+"              movl 12(%%esi), %%edx                                           \n" \
+"              adcl %%ebx, %%eax                                               \n" \
+"      1008:                                                                   \n" \
+"              movl %%ebx, 8(%%edi)                                            \n" \
+"              adcl %%edx, %%eax                                               \n" \
+"      1009:                                                                   \n" \
+"              movl %%edx, 12(%%edi)                                           \n" \
+"                                                                              \n" \
+"      1010:                                                                   \n" \
+"              movl 16(%%esi), %%ebx                                           \n" \
+"      1011:                                                                   \n" \
+"              movl 20(%%esi), %%edx                                           \n" \
+"              adcl %%ebx, %%eax                                               \n" \
+"      1012:                                                                   \n" \
+"              movl %%ebx, 16(%%edi)                                           \n" \
+"              adcl %%edx, %%eax                                               \n" \
+"      1013:                                                                   \n" \
+"              movl %%edx, 20(%%edi)                                           \n" \
+"                                                                              \n" \
+"      1014:                                                                   \n" \
+"              movl 24(%%esi), %%ebx                                           \n" \
+"      1015:                                                                   \n" \
+"              movl 28(%%esi), %%edx                                           \n" \
+"              adcl %%ebx, %%eax                                               \n" \
+"      1016:                                                                   \n" \
+"              movl %%ebx, 24(%%edi)                                           \n" \
+"              adcl %%edx, %%eax                                               \n" \
+"      1017:                                                                   \n" \
+"              movl %%edx, 28(%%edi)                                           \n" \
+"                                                                              \n" \
+"      1018:                                                                   \n" \
+"              lea 32(%%esi), %%esi                                            \n" \
+"      1019:                                                                   \n" \
+"              lea 32(%%edi), %%edi                                            \n" \
+"              dec %%ecx                                                       \n" \
+"              jne 1b                                                          \n" \
+"              adcl $0, %%eax                                                  \n" \
+"      2:      popl %%edx                                                      \n" \
+"              movl %%edx, %%ecx                                               \n" \
+"              andl $0x1c, %%edx                                               \n" \
+"              je 4f                                                           \n" \
+"              shrl $2, %%edx          # This clears CF                        \n" \
+"      1020:                                                                   \n" \
+"      3:      movl (%%esi), %%ebx                                             \n" \
+"              adcl %%ebx, %%eax                                               \n" \
+"      1021:                                                                   \n" \
+"              movl %%ebx, (%%edi)                                             \n" \
+"      1022:                                                                   \n" \
+"              lea 4(%%esi), %%esi                                             \n" \
+"      1023:                                                                   \n" \
+"              lea 4(%%edi), %%edi                                             \n" \
+"              dec %%edx                                                       \n" \
+"              jne 3b                                                          \n" \
+"              adcl $0, %%eax                                                  \n" \
+"      4:      andl $3, %%ecx                                                  \n" \
+"              jz 7f                                                           \n" \
+"              cmpl $2, %%ecx                                                  \n" \
+"              jb 5f                                                           \n" \
+"      1024:                                                                   \n" \
+"              movw (%%esi), %%cx                                              \n" \
+"      1025:                                                                   \n" \
+"              leal 2(%%esi), %%esi                                            \n" \
+"      1026:                                                                   \n" \
+"              movw %%cx, (%%edi)                                              \n" \
+"      1027:                                                                   \n" \
+"              leal 2(%%edi), %%edi                                            \n" \
+"              je 6f                                                           \n" \
+"              shll $16,%%ecx                                                  \n" \
+"      1028:                                                                   \n" \
+"      5:      movb (%%esi), %%cl                                              \n" \
+"      1029:                                                                   \n" \
+"              movb %%cl, (%%edi)                                              \n" \
+"      6:      addl %%ecx, %%eax                                               \n" \
+"              adcl $0, %%eax                                                  \n" \
+"      7:                                                                      \n" \
+"      2000:                                                                   \n" \
+"         .section .fixup,\"ax\"                                               \n" \
+"      3000:           movl %7,%1                                              \n" \
+/* FIXME: zero out the rest of the buffer here !!!!!! */                       \
+"              jmp 2000b                                                       \n" \
+"              .previous                                                       \n" \
+"              .section __ex_table,\"a\"                                       \n" \
+"              .align 4                                                        \n" \
+"                                                                              \n" \
+SRC(  "        .long 1000b,3000b        \n  "    ) \
+DST(  "        .long 1001b,3000b        \n  "    ) \
+SRC(  "        .long 1002b,3000b        \n  "    ) \
+SRC(  "        .long 1003b,3000b        \n  "    ) \
+DST(  "        .long 1004b,3000b        \n  "    ) \
+DST(  "        .long 1005b,3000b        \n  "    ) \
+SRC(  "        .long 1006b,3000b        \n  "    ) \
+SRC(  "        .long 1007b,3000b        \n  "    ) \
+DST(  "        .long 1008b,3000b        \n  "    ) \
+DST(  "        .long 1009b,3000b        \n  "    ) \
+SRC(  "        .long 1010b,3000b        \n  "    ) \
+SRC(  "        .long 1011b,3000b        \n  "    ) \
+DST(  "        .long 1012b,3000b        \n  "    ) \
+DST(  "        .long 1013b,3000b        \n  "    ) \
+SRC(  "        .long 1014b,3000b        \n  "    ) \
+SRC(  "        .long 1015b,3000b        \n  "    ) \
+DST(  "        .long 1016b,3000b        \n  "    ) \
+DST(  "        .long 1017b,3000b        \n  "    ) \
+SRC(  "        .long 1018b,3000b        \n  "    ) \
+DST(  "        .long 1019b,3000b        \n  "    ) \
+SRC(  "        .long 1020b,3000b        \n  "    ) \
+DST(  "        .long 1021b,3000b        \n  "    ) \
+SRC(  "        .long 1022b,3000b        \n  "    ) \
+DST(  "        .long 1023b,3000b        \n  "    ) \
+SRC(  "        .long 1024b,3000b        \n  "    ) \
+SRC(  "        .long 1025b,3000b        \n  "    ) \
+DST(  "        .long 1026b,3000b        \n  "    ) \
+DST(  "        .long 1027b,3000b        \n  "    ) \
+SRC(  "        .long 1028b,3000b        \n  "    ) \
+DST(  "        .long 1029b,3000b        \n  "    ) \
+"        .previous                      \n  "                          \
+       : "=a" (sum), "=r" (*__csum_err)                                \
+       :  "0" (sum), "c" (len), "S" (src), "D" (dst),                  \
+               "1" (*__csum_err), "i" (-EFAULT)                        \
+       : "bx", "cx", "dx", "si", "di" );                               \
+                                                                       \
+    return(sum);                                                       \
+}
 
 /*
- * copy from ds while checksumming, otherwise like csum_partial
+ *  Currently we need only 2 out of the 4 possible type combinations:
  */
 
-unsigned int csum_partial_copy(const char *src, char *dst, 
-                                 int len, int sum) {
-    __asm__("
-       testl $2, %%edi         # Check alignment.
-       jz 2f                   # Jump if alignment is ok.
-       subl $2, %%ecx          # Alignment uses up two bytes.
-       jae 1f                  # Jump if we had at least two bytes.
-       addl $2, %%ecx          # ecx was < 2.  Deal with it.
-       jmp 4f
-1:     movw (%%esi), %%bx
-       addl $2, %%esi
-       movw %%bx, (%%edi)
-       addl $2, %%edi
-       addw %%bx, %%ax
-       adcl $0, %%eax
-2:
-       pushl %%ecx
-       shrl $5, %%ecx
-       jz 2f
-       testl %%esi, %%esi
-1:     movl (%%esi), %%ebx
-       movl 4(%%esi), %%edx
-       adcl %%ebx, %%eax
-       movl %%ebx, (%%edi)
-       adcl %%edx, %%eax
-       movl %%edx, 4(%%edi)
-
-       movl 8(%%esi), %%ebx
-       movl 12(%%esi), %%edx
-       adcl %%ebx, %%eax
-       movl %%ebx, 8(%%edi)
-       adcl %%edx, %%eax
-       movl %%edx, 12(%%edi)
-
-       movl 16(%%esi), %%ebx
-       movl 20(%%esi), %%edx
-       adcl %%ebx, %%eax
-       movl %%ebx, 16(%%edi)
-       adcl %%edx, %%eax
-       movl %%edx, 20(%%edi)
-
-       movl 24(%%esi), %%ebx
-       movl 28(%%esi), %%edx
-       adcl %%ebx, %%eax
-       movl %%ebx, 24(%%edi)
-       adcl %%edx, %%eax
-       movl %%edx, 28(%%edi)
-
-       lea 32(%%esi), %%esi
-       lea 32(%%edi), %%edi
-       dec %%ecx
-       jne 1b
-       adcl $0, %%eax
-2:     popl %%edx
-       movl %%edx, %%ecx
-       andl $0x1c, %%edx
-       je 4f
-       shrl $2, %%edx          # This clears CF
-3:     movl (%%esi), %%ebx
-       adcl %%ebx, %%eax
-       movl %%ebx, (%%edi)
-       lea 4(%%esi), %%esi
-       lea 4(%%edi), %%edi
-       dec %%edx
-       jne 3b
-       adcl $0, %%eax
-4:     andl $3, %%ecx
-       jz 7f
-       cmpl $2, %%ecx
-       jb 5f
-       movw (%%esi), %%cx
-       leal 2(%%esi), %%esi
-       movw %%cx, (%%edi)
-       leal 2(%%edi), %%edi
-       je 6f
-       shll $16,%%ecx
-5:     movb (%%esi), %%cl
-       movb %%cl, (%%edi)
-6:     addl %%ecx, %%eax
-       adcl $0, %%eax
-7:
-       "
-       : "=a" (sum)
-       : "0"(sum), "c"(len), "S"(src), "D" (dst)
-       : "bx", "cx", "dx", "si", "di" );
-    return(sum);
+/*
+ * Generate 'csum_partial_copy_from_user()', we need to do exception
+ * handling for source addresses.
+ */
+
+#define SRC(x) x
+#define DST(x)
+csum_partial_copy_type(_from_user)
+#undef SRC
+#undef DST
+
+/*
+ * Generate 'csum_partial_copy_nocheck()', no need to do exception
+ * handling.
+ */
+
+#define SRC(x)
+#define DST(x)
+csum_partial_copy_type(_nocheck_generic)
+#undef SRC
+#undef DST
+
+/*
+ * Generate 'csum_partial_copy_old()', old and slow compability stuff,
+ * full checking.
+ *
+ * tell us if you see something printk-ing on this. This function will be
+ * removed soon.
+ */
+
+#define SRC(x) x
+#define DST(x) x
+csum_partial_copy_type(_old)
+#undef SRC
+#undef DST
+
+unsigned int csum_partial_copy ( const char *src, char *dst, 
+                                 int len, int sum)
+{
+       int ret;
+       int error = 0;
+
+       ret = csum_partial_copy_old (&error, src, dst, len, sum);
+
+       if (error)
+               printk("csum_partial_copy_old(): tell mingo to convert me!\n");
+
+       return ret;
 }
+
index d197936058839587e3cd2b46092464d298e5ccb3..c3bb43d24886eda36a7650ae950ec874a832ea0d 100644 (file)
@@ -62,12 +62,12 @@ static int isp16_cdrom_base = ISP16_CDROM_IO_BASE;
 static int isp16_cdrom_irq = ISP16_CDROM_IRQ;
 static int isp16_cdrom_dma = ISP16_CDROM_DMA;
 static char *isp16_cdrom_type = ISP16_CDROM_TYPE;
+
+#ifdef MODULE
 MODULE_PARM(isp16_cdrom_base, "i");
 MODULE_PARM(isp16_cdrom_irq, "i");
 MODULE_PARM(isp16_cdrom_dma, "i");
 MODULE_PARM(isp16_cdrom_type, "s");
-
-#ifdef MODULE
 int init_module(void);
 void cleanup_module(void);
 #endif
index 88ff3e56ec273ee243a865d46f9fd2b5a8810453..daede913c3dff84293f4f529469d4687832b5592 100644 (file)
@@ -106,7 +106,10 @@ static int sjcd_audio_status;
 static struct sjcd_play_msf sjcd_playing;
 
 static int sjcd_base = SJCD_BASE_ADDR;
+
+#ifdef MODULE
 MODULE_PARM(sjcd_base, "i");
+#endif
 
 static struct wait_queue *sjcd_waitq = NULL;
 
index 2fac5b245767034b1c70f1c723a3cdee955ee57a..2d0ebef977a7190e51b3b501d132550b82f544e4 100644 (file)
@@ -59,6 +59,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/poll.h>
 
 #include <linux/types.h>
 #include <linux/stddef.h>
index 8d1afdcccddc25a3eb94454b8b6ca6ddef60ea60..616f4fc2e82f45d877d77f3c234f7326c5396401 100644 (file)
@@ -60,6 +60,7 @@
  * User-defined bell sound, new setterm control sequences and printk
  * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
  *
+ * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
  */
 
 #define BLANK 0x0020
@@ -2194,12 +2195,14 @@ void do_blank_screen(int nopowersave)
        hide_cursor();
        console_blanked = fg_console + 1;
 
+       if(!nopowersave)
+       {
 #ifdef CONFIG_APM
-       if (apm_display_blank())
-               return;
+               if (apm_display_blank())
+                       return;
 #endif
-       if(!nopowersave)
-           vesa_blank();
+               vesa_blank();
+       }
 }
 
 void do_unblank_screen(void)
index 4a862a9ad123daead574c0147cf21d888b3e8a66..da5af96253b7091ce5dc848c3208d79cd0048a66 100644 (file)
@@ -46,7 +46,6 @@ static int soft_margin = TIMER_MARGIN;        /* in seconds */
  
 struct timer_list watchdog_ticktock;
 static int timer_alive = 0;
-static int in_use = 0;
 
 
 /*
@@ -71,9 +70,8 @@ static void watchdog_fire(unsigned long data)
  
 static int softdog_open(struct inode *inode, struct file *file)
 {
-       if(in_use)
+       if(timer_alive)
                return -EBUSY;
-       in_use = 1;
        MOD_INC_USE_COUNT;
        /*
         *      Activate timer
@@ -81,7 +79,7 @@ static int softdog_open(struct inode *inode, struct file *file)
        del_timer(&watchdog_ticktock);
        watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
        add_timer(&watchdog_ticktock);
-       timer_alive++;
+       timer_alive=1;
        return 0;
 }
 
@@ -94,9 +92,8 @@ static void softdog_release(struct inode *inode, struct file *file)
 #ifndef CONFIG_WATCHDOG_NOWAYOUT        
        del_timer(&watchdog_ticktock);
        MOD_DEC_USE_COUNT;
-       timer_alive=0;
 #endif 
-       in_use = 0;
+       timer_alive=0;
 }
 
 static void softdog_ping(void)
index 85daeef120aa8311517830027bd3154c62f09aa8..3d1caa97f11d04d4a1f37bc3bbcae3cd5e7f8ed2 100644 (file)
@@ -123,7 +123,7 @@ static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void el_receive(struct device *dev);
 static void el_reset(struct device *dev);
 static int  el1_close(struct device *dev);
-static struct enet_statistics *el1_get_stats(struct device *dev);
+static struct net_device_stats *el1_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 #define EL1_IO_EXTENT  16
@@ -139,7 +139,7 @@ static int el_debug = EL_DEBUG;
 
 struct net_local
 {
-    struct enet_statistics stats;
+    struct net_device_stats stats;
     int tx_pkt_start;          /* The length of the current Tx packet. */
     int collisions;            /* Tx collisions this packet */
     int loading;               /* Spot buffer load collisions */
@@ -398,12 +398,6 @@ static int el_start_xmit(struct sk_buff *skb, struct device *dev)
                dev->trans_start = jiffies;
        }
 
-       if (skb == NULL)
-       {
-               dev_tint(dev);
-               return 0;
-       }
-
        save_flags(flags);
 
        /*
@@ -432,6 +426,8 @@ load_it_again_sam:
                lp->tx_pkt_start = gp_start;
                lp->collisions = 0;
 
+               lp->stats.tx_bytes += skb->len;
+
                /*
                 *      Command mode with status cleared should [in theory]
                 *      mean no more interrupts can be pending on the card.
@@ -769,7 +765,7 @@ static int el1_close(struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *el1_get_stats(struct device *dev)
+static struct net_device_stats *el1_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        return &lp->stats;
index 975acea327fb7d27af72db56ac7ba7b9985db75a..4d97c497502574bf3c8dd16f773641e1c03f89d8 100644 (file)
@@ -1034,6 +1034,9 @@ static int send_packet(struct device *dev, struct sk_buff *skb)
        }
        adapter = dev->priv;
 
+
+       adapter->stats.tx_bytes+=nlen;
+       
        /*
         * send the adapter a transmit packet command. Ignore segment and offset
         * and make sure the length is even
@@ -1111,15 +1114,6 @@ static int elp_start_xmit(struct sk_buff *skb, struct device *dev)
                adapter->stats.tx_dropped++;
        }
 
-       /* Some upper layer thinks we've missed a tx-done interrupt */
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
-       if (skb->len <= 0)
-               return 0;
-
        if (elp_debug >= 3)
                printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
 
@@ -1156,7 +1150,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct device *dev)
  *
  ******************************************************/
 
-static struct enet_statistics *elp_get_stats(struct device *dev)
+static struct net_device_stats *elp_get_stats(struct device *dev)
 {
        elp_device *adapter = (elp_device *) dev->priv;
 
@@ -1329,7 +1323,7 @@ static void elp_init(struct device *dev)
        /*
         * setup ptr to adapter specific information
         */
-       memset(&(adapter->stats), 0, sizeof(struct enet_statistics));
+       memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
 
        /*
         * memory information
index 48282c3da8cb3e0af3bf7decc081dc758a3a6fad..bea9b5031da2de854d1242acb59943bb31feafff 100644 (file)
@@ -264,7 +264,7 @@ typedef struct {
        pcb_struct rx_pcb;      /* PCB for foreground receiving */
        pcb_struct itx_pcb;     /* PCB for background sending */
        pcb_struct irx_pcb;     /* PCB for background receiving */
-       struct enet_statistics stats;
+       struct net_device_stats stats;
 
        void *dma_buffer;
 
index bfda0499bdd8911c33dcdf7ccb7c5d3c7664f4cd..d718c5b6a7d57b23500fc63269fffd0ac8df31e0 100644 (file)
@@ -115,7 +115,7 @@ enum commands {
 
 /* Information that need to be kept for each board. */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        int last_restart;
        ushort rx_head;
        ushort rx_tail;
@@ -283,7 +283,7 @@ static int  el16_send_packet(struct sk_buff *skb, struct device *dev);
 static void    el16_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void el16_rx(struct device *dev);
 static int     el16_close(struct device *dev);
-static struct enet_statistics *el16_get_stats(struct device *dev);
+static struct net_device_stats *el16_get_stats(struct device *dev);
 
 static void hardware_send_packet(struct device *dev, void *buf, short length);
 void init_82586_mem(struct device *dev);
@@ -300,8 +300,8 @@ struct netdev_entry netcard_drv =
        If dev->base_addr == 2, (detachable devices only) allocate space for the
        device and return success.
        */
-int
-el16_probe(struct device *dev)
+
+int el16_probe(struct device *dev)
 {
        int base_addr = dev ? dev->base_addr : 0;
        int i;
@@ -428,10 +428,7 @@ int el16_probe1(struct device *dev, int ioaddr)
        return 0;
 }
 
-\f
-
-static int
-el16_open(struct device *dev)
+static int el16_open(struct device *dev)
 {
        irq2dev_map[dev->irq] = dev;
 
@@ -447,14 +444,14 @@ el16_open(struct device *dev)
        return 0;
 }
 
-static int
-el16_send_packet(struct sk_buff *skb, struct device *dev)
+static int el16_send_packet(struct sk_buff *skb, struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        int ioaddr = dev->base_addr;
        short *shmem = (short*)dev->mem_start;
 
-       if (dev->tbusy) {
+       if (dev->tbusy) 
+       {
                /* If we get here, some higher level has decided we are broken.
                   There should really be a "kick me" function call instead. */
                int tickssofar = jiffies - dev->trans_start;
@@ -480,21 +477,15 @@ el16_send_packet(struct sk_buff *skb, struct device *dev)
                dev->trans_start = jiffies;
        }
 
-       /* If some higher layer thinks we've missed an tx-done interrupt
-          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-          itself. */
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
        /* Block a timer-based transmit from overlapping. */
        if (set_bit(0, (void*)&dev->tbusy) != 0)
                printk("%s: Transmitter access conflict.\n", dev->name);
-       else {
+       else
+       {
                short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
                unsigned char *buf = skb->data;
 
+               lp->stats.tx_bytes+=length;
                /* Disable the 82586's input to the interrupt line. */
                outb(0x80, ioaddr + MISC_CTRL);
                hardware_send_packet(dev, buf, length);
@@ -509,11 +500,10 @@ el16_send_packet(struct sk_buff *skb, struct device *dev)
 
        return 0;
 }
-\f
+
 /*     The typical workload of the driver:
        Handle the network interface interrupts. */
-static void
-el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct device *dev = (struct device *)(irq2dev_map[irq]);
        struct net_local *lp;
@@ -588,8 +578,9 @@ el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                ack_cmd |= CUC_RESUME;
        }
 
-       if ((status & 0x0070) != 0x0040  &&  dev->start) {
-         static void init_rx_bufs(struct device *);
+       if ((status & 0x0070) != 0x0040  &&  dev->start) 
+       {
+               static void init_rx_bufs(struct device *);
                /* The Rx unit is not ready, it must be hung.  Restart the receiver by
                   initializing the rx buffers, and issuing an Rx start command. */
                if (net_debug)
@@ -612,8 +603,7 @@ el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        return;
 }
 
-static int
-el16_close(struct device *dev)
+static int el16_close(struct device *dev)
 {
        int ioaddr = dev->base_addr;
        ushort *shmem = (short*)dev->mem_start;
@@ -642,8 +632,7 @@ el16_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *
-el16_get_stats(struct device *dev)
+static struct net_device_stats *el16_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
 
@@ -653,8 +642,7 @@ el16_get_stats(struct device *dev)
 }
 
 /* Initialize the Rx-block list. */
-static void
-init_rx_bufs(struct device *dev)
+static void init_rx_bufs(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        unsigned short *write_ptr;
@@ -699,8 +687,7 @@ init_rx_bufs(struct device *dev)
 
 }
 
-void
-init_82586_mem(struct device *dev)
+void init_82586_mem(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        short ioaddr = dev->base_addr;
@@ -758,8 +745,7 @@ init_82586_mem(struct device *dev)
        return;
 }
 
-static void
-hardware_send_packet(struct device *dev, void *buf, short length)
+static void hardware_send_packet(struct device *dev, void *buf, short length)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        short ioaddr = dev->base_addr;
@@ -804,8 +790,7 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                dev->tbusy = 0;
 }
 
-static void
-el16_rx(struct device *dev)
+static void el16_rx(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        short *shmem = (short*)dev->mem_start;
index 9d495711047a7b7180e9183ff8a2df9dedb9e489..5560405d2512747c1d8220be5192bd294e2cd9a3 100644 (file)
@@ -110,7 +110,7 @@ enum RxFilter {
 #define SKB_QUEUE_SIZE 64
 
 struct el3_private {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        /* skb send-queue */
        int head, size;
        struct sk_buff *queue[SKB_QUEUE_SIZE];
@@ -123,7 +123,7 @@ static int el3_open(struct device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct device *dev);
 static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void update_stats(int addr, struct device *dev);
-static struct enet_statistics *el3_get_stats(struct device *dev);
+static struct net_device_stats *el3_get_stats(struct device *dev);
 static int el3_rx(struct device *dev);
 static int el3_close(struct device *dev);
 #ifdef HAVE_MULTICAST
@@ -421,8 +421,7 @@ el3_open(struct device *dev)
        return 0;                                       /* Always succeed */
 }
 
-static int
-el3_start_xmit(struct sk_buff *skb, struct device *dev)
+static int el3_start_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct el3_private *lp = (struct el3_private *)dev->priv;
        int ioaddr = dev->base_addr;
@@ -444,14 +443,6 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
                dev->tbusy = 0;
        }
 
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
-       if (skb->len <= 0)
-               return 0;
-
        if (el3_debug > 4) {
                printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
                           dev->name, skb->len, inw(ioaddr + EL3_STATUS));
@@ -479,6 +470,7 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
        if (set_bit(0, (void*)&dev->tbusy) != 0)
                printk("%s: Transmitter access conflict.\n", dev->name);
        else {
+               lp->stats.tx_bytes+=skb->len;
                /* Put out the doubleword header... */
                outw(skb->len, ioaddr + TX_FIFO);
                outw(0x00, ioaddr + TX_FIFO);
@@ -589,8 +581,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 
-static struct enet_statistics *
-el3_get_stats(struct device *dev)
+static struct net_device_stats *el3_get_stats(struct device *dev)
 {
        struct el3_private *lp = (struct el3_private *)dev->priv;
        unsigned long flags;
index 21b411b6636d2a8f58edd5be4793b49e95b981ea..94e107330aaf17e08fca7c5f7f60c18698d07891 100644 (file)
@@ -170,7 +170,7 @@ static void    elmc_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
 static int     elmc_open(struct device *dev);
 static int     elmc_close(struct device *dev);
 static int     elmc_send_packet(struct sk_buff *,struct device *);
-static struct  enet_statistics *elmc_get_stats(struct device *dev);
+static struct  net_device_stats *elmc_get_stats(struct device *dev);
 static void    set_multicast_list(struct device *dev);
 
 /* helper-functions */
@@ -183,25 +183,26 @@ static void    elmc_rcv_int(struct device *dev);
 static void    elmc_xmt_int(struct device *dev);
 static void    elmc_rnr_int(struct device *dev);
 
-struct priv {
-  struct enet_statistics stats;
-  unsigned long base;
-  char *memtop;
-  volatile struct rfd_struct  *rfd_last,*rfd_top,*rfd_first;
-  volatile struct scp_struct  *scp;  /* volatile is important */
-  volatile struct iscp_struct *iscp; /* volatile is important */
-  volatile struct scb_struct  *scb;  /* volatile is important */
-  volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
-  volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+struct priv 
+{
+       struct net_device_stats stats;
+       unsigned long base;
+       char *memtop;
+       volatile struct rfd_struct      *rfd_last,*rfd_top,*rfd_first;
+       volatile struct scp_struct      *scp;   /* volatile is important */
+       volatile struct iscp_struct *iscp; /* volatile is important */
+       volatile struct scb_struct  *scb;  /* volatile is important */
+       volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
+       volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
-  volatile struct nop_cmd_struct *nop_cmds[2];
+       volatile struct nop_cmd_struct *nop_cmds[2];
 #else
-  volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+       volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
-  volatile int    nop_point,num_recv_buffs;
-  volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
-  volatile int    xmit_count,xmit_last;
-  volatile int slot;
+       volatile int    nop_point,num_recv_buffs;
+       volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
+       volatile int    xmit_count,xmit_last;
+       volatile int slot;
 };
 
 #define elmc_attn586()  {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);}
@@ -1208,9 +1209,8 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev)
  * Someone wanna have the statistics
  */
 
-static
-struct enet_statistics*
-elmc_get_stats( struct device *dev ) {
+static struct net_device_stats *elmc_get_stats( struct device *dev ) 
+{
   struct priv *p = (struct priv *) dev->priv;
   unsigned short crc,aln,rsc,ovrn;
 
index 0b6a7f0009ddda3a4901bd17395df69e9aa6eb2f..fdde08dbd661625a4a769be44828b4ecc255a00d 100644 (file)
@@ -233,7 +233,7 @@ struct vortex_private {
        char devname[8];                        /* "ethN" string, also for kernel debug. */
        const char *product_name;
        struct device *next_module;
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        struct sk_buff *tx_skb;         /* Packet being eaten by bus master ctrl.  */
        struct timer_list timer;        /* Media selection timer. */
        int options;                            /* User-settable misc. driver options. */
@@ -276,7 +276,7 @@ static int vortex_rx(struct device *dev);
 static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
 static int vortex_close(struct device *dev);
 static void update_stats(int addr, struct device *dev);
-static struct enet_statistics *vortex_get_stats(struct device *dev);
+static struct net_device_stats *vortex_get_stats(struct device *dev);
 static void set_rx_mode(struct device *dev);
 \f
 
@@ -1067,8 +1067,7 @@ vortex_close(struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *
-vortex_get_stats(struct device *dev)
+static struct net_device_stats *vortex_get_stats(struct device *dev)
 {
        struct vortex_private *vp = (struct vortex_private *)dev->priv;
        unsigned long flags;
index 69a6524da684064b46fae43ac0640c66cacaa74f..f857cdeef54d3c9d99913fd1b5037649dfe3628f 100644 (file)
@@ -179,17 +179,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
                dev->trans_start = jiffies;
     }
     
-    /* Sending a NULL skb means some higher layer thinks we've missed an
-       tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
-       itself. */
-    if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-    }
-    
     length = skb->len;
-    if (skb->len <= 0)
-               return 0;
 
     /* Mask interrupts from the ethercard. */
     outb_p(0x00, e8390_base + EN0_IMR);
@@ -202,6 +192,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
 
     send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
 
+    ei_local->stat.tx_bytes+=send_length;
+    
 #ifdef EI_PINGPONG
 
     /*
@@ -560,6 +552,7 @@ static void ei_receive(struct device *dev)
                                skb->dev = dev;
                                skb_put(skb, pkt_len);  /* Make room */
                                ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+                               ei_local->stat.rx_bytes+=skb->len;
                                skb->protocol=eth_type_trans(skb,dev);
                                netif_rx(skb);
                                ei_local->stat.rx_packets++;
@@ -663,7 +656,7 @@ static void ei_rx_overrun(struct device *dev)
        
 }
 
-static struct enet_statistics *get_stats(struct device *dev)
+static struct net_device_stats *get_stats(struct device *dev)
 {
     short ioaddr = dev->base_addr;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
index 0736b51fbfe016a2d178836fdd0506eaf75cfb34..770dbcdab486ec15e17848adc30967343916dd83 100644 (file)
@@ -75,7 +75,7 @@ struct ei_device {
   unsigned char reg5;          /* Register '5' in a WD8013 */
   unsigned char saved_irq;     /* Original dev->irq value. */
   /* The new statistics table. */
-  struct enet_statistics stat;
+  struct net_device_stats stat;
 };
 
 /* The maximum number of 8390 interrupt service routines called per IRQ. */
index bb60633b5bc6329b15d5f68822ec046683036b38..8ea48df1be30a1b54424173654b603319b714462 100644 (file)
@@ -99,3 +99,4 @@ DE4X5_OPTS    = -DDE4X5_AUTOSENSE=AUTO
 DEFXX_OPTS     =
 ELP_OPTS       =
 TULIP_OPTS     =
+CS89x0_OPTS    =
index 70ef038fa116b2eab9db56c7981b5df44f574202..2f3670ba57e5280a50fd70c0923d26b3af484927 100644 (file)
@@ -76,7 +76,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
-    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
+    tristate 'CS89x0 support' CONFIG_CS89x0
+    tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
     tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -104,6 +105,15 @@ if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
   dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
 fi
 
+#
+# LocalTalk
+#
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  if [ "$CONFIG_ATALK" != "n" ]; then
+    tristate 'LocalTalk PC support' CONFIG_LTPC
+  fi
+fi
+
 tristate 'PLIP (parallel port) support' CONFIG_PLIP
 
 tristate 'PPP (point-to-point) support' CONFIG_PPP
@@ -137,11 +147,6 @@ if [ "$CONFIG_NET_RADIO" != "n" ]; then
   fi
   tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
   tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
-  tristate 'WIC Radio IP bridge' CONFIG_WIC
-fi
-
-if [ "$CONFIG_X25" != "n" ]; then
-  tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER
 fi
 
 tristate 'SLIP (serial line) support' CONFIG_SLIP
@@ -159,4 +164,23 @@ fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
 fi
+#
+# WAN drivers support
+#
+if [ "$CONFIG_WAN_ROUTER" = "y" ]; then
+  bool 'WAN drivers' CONFIG_WAN_DRIVERS
+  if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
+    bool 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA
+    if [ "$CONFIG_VENDOR_SANGOMA" = "y" ]; then
+      int  '  Maximum number of cards' CONFIG_WANPIPE_CARDS 1
+      bool '  WANPIPE X.25 support' CONFIG_WANPIPE_X25
+      bool '  WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+      bool '  WANPIPE PPP support' CONFIG_WANPIPE_PPP
+    fi
+  fi
+fi
+
+if [ "$CONFIG_X25" != "n" ]; then
+  tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER
+fi
 
index 6f0bcff36d265988087170a130051bea355fe36e..ecfbe15124112a10ce481dff4d0137fc9b16f439 100644 (file)
@@ -77,14 +77,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_WIC),y)
-L_OBJS += wic.o
-else
-  ifeq ($(CONFIG_WIC),m)
-  M_OBJS += wic.o
-  endif
-endif
-
 ifeq ($(CONFIG_SMC9194),y)
 L_OBJS += smc9194.o
 else
@@ -630,6 +622,22 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_CS89x0),y)
+L_OBJS += cs89x0.o
+else
+  ifeq ($(CONFIG_CS89x0),m)
+  M_OBJS += cs89x0.o
+  endif
+endif
+
+ifeq ($(CONFIG_LTPC),y)
+L_OBJS += ltpc.o
+else
+  ifeq ($(CONFIG_LTPC),m)
+  M_OBJS += ltpc.o
+  endif
+endif
+
 ifeq ($(CONFIG_BAYCOM),y)
 L_OBJS += baycom.o
 CONFIG_HDLCDRV_BUILTIN = y
@@ -661,6 +669,21 @@ else
 endif
 
 
+ifeq ($(CONFIG_VENDOR_SANGOMA),y)
+  M_OBJS += sdladrv.o
+  M_OBJS += wanpipe.o
+  WANPIPE_OBJS = sdlamain.o
+  ifeq ($(CONFIG_WANPIPE_X25),y)
+    WANPIPE_OBJS += sdla_x25.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_FR),y)
+    WANPIPE_OBJS += sdla_fr.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_PPP),y)
+    WANPIPE_OBJS += sdla_ppp.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 clean:
@@ -725,7 +748,24 @@ sdla.o: sdla.c CONFIG
 
 dlci.o: dlci.c CONFIG
 
+sdladrv.o: sdladrv.c CONFIG
+
+wanpipe.o: $(WANPIPE_OBJS)
+       ld -r -o $@ $^
+
+sdlamain.o: sdlamain.c CONFIG
+
+sdla_x25.o: sdla_x25.c CONFIG
+
+sdla_fr.o: sdla_fr.c CONFIG
+
+sdla_ppp.o: sdla_ppp.c CONFIG
+
 dgrs.o: dgrs.c dgrs.h CONFIG
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+ltpc.o: ltpc.c ltpc.h CONFIG
+       $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
 tulip.o: tulip.c CONFIG
        $(CC) $(CPPFLAGS) $(CFLAGS) $(TULIP_OPTS) -c $<
index 1952fa76c320656b4b20ef4aedc60a4121852ea4..1184377233a892f201ec62edee86b4432559171a 100644 (file)
@@ -1,20 +1,22 @@
-The de425/de434/de435/de500 driver in this distribution  is designed to work
-with  the  Digital Equipment Corporation   series of PCI/EISA ethernet cards
-(DE425, DE434, DE435, DE500) and with all kernels that support PCI.
+This driver has been upgraded to include generic DECchip support through the
+use of the on-board SROM  that is found on all  DECchip cards except for the
+DC21040. The driver  will work with the following  set of cards and probably
+more:
+
+        KINGSTON
+       Linksys
+       ZNYX342
+       SMC8432
+       SMC9332 (w/new SROM)
+       ZNYX31[45]
+       DIGITAL EtherWORKS PCI/EISA (DE425, DE434, DE435, DE450, DE500)
 
 Auto media detection is provided so that the  media choice isn't compiled in
-and is  flexible enough to be able  to  reconfigure on-the-fly. This feature
-hasn't been included for the DE500 unfortunately, due  to a potential patent
-dispute. When I get around to implementing the autosense algorithm by myself
-(which could legally be difficult to prove since I'm  part of the group that
-has implemented the patented algorithm) you'll  have an auto speed selection
-for the de500. If you want the auto speed feature yell at Digital. If enough
-of you do things might change.
-
-The ability to load   this driver as  a loadable  module has been  included,
-although I don't recommend its use with PCI, since PCI dynamically allocates
-where the card will go at boot time (i.e. the  card would have to be present
-in the system at boot time for its address/IRQ to be assigned).
+and is  flexible enough to be able  to  reconfigure on-the-fly. 
+
+The ability to load this driver as  a loadable module  has been included and
+will now load  (and   unload) as many  DECchip  cards  as  it can  find  and
+configure with just one invocation of 'insmod'.
 
 The performance we've achieved  so far has  been measured through the 'ttcp'
 tool at 1.06MB/s for  TCP  and 1.17MB/s for  UDP.   This measures  the total
@@ -32,16 +34,8 @@ All  values are   typical  (in kBytes/sec) from   a  sample of   4  for each
 measurement. Their error  is approx +/-20k on a  quiet (private) network and
 also depend on what load the CPU has, CPU speed etc.
 
-ZYNX and SMC cards, which use the PCI DECchip  DC21040, are not specifically
-supported in this driver because
-
-a) I have  no information on them.   
-b) I cannot test  them with the driver.
-c) Donald Becker's 'tulip.c' driver  works with them....well one person says
-   they do and another says they do not, so take your pick!
-
-This driver can be made to work with the ZYNX  (and may be  the SMC) card by
-setting a compile time flag (IS_NOT_DEC) in linux/drivers/net/CONFIG
+I've had  reports  that Alphas  can get 80+Mb/s   when using  100BASE-TX and
+similar figures for 133MHz Pentium Pros.
 
 Enjoy!
 
diff --git a/drivers/net/README.ltpc b/drivers/net/README.ltpc
new file mode 100644 (file)
index 0000000..477f9fc
--- /dev/null
@@ -0,0 +1,98 @@
+This is the ALPHA version of the ltpc driver.
+
+In order to use it, you will need at least version 1.3.3 of the
+netatalk package, and the Apple or Farallon Localtalk PC card.
+There are a number of different Localtalk cards for the PC; this
+driver applies only to the one with the 65c02 processor chip on it.
+
+To include it in the kernel, select the CONFIG_LTPC switch in the
+configuration dialog; at this time (kernel 2.1.23) compiling it as
+a module will not work.
+
+Before starting up the netatalk demons (perhaps in rc.local), you
+need to add a line such as:
+
+/sbin/ifconfig ltalk0 127.0.0.42
+
+
+The driver will autoprobe, and you should see a message like:
+"LocalTalk card found at 240, IR9, DMA1."
+at bootup.
+
+The appropriate netatalk configuration depends on whether you are
+attached to a network that includes appletalk routers or not.  If,
+like me, you are simply connecting to your home Macintoshes and
+printers, you need to set up netatalk to "seed".  The way I do this
+is to have the lines
+
+dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
+ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
+
+in my atalkd.conf.  What is going on here is that I need to fool
+netatalk into thinking that there are two appletalk interfaces
+present -- otherwise it refuses to seed.  This is a hack, and a
+more permanent solution would be to alter the netatalk code.
+Note that the dummy driver needs to accept multicasts also -- earlier
+versions of dummy.c may need to be patched.  
+
+
+If you are attached to an extended appletalk network, with routers on
+it, then you don't need to fool around with this -- the appropriate
+line in atalkd.conf is
+
+ltalk0 -phase 1
+
+--------------------------------------
+
+Card Configuration:
+
+The interrupts and so forth are configured via the dipswitch on the
+board.  Set the switches so as not to conflict with other hardware.
+
+       Interrupts -- set at most one.  If none are set, the driver uses
+       polled mode.  Because the card was developed in the XT era, the
+       original documentation refers to IRQ2.  Since you'll be running
+       this on an AT (or later) class machine, that really means IRQ9.
+
+       SW1     IRQ 4
+       SW2     IRQ 3
+       SW3     IRQ 9 (2 in original card documentation only applies to XT)
+
+
+       DMA -- choose DMA 1 or 3, and set both corresponding switches.
+
+       SW4     DMA 3
+       SW5     DMA 1
+       SW6     DMA 3
+       SW7     DMA 1
+
+
+       I/O address -- choose one.
+
+       SW8     220 / 240
+
+--------------------------------------
+
+IP:
+       Many people are interested in this driver in order to use IP
+when Localtalk, but no Ethernet, is available.  While the code to do
+this is not strictly speaking part of this driver, an experimental 
+version is available which seems to work under kernel 2.0.xx.  It is
+not yet functional in the 2.1.xx kernels.
+
+--------------------------------------
+
+BUGS:
+
+2.0.xx:
+
+2.1.xx:        The module support doesn't work yet.
+
+______________________________________
+
+THANKS:
+       Thanks to Alan Cox for helpful discussions early on in this
+work, and to Denis Hainsworth for doing the bleeding-edge testing.
+
+-- Bradford Johnson <bradford@math.umn.edu>
+
index 232ba90167fd5fb378b712d60bb81e7ebcf43f12..8bc9397ec6a650dba9400468541061a2fa447094 100644 (file)
@@ -25,6 +25,7 @@ apricot               YES             PROMISC         YES             Hardware
 arcnet         NO              NO              NO              N/A
 at1700         PROMISC         PROMISC         YES             Software
 atp            PROMISC         PROMISC         YES             Software
+cs89x0         YES             YES             YES             Software
 de4x5          YES             NO              YES             Hardware
 de600          NO              NO              NO              N/A
 de620          PROMISC         PROMISC         YES             Software
diff --git a/drivers/net/README.wanpipe b/drivers/net/README.wanpipe
new file mode 100644 (file)
index 0000000..bcfed26
--- /dev/null
@@ -0,0 +1,142 @@
+------------------------------------------------------------------------------
+WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router
+------------------------------------------------------------------------------
+Release 3.0.0
+December 31, 1996
+Author: Gene Kozin <genek@compuserve.com>
+Copyright (c) 1995-1996 Sangoma Technologies Inc.
+------------------------------------------------------------------------------
+
+INTRODUCTION
+
+WANPIPE(tm) is a family of intelligent muliprotocol WAN communication adapters
+for personal computers (ISA bus) designed to provide PC connectivity to
+various communication links, such as leased lines and public data networks, at
+speeds up to T1/E1 using variety of synchronous communications protocols,
+including frame relay, PPP, X.25, SDLC, etc.
+
+WANPIPE driver together with Linux WAN Router module allows you to build
+relatively inexpensive, yet high-prformance multiprotocol WAN router.  For
+more information about Linux WAN Router please read file
+Documentation/networking/wan-router.txt.  You must also obtain WAN Tools
+package to be able to use Linux WAN Router and WANPIPE driver.  The package
+is available via the Internet from Sangoma Technologies' anonymous FTP server:
+
+       ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz
+
+For technical questions and/or comments please e-mail to genek@compuserve.com.
+For general inquiries please contact Sangoma Technologies Inc. by
+
+       Hotline:        1-800-388-2475  (USA and Canada, toll free)
+       Phone:          (905) 474-1990
+       Fax:            (905) 474-9223
+       E-mail:         dm@sangoma.com  (David Mandelstam)
+       WWW:            http://www.sangoma.com
+
+
+
+COPYRIGHT AND LICENSING INFORMATION
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+
+
+
+NEW IN THIS RELEASE
+
+ o Implemented as WAN Link Driver compliant with Linux WAN Router interface
+ o Added support for X.25 protocol
+ o Miscellaneous bug fixes and performance improvements
+
+
+
+FILE LIST
+
+drivers/net:
+       README.wanpipe  This file
+       sdladrv.c       SDLA support module source code
+       wpmain.c        WANPIPE driver module main source code
+       wpx.c           WANPIPE driver module X.25 source code
+       wpf.c           WANPIPE driver module frame relay source code
+       wpp.c           WANPIPE driver module PPP source code
+       sdla_x25.h      SDLA X.25 firmware API definitions
+       sdla_fr.h       SDLA frame relay firmware API definitions
+       sdla_ppp.h      SDLA PPP firmware API definitions
+
+include/linux:
+       wanpipe.h       WANPIPE API definitions
+       sdladrv.h       SDLA support module API definitions
+       sdlasfm.h       SDLA firmware module definitions
+
+
+
+REVISION HISTORY
+
+3.0.0  December 31, 1996
+
+       o Uses Linux WAN Router interface
+       o Added support for X.25 routing
+       o Miscellaneous bug fixes and performance improvements
+
+2.4.1  December 18, 1996
+
+       o Added support for LMI and Q.933 frame relay link management
+
+2.3.0  October 17, 1996
+
+       o All shell scripts use meta-configuration file
+       o Miscellaneous bug fixes
+
+2.2.0  July 16, 1996
+
+       o Compatible with Linux 2.0
+       o Added uninstall script
+       o User's Manual is available in HTML format
+
+2.1.0  June 20, 1996
+
+       o Added support for synchronous PPP
+       o Added support for S503 adapter
+       o Added API for executing adapter commands
+       o Fixed a re-entrancy problem in frame relaty driver
+       o Changed interface between SDLA driver and protocol support modules
+       o Updated frame relay firmware
+
+2.0.0  May 1, 1996
+
+       o Added interactive installation and configuration scripts
+       o Added System V-style start-up script
+       o Added dynamic memory window address selection in SDLA driver
+       o Miscellaneous bug fixes in SDLA driver
+       o Updated S508 frame relay firmware
+       o Changed SFM file format
+
+1.0.0  February 12, 1996
+
+       o Final release
+       o Added support for Linux 1.3
+       o Updated S508 frame relay firmware
+
+0.9.0  December 21, 1995
+
+       o Added SNAP encapsulation for routed frames
+       o Added support for the frame relay switch emulation mode
+       o Added support for S508 adapter
+       o Added capability to autodetect adapter type
+       o Miscellaneous bug fixes in SDLA and frame relay drivers
+
+0.1.0  October 12, 1995
+
+       o Initial version
+
+>>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
index ff853e8d300237266c5a7ec72976d406cde6403b..f0cce96bebcb765af142e47d9f5e2eaafe71b7cd 100644 (file)
@@ -84,14 +84,14 @@ extern int atarilance_probe(struct device *);
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
+extern int cs89x0_probe(struct device *dev);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
 extern int de600_probe(struct device *);
 extern int de620_probe(struct device *);
 
-static int
-ethif_probe(struct device *dev)
+static int ethif_probe(struct device *dev)
 {
     u_long base_addr = dev->base_addr;
 
@@ -150,6 +150,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_AT1500
        && at1500_probe(dev)
 #endif
+#ifdef CONFIG_CS89x0
+       && cs89x0_probe(dev)
+#endif
 #ifdef CONFIG_AT1700
        && at1700_probe(dev)
 #endif
@@ -270,6 +273,17 @@ static struct device atp_dev = {
 #   define     NEXT_DEV        (&arcnet_dev)
 #endif
 
+#if defined(CONFIG_LTPC)
+    extern int ltpc_probe(struct device *);
+    static struct device dev_ltpc = {
+        "ltalk0\0   ",
+                0, 0, 0, 0,
+                0x0, 0,
+                0, 0, 0, NEXT_DEV, ltpc_probe };
+#   undef NEXT_DEV
+#   define NEXT_DEV    (&dev_ltpc)
+#endif  /* LTPC */
+
 /* The first device defaults to I/O base '0', which means autoprobe. */
 #ifndef ETH0_ADDR
 # define ETH0_ADDR 0
index 08873ecb87f1b1e2cd0822a1b653a31629a7e080..a8e532d26b85b4af317d38dc82fe5a5d71c73622 100644 (file)
@@ -122,7 +122,7 @@ struct lance_private {
        int lance_log_rx_bufs, lance_log_tx_bufs;
        int rx_ring_mod_mask, tx_ring_mod_mask;
 
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        int tpe;                      /* cable-selection is TPE */
        int auto_select;              /* cable-selection by carrier */
        unsigned short busmaster_regval;
@@ -645,7 +645,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
        return status;
 }
 
-static struct enet_statistics *lance_get_stats (struct device *dev)
+static struct net_device_stats *lance_get_stats (struct device *dev)
 {
        struct lance_private *lp = (struct lance_private *) dev->priv;
 
index ad8738fc10530ff6c03b98e6c4608409ff7281ac..67a779ee354e950d75ad69a4b7b5ad5ecaa92ef2 100644 (file)
@@ -162,7 +162,7 @@ struct i596_private {
     struct i596_cmd *cmd_head;
     int cmd_backlog;
     unsigned long last_cmd;
-    struct enet_statistics stats;
+    struct net_device_stats stats;
 };
 
 char init_setup[] = {
@@ -185,7 +185,7 @@ static int i596_open(struct device *dev);
 static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
 static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int i596_close(struct device *dev);
-static struct enet_statistics *i596_get_stats(struct device *dev);
+static struct net_device_stats *i596_get_stats(struct device *dev);
 static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd);
 static void print_eth(char *);
 static void set_multicast_list(struct device *dev);
@@ -942,7 +942,7 @@ i596_close(struct device *dev)
     return 0;
 }
 
-static struct enet_statistics *
+static struct net_device_stats *
 i596_get_stats(struct device *dev)
 {
     struct i596_private *lp = (struct i596_private *)dev->priv;
index db1e95e3d478678d399037e0d8a585041e5f8c91..5f1198e3ef9f6fcccaea270613b52fec98ed2f3f 100644 (file)
@@ -535,7 +535,7 @@ struct Outgoing
 
 /* Information that needs to be kept for each board. */
 struct arcnet_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        u_short sequence;       /* sequence number (incs with each packet) */
        u_char stationid,       /* our 8-bit station address */
                recbuf,         /* receive buffer # (0 or 1) */
@@ -609,7 +609,7 @@ static void arcnet_rx(struct device *dev,int recbuf);
 static void arcnetA_rx(struct device *dev,u_char *buf,
        int length,u_char saddr, u_char daddr);
 
-static struct enet_statistics *arcnet_get_stats(struct device *dev);
+static struct net_device_stats *arcnet_get_stats(struct device *dev);
 
 int arcnetA_header(struct sk_buff *skb,struct device *dev,
                unsigned short type,void *daddr,void *saddr,unsigned len);
@@ -2580,8 +2580,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
  * closed.
  */
 
-static struct enet_statistics *
-arcnet_get_stats(struct device *dev)
+static struct net_device_stats *arcnet_get_stats(struct device *dev)
 {
        struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 
index 93939b437fe15ed032771f34f37c1a337177627b..d4c2cb91a8a13591632483ba0f23584a1ed468a9 100644 (file)
@@ -103,7 +103,7 @@ struct ariadne_private {
     u_short *rx_buff[RX_RING_SIZE];
     int cur_tx, cur_rx;                        /* The next free ring entry */
     int dirty_tx;                      /* The ring entries to be free()ed. */
-    struct enet_statistics stats;
+    struct net_device_stats stats;
     char tx_full;
     unsigned long lock;
     int key;
@@ -128,7 +128,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev);
 static int ariadne_rx(struct device *dev);
 static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp);
 static int ariadne_close(struct device *dev);
-static struct enet_statistics *ariadne_get_stats(struct device *dev);
+static struct net_device_stats *ariadne_get_stats(struct device *dev);
 #ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev);
 #endif
@@ -782,7 +782,7 @@ static int ariadne_rx(struct device *dev)
 }
 
 
-static struct enet_statistics *ariadne_get_stats(struct device *dev)
+static struct net_device_stats *ariadne_get_stats(struct device *dev)
 {
     struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
     struct AriadneBoard *board = priv->board;
index b7e715a8f761599e663f740a517971d92d0cc8ac..2cadbbf4a945abc1df08622b053bdec481e6bdd1 100644 (file)
@@ -67,7 +67,7 @@ typedef unsigned char uchar;
 
 /* Information that need to be kept for each board. */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        uint tx_started:1;                      /* Number of packet on the Tx queue. */
        uchar tx_queue;                         /* Number of packet on the Tx queue. */
        ushort tx_queue_len;            /* Current length of the Tx queue. */
@@ -120,7 +120,7 @@ static int  net_send_packet(struct sk_buff *skb, struct device *dev);
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void net_rx(struct device *dev);
 static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 \f
@@ -592,8 +592,8 @@ static int net_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+   
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
 
index 7dbbfffbdd4e3cdb1db347b75ae92029befadce4..93bac94ad4a5485cf1bd4d1542b811f5c2e8f870 100644 (file)
@@ -136,7 +136,7 @@ static unsigned int bionet_min_poll_time = 2;
 /* Information that need to be kept for each board.
  */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        long open_time;                 /* for debugging */
        int  poll_time;                 /* polling time varies with net load */
 };
@@ -157,7 +157,7 @@ static int bionet_open(struct device *dev);
 static int bionet_send_packet(struct sk_buff *skb, struct device *dev);
 static void bionet_poll_rx(struct device *);
 static int bionet_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void bionet_tick(unsigned long);
 
 static struct timer_list bionet_timer = { NULL, NULL, 0, 0, bionet_tick };
@@ -594,8 +594,8 @@ bionet_close(struct device *dev) {
 /* Get the current statistics.
    This may be called with the card open or closed.
  */
-static struct enet_statistics *
-net_get_stats(struct device *dev) {
+static struct net_device_stats *net_get_stats(struct device *dev) 
+{
        struct net_local *lp = (struct net_local *)dev->priv;
        return &lp->stats;
 }
index d6de47007d979350e3d110ee96c2f00ac6f3f2d9..a8f5ab706265f24f16079ac5b814e9a5972442e4 100644 (file)
@@ -134,7 +134,7 @@ static unsigned int pamsnet_min_poll_time = 2;
 /* Information that need to be kept for each board.
  */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        long open_time;                 /* for debugging */
        int  poll_time;                 /* polling time varies with net load */
 };
@@ -167,7 +167,7 @@ static int pamsnet_open(struct device *dev);
 static int pamsnet_send_packet(struct sk_buff *skb, struct device *dev);
 static void pamsnet_poll_rx(struct device *);
 static int pamsnet_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void pamsnet_tick(unsigned long);
 
 static void pamsnet_intr(int irq, void *data, struct pt_regs *fp);
@@ -866,8 +866,8 @@ pamsnet_close(struct device *dev) {
 /* Get the current statistics.
    This may be called with the card open or closed.
  */
-static struct enet_statistics *
-net_get_stats(struct device *dev) {
+static struct net_device_stats *net_get_stats(struct device *dev) 
+{
        struct net_local *lp = (struct net_local *)dev->priv;
        return &lp->stats;
 }
index afab3432ef38aed04f56219e393f59e1fb3dc88d..9b8f4d45c1bee6e8e52098359ecc526bbb2a8b7e 100644 (file)
@@ -223,7 +223,7 @@ struct lance_private {
        int                                     dirty_tx;               /* Ring entries to be freed. */
                                                /* copy function */
        void                            *(*memcpy_f)( void *, const void *, size_t );
-       struct enet_statistics stats;
+       struct net_device_stats stats;
 /* These two must be ints for set_bit() */
        int                                     tx_full;
        int                                     lock;
@@ -346,7 +346,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev );
 static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
 static int lance_rx( struct device *dev );
 static int lance_close( struct device *dev );
-static struct enet_statistics *lance_get_stats( struct device *dev );
+static struct net_device_stats *lance_get_stats( struct device *dev );
 static void set_multicast_list( struct device *dev );
 static int lance_set_mac_address( struct device *dev, void *addr );
 
@@ -1072,7 +1072,7 @@ static int lance_close( struct device *dev )
 }
 
 
-static struct enet_statistics *lance_get_stats( struct device *dev )
+static struct net_device_stats *lance_get_stats( struct device *dev )
 
 {      struct lance_private *lp = (struct lance_private *)dev->priv;
 
index 466fb821fcac8e99a5f8f80b4a6550ae671af4e3..67086642130a2e0e597e950e6dcec1b98300f776 100644 (file)
@@ -139,7 +139,7 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void net_rx(struct device *dev);
 static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
 static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 \f
@@ -747,8 +747,7 @@ net_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        return &lp->stats;
index e58f8c100c2f5c88fd676290227c285e5a6ed5d4..2a64697e999bef61526ee83b837f0076cd64f01b 100644 (file)
@@ -2,12 +2,13 @@
 #include <linux/types.h>
 #include <asm/io.h>
 
-struct net_local {
+struct net_local 
+{
 #ifdef __KERNEL__
-    struct enet_statistics stats;
+       struct net_device_stats stats;
 #endif
-    ushort saved_tx_size;
-    unsigned char
+       ushort saved_tx_size;
+       unsigned char
        re_tx,                  /* Number of packet retransmissions. */
        tx_unit_busy,
        addr_mode,              /* Current Rx filter e.g. promiscuous, etc. */
@@ -15,10 +16,10 @@ struct net_local {
 };
 
 struct rx_header {
-    ushort pad;                        /* The first read is always corrupted. */
-    ushort rx_count;
-    ushort rx_status;          /* Unknown bit assignments :-<.  */
-    ushort cur_addr;           /* Apparently the current buffer address(?) */
+       ushort pad;                     /* The first read is always corrupted. */
+       ushort rx_count;
+       ushort rx_status;               /* Unknown bit assignments :-<.  */
+       ushort cur_addr;                /* Apparently the current buffer address(?) */
 };
 
 #define PAR_DATA       0
@@ -40,15 +41,16 @@ struct rx_header {
 
 enum page0_regs
 {
-    /* The first six registers hold the ethernet physical station address. */
-    PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
-    TxCNT0 = 6, TxCNT1 = 7,            /* The transmit byte count. */
-    TxSTAT = 8, RxSTAT = 9,            /* Tx and Rx status. */
-    ISR = 10, IMR = 11,                        /* Interrupt status and mask. */
-    CMR1 = 12,                         /* Command register 1. */
-    CMR2 = 13,                         /* Command register 2. */
-    MAR = 14,                          /* Memory address register. */
-    CMR2_h = 0x1d, };
+       /* The first six registers hold the ethernet physical station address. */
+       PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
+       TxCNT0 = 6, TxCNT1 = 7,         /* The transmit byte count. */
+       TxSTAT = 8, RxSTAT = 9,         /* Tx and Rx status. */
+       ISR = 10, IMR = 11,             /* Interrupt status and mask. */
+       CMR1 = 12,                      /* Command register 1. */
+       CMR2 = 13,                      /* Command register 2. */
+       MAR = 14,                       /* Memory address register. */
+       CMR2_h = 0x1d, 
+};
 
 enum eepage_regs
 { PROM_CMD = 6, PROM_DATA = 7 };       /* Note that PROM_CMD is in the "high" bits. */
@@ -81,135 +83,139 @@ enum eepage_regs
 
 /* An inline function used below: it differs from inb() by explicitly return an unsigned
    char, saving a truncation. */
+   
 extern inline unsigned char inbyte(unsigned short port)
 {
-    unsigned char _v;
-    __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port));
-    return _v;
+       unsigned char _v;
+       __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port));
+       return _v;
 }
 
 /* Read register OFFSET.
    This command should always be terminated with read_end(). */
+
 extern inline unsigned char read_nibble(short port, unsigned char offset)
 {
-    unsigned char retval;
-    outb(EOC+offset, port + PAR_DATA);
-    outb(RdAddr+offset, port + PAR_DATA);
-    inbyte(port + PAR_STATUS);         /* Settling time delay */
-    retval = inbyte(port + PAR_STATUS);
-    outb(EOC+offset, port + PAR_DATA);
-
-    return retval;
+       unsigned char retval;
+       outb(EOC+offset, port + PAR_DATA);
+       outb(RdAddr+offset, port + PAR_DATA);
+       inbyte(port + PAR_STATUS);              /* Settling time delay */
+       retval = inbyte(port + PAR_STATUS);
+       outb(EOC+offset, port + PAR_DATA);
+
+       return retval;
 }
 
 /* Functions for bulk data read.  The interrupt line is always disabled. */
 /* Get a byte using read mode 0, reading data from the control lines. */
+
 extern inline unsigned char read_byte_mode0(short ioaddr)
 {
-    unsigned char low_nib;
-
-    outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);       /* Settling time delay -- needed!  */
-    inbyte(ioaddr + PAR_STATUS);       /* Settling time delay -- needed!  */
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+       unsigned char low_nib;
+
+       outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+       inbyte(ioaddr + PAR_STATUS);
+       low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+       outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+       inbyte(ioaddr + PAR_STATUS);    /* Settling time delay -- needed!  */
+       inbyte(ioaddr + PAR_STATUS);    /* Settling time delay -- needed!  */
+       return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
 /* The same as read_byte_mode0(), but does multiple inb()s for stability. */
+
 extern inline unsigned char read_byte_mode2(short ioaddr)
 {
-    unsigned char low_nib;
-
-    outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);       /* Settling time delay -- needed!  */
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+       unsigned char low_nib;
+
+       outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+       inbyte(ioaddr + PAR_STATUS);
+       low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+       outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+       inbyte(ioaddr + PAR_STATUS);    /* Settling time delay -- needed!  */
+       return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
 /* Read a byte through the data register. */
+
 extern inline unsigned char read_byte_mode4(short ioaddr)
 {
-    unsigned char low_nib;
+       unsigned char low_nib;
 
-    outb(RdAddr | MAR, ioaddr + PAR_DATA);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+       outb(RdAddr | MAR, ioaddr + PAR_DATA);
+       low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+       outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+       return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
 /* Read a byte through the data register, double reading to allow settling. */
+
 extern inline unsigned char read_byte_mode6(short ioaddr)
 {
-    unsigned char low_nib;
-
-    outb(RdAddr | MAR, ioaddr + PAR_DATA);
-    inbyte(ioaddr + PAR_STATUS);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
-    inbyte(ioaddr + PAR_STATUS);
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+       unsigned char low_nib;
+
+       outb(RdAddr | MAR, ioaddr + PAR_DATA);
+       inbyte(ioaddr + PAR_STATUS);
+       low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+       outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+       inbyte(ioaddr + PAR_STATUS);
+       return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
-extern inline void
-write_reg(short port, unsigned char reg, unsigned char value)
+extern inline void write_reg(short port, unsigned char reg, unsigned char value)
 {
-    unsigned char outval;
-    outb(EOC | reg, port + PAR_DATA);
-    outval = WrAddr | reg;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);     /* Double write for PS/2. */
-
-    outval &= 0xf0;
-    outval |= value;
-    outb(outval, port + PAR_DATA);
-    outval &= 0x1f;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);
-
-    outb(EOC | outval, port + PAR_DATA);
+       unsigned char outval;
+       outb(EOC | reg, port + PAR_DATA);
+       outval = WrAddr | reg;
+       outb(outval, port + PAR_DATA);
+       outb(outval, port + PAR_DATA);  /* Double write for PS/2. */
+
+       outval &= 0xf0;
+       outval |= value;
+       outb(outval, port + PAR_DATA);
+       outval &= 0x1f;
+       outb(outval, port + PAR_DATA);
+       outb(outval, port + PAR_DATA);
+
+       outb(EOC | outval, port + PAR_DATA);
 }
 
-extern inline void
-write_reg_high(short port, unsigned char reg, unsigned char value)
+extern inline void write_reg_high(short port, unsigned char reg, unsigned char value)
 {
-    unsigned char outval = EOC | HNib | reg;
+       unsigned char outval = EOC | HNib | reg;
 
-    outb(outval, port + PAR_DATA);
-    outval &= WrAddr | HNib | 0x0f;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);     /* Double write for PS/2. */
+       outb(outval, port + PAR_DATA);
+       outval &= WrAddr | HNib | 0x0f;
+       outb(outval, port + PAR_DATA);
+       outb(outval, port + PAR_DATA);  /* Double write for PS/2. */
 
-    outval = WrAddr | HNib | value;
-    outb(outval, port + PAR_DATA);
-    outval &= HNib | 0x0f;             /* HNib | value */
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);
+       outval = WrAddr | HNib | value;
+       outb(outval, port + PAR_DATA);
+       outval &= HNib | 0x0f;          /* HNib | value */
+       outb(outval, port + PAR_DATA);
+       outb(outval, port + PAR_DATA);
 
-    outb(EOC | HNib | outval, port + PAR_DATA);
+       outb(EOC | HNib | outval, port + PAR_DATA);
 }
 
 /* Write a byte out using nibble mode.  The low nibble is written first. */
-extern inline void
-write_reg_byte(short port, unsigned char reg, unsigned char value)
+
+extern inline void write_reg_byte(short port, unsigned char reg, unsigned char value)
 {
-    unsigned char outval;
-    outb(EOC | reg, port + PAR_DATA);  /* Reset the address register. */
-    outval = WrAddr | reg;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);     /* Double write for PS/2. */
-
-    outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
-    outb(value & 0x0f, port + PAR_DATA);
-    value >>= 4;
-    outb(value, port + PAR_DATA);
-    outb(0x10 | value, port + PAR_DATA);
-    outb(0x10 | value, port + PAR_DATA);
-
-    outb(EOC  | value, port + PAR_DATA);       /* Reset the address register. */
+       unsigned char outval;
+       outb(EOC | reg, port + PAR_DATA);       /* Reset the address register. */
+       outval = WrAddr | reg;
+       outb(outval, port + PAR_DATA);
+       outb(outval, port + PAR_DATA);          /* Double write for PS/2. */
+
+       outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
+       outb(value & 0x0f, port + PAR_DATA);
+       value >>= 4;
+       outb(value, port + PAR_DATA);
+       outb(0x10 | value, port + PAR_DATA);
+       outb(0x10 | value, port + PAR_DATA);
+
+       outb(EOC  | value, port + PAR_DATA);    /* Reset the address register. */
 }
 
 /*
@@ -219,30 +225,32 @@ write_reg_byte(short port, unsigned char reg, unsigned char value)
  * It should only be needed when there is skew between the individual data
  * lines.
  */
+
 extern inline void write_byte_mode0(short ioaddr, unsigned char value)
 {
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+       outb(value & 0x0f, ioaddr + PAR_DATA);
+       outb((value>>4) | 0x10, ioaddr + PAR_DATA);
 }
 
 extern inline void write_byte_mode1(short ioaddr, unsigned char value)
 {
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
-    outb((value>>4) | 0x10, ioaddr + PAR_DATA);
-    outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
+       outb(value & 0x0f, ioaddr + PAR_DATA);
+       outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
+       outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+       outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
 }
 
 /* Write 16bit VALUE to the packet buffer: the same as above just doubled. */
+
 extern inline void write_word_mode0(short ioaddr, unsigned short value)
 {
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    value >>= 4;
-    outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
-    value >>= 4;
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    value >>= 4;
-    outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+       outb(value & 0x0f, ioaddr + PAR_DATA);
+       value >>= 4;
+       outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+       value >>= 4;
+       outb(value & 0x0f, ioaddr + PAR_DATA);
+       value >>= 4;
+       outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
 }
 
 /*  EEPROM_Ctrl bits. */
index 7ebdfea5e7df49061a67f89e17249ba653a5a890..134bf569dfb9b37d5d7de1f6f9eaaae7ac0032f9 100644 (file)
@@ -122,7 +122,7 @@ static struct bpqdev {
        char   ethname[14];             /* ether device name */
        struct device *ethdev;          /* link to ethernet device */
        struct device axdev;            /* bpq device (bpq#) */
-       struct enet_statistics stats;   /* some statistics */
+       struct net_device_stats stats;  /* some statistics */
        char   dest_addr[6];            /* ether destination address */
        char   acpt_addr[6];            /* accept ether frames from this address only */
 } *bpq_devices = NULL;
@@ -331,7 +331,7 @@ static int bpq_xmit(struct sk_buff *skb, struct device *dev)
 /*
  *     Statistics
  */
-static struct enet_statistics *bpq_get_stats(struct device *dev)
+static struct net_device_stats *bpq_get_stats(struct device *dev)
 {
        struct bpqdev *bpq;
 
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
new file mode 100644 (file)
index 0000000..fcf8a64
--- /dev/null
@@ -0,0 +1,1182 @@
+/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
+/*
+       Written 1996 by Russell Nelson, with reference to skeleton.c
+       written 1993-1994 by Donald Becker.
+
+       This software may be used and distributed according to the terms
+       of the GNU Public License, incorporated herein by reference.
+
+       The author may be reached at nelson@crynwr.com, Crynwr
+       Software, 11 Grant St., Potsdam, NY 13676
+
+  Changelog:
+
+  Mike Cruse        : mcruse@cti-ltd.com
+                    : Changes for Linux 2.0 compatibility. 
+                    : Added dev_id parameter in net_interrupt(),
+                    : request_irq() and free_irq(). Just NULL for now.
+
+  Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
+                    : in net_open() and net_close() so kerneld would know
+                    : that the module is in use and wouldn't eject the 
+                    : driver prematurely.
+
+  Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
+                    : as an example. Disabled autoprobing in init_module(),
+                    : not a good thing to do to other devices while Linux
+                    : is running from all accounts.
+*/
+
+static char *version =
+"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
+
+/* ======================= configure the driver here ======================= */
+
+/* we also support 1.2.13 */
+#define SUPPORTS_1_2_13 0
+
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+
+/* ======================= end of configuration ======================= */
+
+
+/* Always include 'config.h' first in case the user wants to turn on
+   or override something. */
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define PRINTK(x) printk x
+
+/*
+  Sources:
+
+       Crynwr packet driver epktisa.
+
+       Crystal Semiconductor data sheets.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "cs89x0.h"
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int netcard_portlist[] =
+   { 0x300, 0x320, 0x340, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define NETCARD_IO_EXTENT      16
+
+/* Information that need to be kept for each board. */
+struct net_local {
+       struct net_device_stats stats;
+       int chip_type;          /* one of: CS8900, CS8920, CS8920M */
+       char chip_revision;     /* revision letter of the chip ('A'...) */
+       int send_cmd;           /* the propercommand used to send a packet. */
+       int auto_neg_cnf;
+       int adapter_cnf;
+       int isa_config;
+       int irq_map;
+       int rx_mode;
+       int curr_rx_cfg;
+        int linectl;
+        int send_underrun;      /* keep track of how many underruns in a row we get */
+       struct sk_buff *skb;
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int cs89x0_probe(struct device *dev);
+
+static int cs89x0_probe1(struct device *dev, int ioaddr);
+static int net_open(struct device *dev);
+static int     net_send_packet(struct sk_buff *skb, struct device *dev);
+#if SUPPORTS_1_2_13
+static void net_interrupt(int irq, struct pt_regs *regs);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#else
+static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void set_multicast_list(struct device *dev);
+#endif
+static void net_rx(struct device *dev);
+static int net_close(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
+static void reset_chip(struct device *dev);
+static int get_eeprom_data(struct device *dev, int off, int len, int *buffer);
+static int get_eeprom_cksum(int off, int len, int *buffer);
+static int set_mac_address(struct device *dev, void *addr);
+
+
+/* Example routines you must write ;->. */
+#define tx_done(dev) 1
+
+\f
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, allocate space for the device and return success
+   (detachable devices only).
+   */
+#ifdef HAVE_DEVLIST
+/* Support for a alternate probe manager, which will eliminate the
+   boilerplate below. */
+struct netdev_entry netcard_drv =
+{"netcard", cs89x0_probe1, NETCARD_IO_EXTENT, netcard_portlist};
+#else
+int
+cs89x0_probe(struct device *dev)
+{
+       int i;
+       int base_addr = dev ? dev->base_addr : 0;
+
+       if (base_addr > 0x1ff)          /* Check a single specified location. */
+               return cs89x0_probe1(dev, base_addr);
+       else if (base_addr != 0)        /* Don't probe at all. */
+               return ENXIO;
+
+       for (i = 0; netcard_portlist[i]; i++) {
+               int ioaddr = netcard_portlist[i];
+               if (check_region(ioaddr, NETCARD_IO_EXTENT))
+                       continue;
+               if (cs89x0_probe1(dev, ioaddr) == 0)
+                       return 0;
+       }
+       printk("cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
+       return ENODEV;
+}
+#endif
+
+int inline
+readreg(struct device *dev, int portno)
+{
+       outw(portno, dev->base_addr + ADD_PORT);
+       return inw(dev->base_addr + DATA_PORT);
+}
+
+void inline
+writereg(struct device *dev, int portno, int value)
+{
+       outw(portno, dev->base_addr + ADD_PORT);
+       outw(value, dev->base_addr + DATA_PORT);
+}
+
+
+int inline
+readword(struct device *dev, int portno)
+{
+       return inw(dev->base_addr + portno);
+}
+
+void inline
+writeword(struct device *dev, int portno, int value)
+{
+       outw(value, dev->base_addr + portno);
+}
+
+int
+wait_eeprom_ready(struct device *dev)
+{
+       int timeout = jiffies;
+       /* check to see if the EEPROM is ready, a timeout is used -
+          just in case EEPROM is ready when SI_BUSY in the
+          PP_SelfST is clear */
+       while(readreg(dev, PP_SelfST) & SI_BUSY)
+               if (jiffies - timeout >= 40)
+                       return -1;
+       return 0;
+}
+
+int
+get_eeprom_data(struct device *dev, int off, int len, int *buffer)
+{
+       int i;
+
+       if (net_debug > 3) printk("EEPROM data from %x for %x:\n",off,len);
+       for (i = 0; i < len; i++) {
+               if (wait_eeprom_ready(dev) < 0) return -1;
+               /* Now send the EEPROM read command and EEPROM location to read */
+               writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD);
+               if (wait_eeprom_ready(dev) < 0) return -1;
+               buffer[i] = readreg(dev, PP_EEData);
+               if (net_debug > 3) printk("%04x ", buffer[i]);
+       }
+       if (net_debug > 3) printk("\n");
+        return 0;
+}
+
+int
+get_eeprom_cksum(int off, int len, int *buffer)
+{
+       int i, cksum;
+
+       cksum = 0;
+       for (i = 0; i < len; i++)
+               cksum += buffer[i];
+       cksum &= 0xffff;
+       if (cksum == 0)
+               return 0;
+       return -1;
+}
+
+/* This is the real probe routine.  Linux has a history of friendly device
+   probes on the ISA bus.  A good device probes avoids doing writes, and
+   verifies that the correct device exists and functions.  */
+
+static int cs89x0_probe1(struct device *dev, int ioaddr)
+{
+       struct net_local *lp;
+       static unsigned version_printed = 0;
+       int i;
+       unsigned rev_type = 0;
+       int eeprom_buff[CHKSUM_LEN];
+
+       /* Initialize the device structure. */
+       if (dev->priv == NULL) {
+               dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+                memset(dev->priv, 0, sizeof(struct net_local));
+        }
+       lp = (struct net_local *)dev->priv;
+
+       /* if they give us an odd I/O address, then do ONE write to
+           the address port, to get it back to address zero, where we
+           expect to find the EISA signature word. */
+       if (ioaddr & 1) {
+               ioaddr &= ~1;
+               if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
+                       return ENODEV;
+               outw(PP_ChipID, ioaddr + ADD_PORT);
+       }
+
+       if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
+               return ENODEV;
+
+       /* Fill in the 'dev' fields. */
+       dev->base_addr = ioaddr;
+
+       /* get the chip type */
+       rev_type = readreg(dev, PRODUCT_ID_ADD);
+       lp->chip_type = rev_type &~ REVISON_BITS;
+       lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
+
+       /* Check the chip type and revision in order to set the correct send command
+       CS8920 revision C and CS8900 revision F can use the faster send. */
+       lp->send_cmd = TX_AFTER_381;
+       if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
+               lp->send_cmd = TX_NOW;
+       if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
+               lp->send_cmd = TX_NOW;
+
+       if (net_debug  &&  version_printed++ == 0)
+               printk(version);
+
+       printk("%s: cs89%c0%s rev %c found at %#3lx",
+              dev->name,
+              lp->chip_type==CS8900?'0':'2',
+              lp->chip_type==CS8920M?"M":"",
+              lp->chip_revision,
+              dev->base_addr);
+
+       reset_chip(dev);
+
+       /* First check to see if an EEPROM is attached*/
+       if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
+               printk("\ncs89x0: No EEPROM, relying on command line....\n");
+       else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
+               printk("\ncs89x0: EEPROM read failed, relying on command line.\n");
+        } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
+                printk("\ncs89x0: EEPROM checksum bad, relyong on command line\n");
+        } else {
+                /* get transmission control word  but keep the autonegotiation bits */
+                if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
+                /* Store adapter configuration */
+                if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
+                /* Store ISA configuration */
+                lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2];
+                /* store the initial memory base address */
+                dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
+                for (i = 0; i < ETH_ALEN/2; i++) {
+                        dev->dev_addr[i*2] = eeprom_buff[i];
+                        dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
+                }
+        }
+
+
+       printk(" media %s%s%s",
+              (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"",
+              (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"",
+              (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":"");
+
+       lp->irq_map = 0xffff;
+
+       /* If this is a CS8900 then no pnp soft */
+       if (lp->chip_type != CS8900 &&
+           /* Check if the ISA IRQ has been set  */
+               (i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
+                (i != 0 && i < CS8920_NO_INTS))) {
+               if (!dev->irq)
+                       dev->irq = i;
+       } else {
+               i = lp->isa_config & INT_NO_MASK;
+               if (lp->chip_type == CS8900) {
+                       /* the table that follows is dependent upon how you wired up your cs8900
+                        * in your system.  The table is the same as the cs8900 engineering demo
+                        * board.  irq_map also depends on the contents of the table.  Also see
+                        * write_irq, which is the reverse mapping of the table below. */
+                       switch(i) {
+                       case 0: i = 10; break;
+                       case 1: i = 11; break;
+                       case 2: i = 12; break;
+                       case 3: i =  5; break;
+                       default: printk("\ncs89x0: bug: isa_config is %d\n", i);
+                       }
+                       lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
+               } else {
+                       int irq_map_buff[IRQ_MAP_LEN/2];
+
+                       if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
+                                           IRQ_MAP_LEN/2,
+                                           irq_map_buff) >= 0) {
+                               if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
+                                       lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1] << 8);
+                       }
+               }
+               if (!dev->irq)
+                       dev->irq = i;
+       }
+
+       printk(" IRQ %d", dev->irq);
+
+
+       /* print the ethernet address. */
+       for (i = 0; i < ETH_ALEN; i++)
+               printk(" %2.2x", dev->dev_addr[i]);
+
+       /* Grab the region so we can find another board if autoIRQ fails. */
+       request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0");
+
+       dev->open               = net_open;
+       dev->stop               = net_close;
+       dev->hard_start_xmit = net_send_packet;
+       dev->get_stats  = net_get_stats;
+       dev->set_multicast_list = &set_multicast_list;
+       dev->set_mac_address = &set_mac_address;
+
+       /* Fill in the fields of the device structure with ethernet values. */
+       ether_setup(dev);
+
+       printk("\n");
+       return 0;
+}
+
+
+\f
+void
+reset_chip(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int reset_start_time;
+
+       writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
+
+       /* wait 30 ms */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 3;
+       schedule();
+
+       if (lp->chip_type != CS8900) {
+               /* Hardware problem requires PNP registers to be reconfigured after a reset */
+               outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT);
+               outb(dev->irq, ioaddr + DATA_PORT);
+               outb(0,      ioaddr + DATA_PORT + 1);
+
+               outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT);
+               outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT);
+               outb((dev->mem_start >> 24) & 0xff,   ioaddr + DATA_PORT + 1);
+       }
+       /* Wait until the chip is reset */
+       reset_start_time = jiffies;
+       while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
+               ;
+}
+
+\f
+void
+control_dc_dc(struct device *dev, int on_not_off)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned int selfcontrol;
+       int timenow = jiffies;
+       /* control the DC to DC convertor in the SelfControl register.  */
+
+       selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
+       if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
+               selfcontrol |= HCB1;
+       else
+               selfcontrol &= ~HCB1;
+       writereg(dev, PP_SelfCTL, selfcontrol);
+
+       /* Wait for the DC/DC converter to power up - 500ms */
+       while (jiffies - timenow < 100)
+               ;
+
+}
+
+static int
+detect_tp(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int timenow = jiffies;
+
+       if (net_debug > 1) printk("%s: Attempting TP\n", dev->name);
+
+        /* If connected to another full duplex capable 10-Base-T card the link pulses
+           seem to be lost when the auto detect bit in the LineCTL is set.
+           To overcome this the auto detect bit will be cleared whilst testing the
+           10-Base-T interface.  This would not be necessary for the sparrow chip but
+           is simpler to do it anyway. */
+       writereg(dev, PP_LineCTL, lp->linectl &~ AUI_ONLY);
+       control_dc_dc(dev, 0);
+
+        /* Delay for the hardware to work out if the TP cable is present - 150ms */
+       for (timenow = jiffies; jiffies - timenow < 15; )
+                ;
+       if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
+               return 0;
+
+       if (lp->chip_type != CS8900) {
+
+               writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);
+
+               if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
+                       printk("%s: negotiating duplex...\n",dev->name);
+                       while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
+                               if (jiffies - timenow > 4000) {
+                                       printk("**** Full / half duplex auto-negotiation timed out ****\n");
+                                       break;
+                               }
+                       }
+               }
+               if (readreg(dev, PP_AutoNegST) & FDX_ACTIVE)
+                       printk("%s: using full duplex\n", dev->name);
+               else
+                       printk("%s: using half duplex\n", dev->name);
+       }
+
+       return A_CNF_MEDIA_10B_T;
+}
+
+/* send a test packet - return true if carrier bits are ok */
+int
+send_test_pkt(struct device *dev)
+{
+       int ioaddr = dev->base_addr;
+       char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
+                                0, 46, /* A 46 in network order */
+                                0, 0, /* DSAP=0 & SSAP=0 fields */
+                                0xf3, 0 /* Control (Test Req + P bit set) */ };
+       long timenow = jiffies;
+
+       writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
+
+       memcpy(test_packet,          dev->dev_addr, ETH_ALEN);
+       memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN);
+
+        outw(TX_AFTER_ALL, ioaddr + TX_CMD_PORT);
+        outw(ETH_ZLEN, ioaddr + TX_LEN_PORT);
+
+       /* Test to see if the chip has allocated memory for the packet */
+       while (jiffies - timenow < 5)
+               if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
+                       break;
+       if (jiffies - timenow >= 5)
+               return 0;       /* this shouldn't happen */
+
+       /* Write the contents of the packet */
+       if (dev->mem_start) {
+               memcpy((void *)dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN);
+       } else {
+               outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
+       }
+
+       if (net_debug > 1) printk("Sending test packet ");
+       /* wait a couple of jiffies for packet to be received */
+       for (timenow = jiffies; jiffies - timenow < 3; )
+                ;
+        if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
+                if (net_debug > 1) printk("succeeded\n");
+                return 1;
+        }
+       if (net_debug > 1) printk("failed\n");
+       return 0;
+}
+
+
+int
+detect_aui(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name);
+       control_dc_dc(dev, 0);
+
+       writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
+
+       if (send_test_pkt(dev))
+               return A_CNF_MEDIA_AUI;
+       else
+               return 0;
+}
+
+int
+detect_bnc(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name);
+       control_dc_dc(dev, 1);
+
+       writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
+
+       if (send_test_pkt(dev))
+               return A_CNF_MEDIA_10B_2;
+       else
+               return 0;
+}
+
+\f
+void
+write_irq(struct device *dev, int chip_type, int irq)
+{
+       int i;
+
+       if (chip_type == CS8900) {
+               switch(irq) {
+               case 10: i = 0; break;
+               case 11: i = 1; break;
+               case 12: i = 2; break;
+               case 5: i =  3; break;
+               default: i = 3; break;
+               }
+               writereg(dev, PP_CS8900_ISAINT, i);
+       } else {
+               writereg(dev, PP_CS8920_ISAINT, irq);
+       }
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+   */
+static int
+net_open(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int result = 0;
+       int i;
+
+       if (dev->irq < 2) {
+               /* Allow interrupts to be generated by the chip */
+               writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+               for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {
+#if SUPPORTS_1_2_13
+                       if (request_irq (i, NULL, 0, "bogus") != -EBUSY) {
+#else
+                       if (request_irq (i, NULL, 0, "bogus", NULL) != -EBUSY) {
+#endif
+#if 0
+                               /* Twinkle the interrupt, and check if it's seen. */
+                               autoirq_setup(0);
+                               write_irq(dev, lp->chip_type, i);
+                               writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
+                               if (i == autoirq_report(0)       /* It's a good IRQ line! */
+                                   && request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0") == 0)
+                                       break;
+#else
+                               write_irq(dev, lp->chip_type, i);
+                               writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
+#if SUPPORTS_1_2_13
+                               if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0") == 0)
+#else
+                               if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", NULL) == 0)
+#endif
+                                       break;
+#endif
+                       }
+               }
+
+
+               if (i >= CS8920_NO_INTS) {
+                       writereg(dev, PP_BusCTL, 0);    /* disable interrupts. */
+                       return -EAGAIN;
+               }
+       } else {
+               if (((1 << dev->irq) & lp->irq_map) == 0) {
+                       printk("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
+                               dev->name, dev->irq, lp->irq_map);
+                       return -EAGAIN;
+               }
+               writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+               write_irq(dev, lp->chip_type, dev->irq);
+#if SUPPORTS_1_2_13
+               if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0")) {
+#else
+               if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", NULL)) {
+#endif
+                       return -EAGAIN;
+               }
+       }
+
+       irq2dev_map[dev->irq] = dev;
+
+       /* set the Ethernet address */
+       for (i=0; i < ETH_ALEN/2; i++)
+               writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+       /* while we're testing the interface, leave interrupts disabled */
+       writereg(dev, PP_BusCTL, MEMORY_ON);
+
+       /* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */
+       if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
+                lp->linectl = LOW_RX_SQUELCH;
+       else
+                lp->linectl = 0;
+
+        /* check to make sure that they have the "right" hardware available */
+       switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
+       case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break;
+       case A_CNF_MEDIA_AUI:   result = lp->adapter_cnf & A_CNF_AUI; break;
+       case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
+        default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
+        }
+        if (!result) {
+                printk("%s: EEPROM is configured for unavailable media\n", dev->name);
+        release_irq:
+                writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
+#if SUPPORTS_1_2_13
+                free_irq(dev->irq);
+#else
+                free_irq(dev->irq, NULL);
+#endif
+                irq2dev_map[dev->irq] = 0;
+               return -EAGAIN;
+       }
+
+        /* set the hardware to the configured choice */
+       switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
+       case A_CNF_MEDIA_10B_T:
+                result = detect_tp(dev);
+                if (!result) printk("%s: 10Base-T (RJ-45) has no cable\n", dev->name);
+                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                        result = A_CNF_MEDIA_10B_T; /* Yes! I don't care if I see a link pulse */
+               break;
+       case A_CNF_MEDIA_AUI:
+                result = detect_aui(dev);
+                if (!result) printk("%s: 10Base-5 (AUI) has no cable\n", dev->name);
+                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                        result = A_CNF_MEDIA_AUI; /* Yes! I don't care if I see a carrrier */
+               break;
+       case A_CNF_MEDIA_10B_2:
+                result = detect_bnc(dev);
+                if (!result) printk("%s: 10Base-2 (BNC) has no cable\n", dev->name);
+                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                        result = A_CNF_MEDIA_10B_2; /* Yes! I don't care if I can xmit a packet */
+               break;
+       case A_CNF_MEDIA_AUTO:
+               writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);
+               if (lp->adapter_cnf & A_CNF_10B_T)
+                       if ((result = detect_tp(dev)) != 0)
+                               break;
+               if (lp->adapter_cnf & A_CNF_AUI)
+                       if ((result = detect_aui(dev)) != 0)
+                               break;
+               if (lp->adapter_cnf & A_CNF_10B_2)
+                       if ((result = detect_bnc(dev)) != 0)
+                               break;
+               printk("%s: no media detected\n", dev->name);
+                goto release_irq;
+       }
+       switch(result) {
+       case 0: printk("%s: no network cable attached to configured media\n", dev->name);
+                goto release_irq;
+       case A_CNF_MEDIA_10B_T: printk("%s: using 10Base-T (RJ-45)\n", dev->name);break;
+       case A_CNF_MEDIA_AUI:   printk("%s: using 10Base-5 (AUI)\n", dev->name);break;
+       case A_CNF_MEDIA_10B_2: printk("%s: using 10Base-2 (BNC)\n", dev->name);break;
+       default: printk("%s: unexpected result was %x\n", dev->name, result); goto release_irq;
+       }
+
+       /* Turn on both receive and transmit operations */
+       writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
+
+       /* Receive only error free packets addressed to this card */
+       lp->rx_mode = 0;
+       writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
+
+       lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
+       if (lp->isa_config & STREAM_TRANSFER)
+               lp->curr_rx_cfg |= RX_STREAM_ENBL;
+
+       writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
+
+       writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
+              TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
+
+       writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
+                TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
+
+       /* now that we've got our act together, enable everything */
+       writereg(dev, PP_BusCTL, ENABLE_IRQ
+                 );
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+        MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+       if (dev->tbusy) {
+               /* If we get here, some higher level has decided we are broken.
+                  There should really be a "kick me" function call instead. */
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 5)
+                       return 1;
+               if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+                          tx_done(dev) ? "IRQ conflict" : "network cable problem");
+               /* Try to restart the adaptor. */
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+       }
+
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself. */
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+
+       /* Block a timer-based transmit from overlapping.  This could better be
+          done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk("%s: Transmitter access conflict.\n", dev->name);
+       else {
+               struct net_local *lp = (struct net_local *)dev->priv;
+               short ioaddr = dev->base_addr;
+               unsigned long flags;
+
+               if (net_debug > 3)printk("%s: sent %ld byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+               /* keep the upload from being interrupted, since we
+                   ask the chip to start transmitting before the
+                   whole packet has been completely uploaded. */
+               save_flags(flags);
+               cli();
+
+               /* initiate a transmit sequence */
+               outw(lp->send_cmd, ioaddr + TX_CMD_PORT);
+               outw(skb->len, ioaddr + TX_LEN_PORT);
+
+               /* Test to see if the chip has allocated memory for the packet */
+               if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+                       /* Gasp!  It hasn't.  But that shouldn't happen since
+                          we're waiting for TxOk, so return 1 and requeue this packet. */
+                       restore_flags(flags);
+                       return 1;
+               }
+
+               /* Write the contents of the packet */
+                outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+
+               restore_flags(flags);
+               dev->trans_start = jiffies;
+       }
+       dev_kfree_skb (skb, FREE_WRITE);
+
+       return 0;
+}
+\f
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void
+#if SUPPORTS_1_2_13
+net_interrupt(int irq, struct pt_regs * regs)
+#else
+net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+#endif
+{
+       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       struct net_local *lp;
+       int ioaddr, status;
+
+       if (dev == NULL) {
+               printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+       if (dev->interrupt)
+               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+       dev->interrupt = 1;
+
+       ioaddr = dev->base_addr;
+       lp = (struct net_local *)dev->priv;
+
+       /* we MUST read all the events out of the ISQ, otherwise we'll never
+           get interrupted again.  As a consequence, we can't have any limit
+           on the number of times we loop in the interrupt handler.  The
+           hardware guarantees that eventually we'll run out of events.  Of
+           course, if you're on a slow machine, and packets are arriving
+           faster than you can read them off, you're screwed.  Hasta la
+           vista, baby!  */
+       while ((status = readword(dev, ISQ_PORT))) {
+               if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
+               switch(status & ISQ_EVENT_MASK) {
+               case ISQ_RECEIVER_EVENT:
+                       /* Got a packet(s). */
+                       net_rx(dev);
+                       break;
+               case ISQ_TRANSMITTER_EVENT:
+                       lp->stats.tx_packets++;
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);        /* Inform upper layers. */
+                       if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+                       if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+                       if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+                       if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
+                       if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+                       break;
+               case ISQ_BUFFER_EVENT:
+                       if (status & READY_FOR_TX) {
+                               /* we tried to transmit a packet earlier,
+                                   but inexplicably ran out of buffers.
+                                   That shouldn't happen since we only ever
+                                   load one packet.  Shrug.  Do the right
+                                   thing anyway. */
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);        /* Inform upper layers. */
+                       }
+                       if (status & TX_UNDERRUN) {
+                               if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
+                                lp->send_underrun++;
+                                if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
+                                else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
+                        }
+                       break;
+               case ISQ_RX_MISS_EVENT:
+                       lp->stats.rx_missed_errors += (status >>6);
+                       break;
+               case ISQ_TX_COL_EVENT:
+                       lp->stats.collisions += (status >>6);
+                       break;
+               }
+       }
+       dev->interrupt = 0;
+       return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+       struct sk_buff *skb;
+       int status, length;
+
+       status = inw(ioaddr + RX_FRAME_PORT);
+       length = inw(ioaddr + RX_FRAME_PORT);
+       if ((status & RX_OK) == 0) {
+               lp->stats.rx_errors++;
+               if (status & RX_RUNT) lp->stats.rx_length_errors++;
+               if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
+               if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+                       /* per str 172 */
+                       lp->stats.rx_crc_errors++;
+               if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+               return;
+       }
+
+       /* Malloc up new buffer. */
+       skb = alloc_skb(length, GFP_ATOMIC);
+       if (skb == NULL) {
+               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+               lp->stats.rx_dropped++;
+               return;
+       }
+       skb->len = length;
+       skb->dev = dev;
+
+        insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
+       if (length & 1)
+               skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT);
+
+       if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
+                                 dev->name, length,
+                                 (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+#if !SUPPORTS_1_2_13
+        skb->protocol=eth_type_trans(skb,dev);
+#endif
+       netif_rx(skb);
+       lp->stats.rx_packets++;
+       return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+net_close(struct device *dev)
+{
+
+       writereg(dev, PP_RxCFG, 0);
+       writereg(dev, PP_TxCFG, 0);
+       writereg(dev, PP_BufCFG, 0);
+       writereg(dev, PP_BusCTL, 0);
+
+       dev->start = 0;
+
+#if SUPPORTS_1_2_13
+       free_irq(dev->irq);
+#else
+       free_irq(dev->irq, NULL);
+#endif
+
+       irq2dev_map[dev->irq] = 0;
+
+       /* Update the statistics here. */
+
+        MOD_DEC_USE_COUNT;
+       return 0;
+
+}
+
+/* Get the current statistics. This may be called with the card open or
+   closed. */
+static struct net_device_stats *
+net_get_stats(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       cli();
+       /* Update the statistics from the device registers. */
+       lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+       lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+       sti();
+
+       return &lp->stats;
+}
+
+#if SUPPORTS_1_2_13
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1     Promiscuous mode, receive all packets
+   num_addrs == 0      Normal mode, clear multicast list
+   num_addrs > 0       Multicast mode, receive normal and MC packets, and do
+                       best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if (num_addrs == 0)
+               lp->rx_mode = 0;
+       else if (num_addrs > 0)
+               lp->rx_mode = RX_MULTCAST_ACCEPT;
+       else if (num_addrs == -1)
+               lp->rx_mode = RX_ALL_ACCEPT;
+
+       writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+       /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
+       writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
+            (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+
+}
+#else
+static void set_multicast_list(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if(dev->flags&IFF_PROMISC)
+       {
+               lp->rx_mode = RX_ALL_ACCEPT;
+       }
+       else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
+       {
+               /* The multicast-accept list is initialized to accept-all, and we
+                  rely on higher-level filtering for now. */
+               lp->rx_mode = RX_MULTCAST_ACCEPT;
+       } 
+       else
+               lp->rx_mode = 0;
+
+       writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+       /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
+       writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
+            (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+}
+#endif
+
+
+static int
+set_mac_address(struct device *dev, void *addr)
+{
+       int i;
+       if (dev->start)
+               return -EBUSY;
+       printk("%s: Setting MAC address to ", dev->name);
+       for (i = 0; i < 6; i++)
+               printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+       printk(".\n");
+       /* set the Ethernet address */
+       for (i=0; i < ETH_ALEN/2; i++)
+               writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+       return 0;
+}
+#ifdef MODULE
+#if SUPPORTS_1_2_13
+char kernel_version[] = UTS_RELEASE;
+#endif
+static char namespace[16] = "";
+static struct device dev_cs89x0 = {
+        NULL,
+        0, 0, 0, 0,
+        0, 0,
+        0, 0, 0, NULL, NULL };
+
+int io=0;
+int irq=0;
+#endif
+#ifdef MODULE
+int debug=1;
+char *media="auto";
+char *duplex="f";
+
+/*
+* media=t             - specify media type
+   or media=2
+   or media=aui
+   or medai=auto
+* duplex=f            - specify forced half/full/autonegotiate duplex
+   or duplex=h
+   or duplex=auto
+* debug=#             - debug level
+
+
+* Default Chip Configuration:
+  * DMA Burst = enabled
+  * IOCHRDY Enabled = enabled
+    * UseSA = enabled
+    * CS8900 defaults to half-duplex if not specified on command-line
+    * CS8920 defaults to autoneg if not specified on command-line
+    * Use reset defaults for other config parameters
+
+* Assumptions:
+  * media type specified is supported (circuitry is present)
+  * if memory address is > 1MB, then required mem decode hw is present
+  * if 10B-2, then agent other than driver will enable DC/DC converter
+    (hw or software util)
+
+
+*/
+
+int
+init_module(void)
+{
+       struct net_local *lp;
+
+       net_debug = debug;
+        dev_cs89x0.name = namespace;
+       dev_cs89x0.irq = irq;
+       dev_cs89x0.base_addr = io;
+        dev_cs89x0.init = cs89x0_probe;
+        dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+       memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
+       lp = (struct net_local *)dev_cs89x0.priv;
+
+        /* boy, they'd better get these right */
+        if (!strcmp(media, "rj45"))
+               lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
+       if (!strcmp(media, "aui"))
+               lp->adapter_cnf = A_CNF_MEDIA_AUI   | A_CNF_AUI;
+       if (!strcmp(media, "bnc"))
+               lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2;
+
+        if (!strcmp(duplex, "auto"))
+               lp->auto_neg_cnf = AUTO_NEG_ENABLE;
+
+        if (io == 0)  {
+                printk(KERN_NOTICE "cs89x0.c: Module autoprobing not allowed.\n");
+                printk(KERN_NOTICE "cs89x0.c: Append io=0xNNN\n");
+                return -EPERM;
+        }
+        if (register_netdev(&dev_cs89x0) != 0) {
+                printk(KERN_WARNING "cs89x0.c: No card found at 0x%x\n", io);
+                return -ENXIO;
+        }
+       return 0;
+}
+
+void
+cleanup_module(void)
+{
+
+#endif
+#ifdef MODULE
+       outw(0, dev_cs89x0.base_addr + ADD_PORT);
+#endif
+#ifdef MODULE
+
+        if (dev_cs89x0.priv != NULL) {
+                /* Free up the private structure, or leak memory :-)  */
+                kfree(dev_cs89x0.priv);
+                dev_cs89x0.priv = NULL;        /* gets re-allocated by cs89x0_probe1 */
+                /* If we don't do this, we can't re-insmod it later. */
+                release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT);
+                unregister_netdev(&dev_cs89x0);
+        }
+}
+#endif /* MODULE */
+\f
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS -c cs89x0.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ *
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
new file mode 100644 (file)
index 0000000..d988bdc
--- /dev/null
@@ -0,0 +1,456 @@
+/*  Copyright, 1988-1992, Russell Nelson, Crynwr Software
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, version 1.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   */
+
+#define PP_ChipID 0x0000       /* offset   0h -> Corp -ID              */
+                               /* offset   2h -> Model/Product Number  */
+                               /* offset   3h -> Chip Revision Number  */
+
+#define PP_ISAIOB 0x0020       /*  IO base address */
+#define PP_CS8900_ISAINT 0x0022        /*  ISA interrupt select */
+#define PP_CS8920_ISAINT 0x0370        /*  ISA interrupt select */
+#define PP_CS8900_ISADMA 0x0024        /*  ISA Rec DMA channel */
+#define PP_CS8920_ISADMA 0x0374        /*  ISA Rec DMA channel */
+#define PP_ISASOF 0x0026       /*  ISA DMA offset */
+#define PP_DmaFrameCnt 0x0028  /*  ISA DMA Frame count */
+#define PP_DmaByteCnt 0x002A   /*  ISA DMA Byte count */
+#define PP_CS8900_ISAMemB 0x002C       /*  Memory base */
+#define PP_CS8920_ISAMemB 0x0348 /*  */
+
+#define PP_ISABootBase 0x0030  /*  Boot Prom base  */
+#define PP_ISABootMask 0x0034  /*  Boot Prom Mask */
+
+/* EEPROM data and command registers */
+#define PP_EECMD 0x0040                /*  NVR Interface Command register */
+#define PP_EEData 0x0042       /*  NVR Interface Data Register */
+#define PP_DebugReg 0x0044     /*  Debug Register */
+
+#define PP_RxCFG 0x0102                /*  Rx Bus config */
+#define PP_RxCTL 0x0104                /*  Receive Control Register */
+#define PP_TxCFG 0x0106                /*  Transmit Config Register */
+#define PP_TxCMD 0x0108                /*  Transmit Command Register */
+#define PP_BufCFG 0x010A       /*  Bus configuration Register */
+#define PP_LineCTL 0x0112      /*  Line Config Register */
+#define PP_SelfCTL 0x0114      /*  Self Command Register */
+#define PP_BusCTL 0x0116       /*  ISA bus control Register */
+#define PP_TestCTL 0x0118      /*  Test Register */
+#define PP_AutoNegCTL 0x011C   /*  Auto Negotiation Ctrl */
+
+#define PP_ISQ 0x0120          /*  Interrupt Status */
+#define PP_RxEvent 0x0124      /*  Rx Event Register */
+#define PP_TxEvent 0x0128      /*  Tx Event Register */
+#define PP_BufEvent 0x012C     /*  Bus Event Register */
+#define PP_RxMiss 0x0130       /*  Receive Miss Count */
+#define PP_TxCol 0x0132                /*  Transmit Collision Count */
+#define PP_LineST 0x0134       /*  Line State Register */
+#define PP_SelfST 0x0136       /*  Self State register */
+#define PP_BusST 0x0138                /*  Bus Status */
+#define PP_TDR 0x013C          /*  Time Domain Reflectometry */
+#define PP_AutoNegST 0x013E    /*  Auto Neg Status */
+#define PP_TxCommand 0x0144    /*  Tx Command */
+#define PP_TxLength 0x0146     /*  Tx Length */
+#define PP_LAF 0x0150          /*  Hash Table */
+#define PP_IA 0x0158           /*  Physical Address Register */
+
+#define PP_RxStatus 0x0400     /*  Receive start of frame */
+#define PP_RxLength 0x0402     /*  Receive Length of frame */
+#define PP_RxFrame 0x0404      /*  Receive frame pointer */
+#define PP_TxFrame 0x0A00      /*  Transmit frame pointer */
+
+/*  Primary I/O Base Address. If no I/O base is supplied by the user, then this */
+/*  can be used as the default I/O base to access the PacketPage Area. */
+#define DEFAULTIOBASE 0x0300
+#define FIRST_IO 0x020C                /*  First I/O port to check */
+#define LAST_IO 0x037C         /*  Last I/O port to check (+10h) */
+#define ADD_MASK 0x3000                /*  Mask it use of the ADD_PORT register */
+#define ADD_SIG 0x3000         /*  Expected ID signature */
+
+#define CHIP_EISA_ID_SIG 0x630E   /*  Product ID Code for Crystal Chip (CS8900 spec 4.3) */
+
+#ifdef IBMEIPKT
+#define EISA_ID_SIG 0x4D24     /*  IBM */
+#define PART_NO_SIG 0x1010     /*  IBM */
+#define MONGOOSE_BIT 0x0000    /*  IBM */
+#else
+#define EISA_ID_SIG 0x630E     /*  PnP Vendor ID (same as chip id for Crystal board) */
+#define PART_NO_SIG 0x4000     /*  ID code CS8920 board (PnP Vendor Product code) */
+#define MONGOOSE_BIT 0x2000    /*  PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */
+#endif
+
+#define PRODUCT_ID_ADD 0x0002   /*  Address of product ID */
+
+/*  Mask to find out the types of  registers */
+#define REG_TYPE_MASK 0x001F
+
+/*  Eeprom Commands */
+#define ERSE_WR_ENBL 0x00F0
+#define ERSE_WR_DISABLE 0x0000
+
+/*  Defines Control/Config register quintuplet numbers */
+#define RX_BUF_CFG 0x0003
+#define RX_CONTROL 0x0005
+#define TX_CFG 0x0007
+#define TX_COMMAND 0x0009
+#define BUF_CFG 0x000B
+#define LINE_CONTROL 0x0013
+#define SELF_CONTROL 0x0015
+#define BUS_CONTROL 0x0017
+#define TEST_CONTROL 0x0019
+
+/*  Defines Status/Count registers quintuplet numbers */
+#define RX_EVENT 0x0004
+#define TX_EVENT 0x0008
+#define BUF_EVENT 0x000C
+#define RX_MISS_COUNT 0x0010
+#define TX_COL_COUNT 0x0012
+#define LINE_STATUS 0x0014
+#define SELF_STATUS 0x0016
+#define BUS_STATUS 0x0018
+#define TDR 0x001C
+
+/* PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition -  Read/write */
+#define SKIP_1 0x0040
+#define RX_STREAM_ENBL 0x0080
+#define RX_OK_ENBL 0x0100
+#define RX_DMA_ONLY 0x0200
+#define AUTO_RX_DMA 0x0400
+#define BUFFER_CRC 0x0800
+#define RX_CRC_ERROR_ENBL 0x1000
+#define RX_RUNT_ENBL 0x2000
+#define RX_EXTRA_DATA_ENBL 0x4000
+
+/* PP_RxCTL - Receive Control bit definition - Read/write */
+#define RX_IA_HASH_ACCEPT 0x0040
+#define RX_PROM_ACCEPT 0x0080
+#define RX_OK_ACCEPT 0x0100
+#define RX_MULTCAST_ACCEPT 0x0200
+#define RX_IA_ACCEPT 0x0400
+#define RX_BROADCAST_ACCEPT 0x0800
+#define RX_BAD_CRC_ACCEPT 0x1000
+#define RX_RUNT_ACCEPT 0x2000
+#define RX_EXTRA_DATA_ACCEPT 0x4000
+#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT)
+/*  Default receive mode - individually addressed, broadcast, and error free */
+#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT)
+
+/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */
+#define TX_LOST_CRS_ENBL 0x0040
+#define TX_SQE_ERROR_ENBL 0x0080
+#define TX_OK_ENBL 0x0100
+#define TX_LATE_COL_ENBL 0x0200
+#define TX_JBR_ENBL 0x0400
+#define TX_ANY_COL_ENBL 0x0800
+#define TX_16_COL_ENBL 0x8000
+
+/* PP_TxCMD - Transmit Command bit definition - Read-only */
+#define TX_START_4_BYTES 0x0000
+#define TX_START_64_BYTES 0x0040
+#define TX_START_128_BYTES 0x0080
+#define TX_START_ALL_BYTES 0x00C0
+#define TX_FORCE 0x0100
+#define TX_ONE_COL 0x0200
+#define TX_TWO_PART_DEFF_DISABLE 0x0400
+#define TX_NO_CRC 0x1000
+#define TX_RUNT 0x2000
+
+/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */
+#define GENERATE_SW_INTERRUPT 0x0040
+#define RX_DMA_ENBL 0x0080
+#define READY_FOR_TX_ENBL 0x0100
+#define TX_UNDERRUN_ENBL 0x0200
+#define RX_MISS_ENBL 0x0400
+#define RX_128_BYTE_ENBL 0x0800
+#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000
+#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000
+#define RX_DEST_MATCH_ENBL 0x8000
+
+/* PP_LineCTL - Line Control bit definition - Read/write */
+#define SERIAL_RX_ON 0x0040
+#define SERIAL_TX_ON 0x0080
+#define AUI_ONLY 0x0100
+#define AUTO_AUI_10BASET 0x0200
+#define MODIFIED_BACKOFF 0x0800
+#define NO_AUTO_POLARITY 0x1000
+#define TWO_PART_DEFDIS 0x2000
+#define LOW_RX_SQUELCH 0x4000
+
+/* PP_SelfCTL - Software Self Control bit definition - Read/write */
+#define POWER_ON_RESET 0x0040
+#define SW_STOP 0x0100
+#define SLEEP_ON 0x0200
+#define AUTO_WAKEUP 0x0400
+#define HCB0_ENBL 0x1000
+#define HCB1_ENBL 0x2000
+#define HCB0 0x4000
+#define HCB1 0x8000
+
+/* PP_BusCTL - ISA Bus Control bit definition - Read/write */
+#define RESET_RX_DMA 0x0040
+#define MEMORY_ON 0x0400
+#define DMA_BURST_MODE 0x0800
+#define IO_CHANNEL_READY_ON 0x1000
+#define RX_DMA_SIZE_64K 0x2000
+#define ENABLE_IRQ 0x8000
+
+/* PP_TestCTL - Test Control bit definition - Read/write */
+#define LINK_OFF 0x0080
+#define ENDEC_LOOPBACK 0x0200
+#define AUI_LOOPBACK 0x0400
+#define BACKOFF_OFF 0x0800
+#define FAST_TEST 0x8000
+
+/* PP_RxEvent - Receive Event Bit definition - Read-only */
+#define RX_IA_HASHED 0x0040
+#define RX_DRIBBLE 0x0080
+#define RX_OK 0x0100
+#define RX_HASHED 0x0200
+#define RX_IA 0x0400
+#define RX_BROADCAST 0x0800
+#define RX_CRC_ERROR 0x1000
+#define RX_RUNT 0x2000
+#define RX_EXTRA_DATA 0x4000
+
+#define HASH_INDEX_MASK 0x0FC00
+
+/* PP_TxEvent - Transmit Event Bit definition - Read-only */
+#define TX_LOST_CRS 0x0040
+#define TX_SQE_ERROR 0x0080
+#define TX_OK 0x0100
+#define TX_LATE_COL 0x0200
+#define TX_JBR 0x0400
+#define TX_16_COL 0x8000
+#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS)
+#define TX_COL_COUNT_MASK 0x7800
+
+/* PP_BufEvent - Buffer Event Bit definition - Read-only */
+#define SW_INTERRUPT 0x0040
+#define RX_DMA 0x0080
+#define READY_FOR_TX 0x0100
+#define TX_UNDERRUN 0x0200
+#define RX_MISS 0x0400
+#define RX_128_BYTE 0x0800
+#define TX_COL_OVRFLW 0x1000
+#define RX_MISS_OVRFLW 0x2000
+#define RX_DEST_MATCH 0x8000
+
+/* PP_LineST - Ethernet Line Status bit definition - Read-only */
+#define LINK_OK 0x0080
+#define AUI_ON 0x0100
+#define TENBASET_ON 0x0200
+#define POLARITY_OK 0x1000
+#define CRS_OK 0x4000
+
+/* PP_SelfST - Chip Software Status bit definition */
+#define ACTIVE_33V 0x0040
+#define INIT_DONE 0x0080
+#define SI_BUSY 0x0100
+#define EEPROM_PRESENT 0x0200
+#define EEPROM_OK 0x0400
+#define EL_PRESENT 0x0800
+#define EE_SIZE_64 0x1000
+
+/* PP_BusST - ISA Bus Status bit definition */
+#define TX_BID_ERROR 0x0080
+#define READY_FOR_TX_NOW 0x0100
+
+/* PP_AutoNegCTL - Auto Negotiation Control bit definition */
+#define RE_NEG_NOW 0x0040
+#define ALLOW_FDX 0x0080
+#define AUTO_NEG_ENABLE 0x0100
+#define NLP_ENABLE 0x0200
+#define FORCE_FDX 0x8000
+#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE)
+#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW)
+
+/* PP_AutoNegST - Auto Negotiation Status bit definition */
+#define AUTO_NEG_BUSY 0x0080
+#define FLP_LINK 0x0100
+#define FLP_LINK_GOOD 0x0800
+#define LINK_FAULT 0x1000
+#define HDX_ACTIVE 0x4000
+#define FDX_ACTIVE 0x8000
+
+/*  The following block defines the ISQ event types */
+#define ISQ_RECEIVER_EVENT 0x04
+#define ISQ_TRANSMITTER_EVENT 0x08
+#define ISQ_BUFFER_EVENT 0x0c
+#define ISQ_RX_MISS_EVENT 0x10
+#define ISQ_TX_COL_EVENT 0x12
+
+#define ISQ_EVENT_MASK 0x003F   /*  ISQ mask to find out type of event */
+#define ISQ_HIST 16            /*  small history buffer */
+#define AUTOINCREMENT 0x8000   /*  Bit mask to set bit-15 for autoincrement */
+
+#define TXRXBUFSIZE 0x0600
+#define RXDMABUFSIZE 0x8000
+#define RXDMASIZE 0x4000
+#define TXRX_LENGTH_MASK 0x07FF
+
+/*  rx options bits */
+#define RCV_WITH_RXON  1       /*  Set SerRx ON */
+#define RCV_COUNTS     2       /*  Use Framecnt1 */
+#define RCV_PONG       4       /*  Pong respondent */
+#define RCV_DONG       8       /*  Dong operation */
+#define RCV_POLLING    0x10    /*  Poll RxEvent */
+#define RCV_ISQ                0x20    /*  Use ISQ, int */
+#define RCV_AUTO_DMA   0x100   /*  Set AutoRxDMAE */
+#define RCV_DMA                0x200   /*  Set RxDMA only */
+#define RCV_DMA_ALL    0x400   /*  Copy all DMA'ed */
+#define RCV_FIXED_DATA 0x800   /*  Every frame same */
+#define RCV_IO         0x1000  /*  Use ISA IO only */
+#define RCV_MEMORY     0x2000  /*  Use ISA Memory */
+
+#define RAM_SIZE       0x1000       /*  The card has 4k bytes or RAM */
+#define PKT_START PP_TxFrame  /*  Start of packet RAM */
+
+#define RX_FRAME_PORT  0x0000
+#define TX_FRAME_PORT RX_FRAME_PORT
+#define TX_CMD_PORT    0x0004
+#define TX_NOW         0x0000       /*  Tx packet after   5 bytes copied */
+#define TX_AFTER_381   0x0020       /*  Tx packet after 381 bytes copied */
+#define TX_AFTER_ALL   0x0060       /*  Tx packet after all bytes copied */
+#define TX_LEN_PORT    0x0006
+#define ISQ_PORT       0x0008
+#define ADD_PORT       0x000A
+#define DATA_PORT      0x000C
+
+#define EEPROM_WRITE_EN                0x00F0
+#define EEPROM_WRITE_DIS       0x0000
+#define EEPROM_WRITE_CMD       0x0100
+#define EEPROM_READ_CMD                0x0200
+
+/*  Receive Header */
+/*  Description of header of each packet in receive area of memory */
+#define RBUF_EVENT_LOW 0   /*  Low byte of RxEvent - status of received frame */
+#define RBUF_EVENT_HIGH        1   /*  High byte of RxEvent - status of received frame */
+#define RBUF_LEN_LOW   2   /*  Length of received data - low byte */
+#define RBUF_LEN_HI    3   /*  Length of received data - high byte */
+#define RBUF_HEAD_LEN  4   /*  Length of this header */
+
+#define CHIP_READ 0x1   /*  Used to mark state of the repins code (chip or dma) */
+#define DMA_READ 0x2   /*  Used to mark state of the repins code (chip or dma) */
+
+/*  for bios scan */
+/*  */
+#ifdef CSDEBUG
+/*  use these values for debugging bios scan */
+#define BIOS_START_SEG 0x00000
+#define BIOS_OFFSET_INC 0x0010
+#else
+#define BIOS_START_SEG 0x0c000
+#define BIOS_OFFSET_INC 0x0200
+#endif
+
+#define BIOS_LAST_OFFSET 0x0fc00
+
+/*  Byte offsets into the EEPROM configuration buffer */
+#define ISA_CNF_OFFSET 0x6
+#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8)                     /*  8900 eeprom */
+#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8)               /*  8920 eeprom */
+
+  /*  the assumption here is that the bits in the eeprom are generally  */
+  /*  in the same position as those in the autonegctl register. */
+  /*  Of course the IMM bit is not in that register so it must be  */
+  /*  masked out */
+#define EE_FORCE_FDX  0x8000
+#define EE_NLP_ENABLE 0x0200
+#define EE_AUTO_NEG_ENABLE 0x0100
+#define EE_ALLOW_FDX 0x0080
+#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX)
+
+#define IMM_BIT 0x0040         /*  ignore missing media         */
+
+#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2)
+#define A_CNF_10B_T 0x0001
+#define A_CNF_AUI 0x0002
+#define A_CNF_10B_2 0x0004
+#define A_CNF_MEDIA_TYPE 0x0060
+#define A_CNF_MEDIA_AUTO 0x0000
+#define A_CNF_MEDIA_10B_T 0x0020
+#define A_CNF_MEDIA_AUI 0x0040
+#define A_CNF_MEDIA_10B_2 0x0060
+#define A_CNF_DC_DC_POLARITY 0x0080
+#define A_CNF_NO_AUTO_POLARITY 0x2000
+#define A_CNF_LOW_RX_SQUELCH 0x4000
+#define A_CNF_EXTND_10B_2 0x8000
+
+#define PACKET_PAGE_OFFSET 0x8
+
+/*  Bit definitions for the ISA configuration word from the EEPROM */
+#define INT_NO_MASK 0x000F
+#define DMA_NO_MASK 0x0070
+#define ISA_DMA_SIZE 0x0200
+#define ISA_AUTO_RxDMA 0x0400
+#define ISA_RxDMA 0x0800
+#define DMA_BURST 0x1000
+#define STREAM_TRANSFER 0x2000
+#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA)
+
+/*  DMA controller registers */
+#define DMA_BASE 0x00     /*  DMA controller base */
+#define DMA_BASE_2 0x0C0    /*  DMA controller base */
+
+#define DMA_STAT 0x0D0    /*  DMA controller status register */
+#define DMA_MASK 0x0D4    /*  DMA controller mask register */
+#define DMA_MODE 0x0D6    /*  DMA controller mode register */
+#define DMA_RESETFF 0x0D8    /*  DMA controller first/last flip flop */
+
+/*  DMA data */
+#define DMA_DISABLE 0x04     /*  Disable channel n */
+#define DMA_ENABLE 0x00     /*  Enable channel n */
+/*  Demand transfers, incr. address, auto init, writes, ch. n */
+#define DMA_RX_MODE 0x14
+/*  Demand transfers, incr. address, auto init, reads, ch. n */
+#define DMA_TX_MODE 0x18
+
+#define DMA_SIZE (16*1024) /*  Size of dma buffer - 16k */
+
+#define CS8900 0x0000
+#define CS8920 0x4000   
+#define CS8920M 0x6000   
+#define REVISON_BITS 0x1F00
+#define EEVER_NUMBER 0x12
+#define CHKSUM_LEN 0x14
+#define CHKSUM_VAL 0x0000
+#define START_EEPROM_DATA 0x001c /*  Offset into eeprom for start of data */
+#define IRQ_MAP_EEPROM_DATA 0x0046 /*  Offset into eeprom for the IRQ map */
+#define IRQ_MAP_LEN 0x0004 /*  No of bytes to read for the IRQ map */
+#define PNP_IRQ_FRMT 0x0022 /*  PNP small item IRQ format */
+#define CS8900_IRQ_MAP 0x1c20 /*  This IRQ map is fixed */
+
+#define CS8920_NO_INTS 0x0F   /*  Max CS8920 interrupt select # */
+
+#define PNP_ADD_PORT 0x0279
+#define PNP_WRITE_PORT 0x0A79
+
+#define GET_PNP_ISA_STRUCT 0x40
+#define PNP_ISA_STRUCT_LEN 0x06
+#define PNP_CSN_CNT_OFF 0x01
+#define PNP_RD_PORT_OFF 0x02
+#define PNP_FUNCTION_OK 0x00
+#define PNP_WAKE 0x03
+#define PNP_RSRC_DATA 0x04
+#define PNP_RSRC_READY 0x01
+#define PNP_STATUS 0x05
+#define PNP_ACTIVATE 0x30
+#define PNP_CNF_IO_H 0x60
+#define PNP_CNF_IO_L 0x61
+#define PNP_CNF_INT 0x70
+#define PNP_CNF_DMA 0x74
+#define PNP_CNF_MEM 0x48
+
+#define BIT0 1
+#define BIT15 0x8000
+
index 62ca67dc1b0ecc8e4077cd973ceb239bf998f19b..7c6ce635fea71226a318d5a2230a0798faa264ee 100644 (file)
@@ -1,12 +1,13 @@
-/*  de4x5.c: A DIGITAL DE425/DE434/DE435/DE450/DE500 ethernet driver for Linux.
+/*  de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500
+             ethernet driver for Linux.
 
     Copyright 1994, 1995 Digital Equipment Corporation.
 
     This software may be used and distributed according to the terms of
     the GNU Public License, incorporated herein by reference.
 
-    This driver is written for the Digital Equipment Corporation series
-    of EtherWORKS ethernet cards:
+    Originally,   this  driver  was    written  for the  Digital   Equipment
+    Corporation series of EtherWORKS ethernet cards:
 
         DE425 TP/COAX EISA
        DE434 TP PCI
        DE450 TP/COAX/AUI PCI
        DE500 10/100 PCI Fasternet
 
+    but it  will now  attempt  to support all  cards   which conform  to the
+    Digital  Semiconductor SROM    Specification.   The   driver   currently
+    recognises the following chips:
+
+        DC21040     (no SROM)
+       DC21041[A]
+       DC21140[A]
+
+    I plan to  add DC2114[23]  support ASAP,  time permitting.   So far  the
+    driver is known to work with the following cards:
+
+        KINGSTON
+       Linksys
+       ZNYX342
+       SMC8432
+       SMC9332 (w/new SROM)
+       ZNYX31[45]
+
     The driver has been tested on a relatively busy network using the DE425,
     DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
     16M of data to a DECstation 5000/200 as follows:
     The author may be reached at davies@maniac.ultranet.com.
 
     =========================================================================
-    This driver has been written  substantially  from scratch, although  its
+    This driver  has been written substantially  from scratch,  although its
     inheritance of style and stack interface from 'ewrk3.c' and in turn from
-    Donald Becker's 'lance.c' should be obvious.
+    Donald Becker's 'lance.c' should be obvious. With the module autoload of
+    every  usable DECchip board,  I pinched Donald's  'next_module' field to
+    link my modules together.
 
     Upto 15 EISA cards can be supported under this driver, limited primarily
     by the available IRQ lines.  I have  checked different configurations of
     to the differences in the EISA and PCI CSR address offsets from the base
     address.
 
-    The ability to load this driver  as a loadable  module has been included
-    and used extensively during the  driver development (to save those  long
-    reboot sequences).  Loadable module support under  PCI and EISA has been
+    The ability to load this  driver as a loadable  module has been included
+    and used extensively  during the driver development  (to save those long
+    reboot sequences).  Loadable module support  under PCI and EISA has been
     achieved by letting the driver autoprobe as if it were compiled into the
-    kernel, except that there is no autoprobing of the IRQ lines. This is of
-    no great consequence except do  make sure you're not sharing  interrupts
-    with anything that cannot   accommodate interrupt sharing!  By  default,
-    the driver will autoprobe for the next available card.
-
-    Essentially, the I/O address and IRQ information  are ignored and filled
-    in later by  the PCI BIOS   during the PCI  probe.  Note  that the board
-    should be in the system at boot time so that its I/O address and IRQ are
-    allocated by the PCI BIOS automatically.
+    kernel. Do make sure  you're not sharing  interrupts with anything  that
+    cannot accommodate  interrupt  sharing!
 
     To utilise this ability, you have to do 8 things:
 
     0) have a copy of the loadable modules code installed on your system.
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
-    2) edit the source code near line 4146 to reflect the I/O address you're
-    using (only  if you want to manually  load the module),  or assign these
-    when loading by:
+    2) for fixed  autoprobes (not  recommended),  edit the source code  near
+    line 4927 to reflect the I/O address  you're using, or assign these when
+    loading by:
 
-                   insmod de4x5.o io=0xghh         where g = bus number
-                                                       hh = device number
+                   insmod de4x5 io=0xghh           where g = bus number
+                                                       hh = device number   
 
        NB: autoprobing for modules is now supported by default. You may just
            use:
 
-                   insmod de4x5.o
+                   insmod de4x5
 
-           to load the next available board. For a specific board, still use
+           to load all available boards. For a specific board, still use
           the 'io=?' above.
     3) compile  de4x5.c, but include -DMODULE in  the command line to ensure
     that the correct bits are compiled (see end of source code).
     4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
     kernel with the de4x5 configuration turned off and reboot.
-    5) insmod de4x5.o [io=0xghh]
-    6) run the net startup bits for your new eth?? interface(s) manually
-    (usually /etc/rc.inet[12] at boot time).
+    5) insmod de4x5 [io=0xghh]
+    6) run the net startup bits for your new eth?? interface(s) manually 
+    (usually /etc/rc.inet[12] at boot time). 
     7) enjoy!
 
-    To unload a module, turn off the associated interface(s)
+    To unload a module, turn off the associated interface(s) 
     'ifconfig eth?? down' then 'rmmod de4x5'.
 
     Automedia detection is included so that in  principal you can disconnect
     By  default,  the driver will  now   autodetect any  DECchip based card.
     Should you have a need to restrict the driver to DIGITAL only cards, you
     can compile with a  DEC_ONLY define, or if  loading as a module, use the
-    'dec_only=1'  parameter. However, this  "feature" is in no way supported
-    nor  tested in this  driver  and the user  may use  it  at his/her  sole
-    discretion.   I have had  2 conflicting reports that  my  driver will or
-    won't work  with Znyx.   Try  Donald Becker's 'tulip.c' if   this driver
-    doesn't work for you. I will not be supporting Znyx  and SMC cards since
-    I have  no information on  them and  can't test  them in  a system (this
-    applies most particularly to the DC21140 based cards).
+    'dec_only=1'  parameter.
 
     I've changed the timing routines to  use the kernel timer and scheduling
     functions  so that the  hangs  and other assorted problems that occurred
     aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
     longword aligned data copies (which makes them really slow). No comment.
 
+    I  have added SROM decoding  routines to make this  driver work with any
+    card that  supports the Digital  Semiconductor SROM spec. This will help
+    all  cards running the dc2114x  series chips in particular.  Cards using
+    the dc2104x  chips should run correctly with  the basic  driver.  I'm in
+    debt to <mjacob@feral.com> for the  testing and feedback that helped get
+    this feature working.  So far we have  tested KINGSTON, SMC8432, SMC9332
+    (with the latest SROM complying  with the SROM spec  V3: their first was
+    broken), ZNYX342  and  LinkSys. ZYNX314 (dual  21041  MAC) and  ZNYX 315
+    (quad 21041 MAC)  cards also  appear  to work despite their  incorrectly
+    wired IRQs.
+
     TO DO:
     ------
 
     ----------------
 
     Version   Date        Description
-
+  
       0.1     17-Nov-94   Initial writing. ALPHA code release.
       0.2     13-Jan-95   Added PCI support for DE435's.
       0.21    19-Jan-95   Added auto media detection.
                          Add request/release_region code.
                          Add loadable modules support for PCI.
                          Clean up loadable modules support.
-      0.23    28-Feb-95   Added DC21041 and DC21140 support.
+      0.23    28-Feb-95   Added DC21041 and DC21140 support. 
                           Fix missed frame counter value and initialisation.
                          Fixed EISA probe.
       0.24    11-Apr-95   Change delay routine to use <linux/udelay>.
                           Add kernel timer code (h/w is too flaky).
                          Add MII based PHY autosense.
                          Add new multicasting code.
-                         Add new autosense algorithms for media/mode
+                         Add new autosense algorithms for media/mode 
                          selection using kernel scheduling/timing.
                          Re-formatted.
                          Made changes suggested by <jeff@router.patch.net>:
                           Add Accton to the list of broken cards.
                          Fix TX under-run bug for non DC21140 chips.
                          Fix boot command probe bug in alloc_device() as
-                          reported by <koen.gadeyne@barco.com> and
+                          reported by <koen.gadeyne@barco.com> and 
                           <orava@nether.tky.hut.fi>.
                          Add cache locks to prevent a race condition as
-                          reported by <csd@microplex.com> and
+                          reported by <csd@microplex.com> and 
                           <baba@beckman.uiuc.edu>.
                          Upgraded alloc_device() code.
       0.431  28-Jun-96    Fix potential bug in queue_pkt() from discussion
                           with <csd@microplex.com>
       0.44   13-Aug-96    Fix RX overflow bug in 2114[023] chips.
                           Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
-                         and <michael@compurex.com>
+                         and <michael@compurex.com>.
       0.441   9-Sep-96    Change dc21041_autoconf() to probe quiet BNC media
                            with a loopback packet.
       0.442   9-Sep-96    Include AUI in dc21041 media printout. Bug reported
                            by <bhat@mundook.cs.mu.OZ.AU>
-      0.45    8-Dec-96    Include endian functions for PPC use, from work
+      0.45    8-Dec-96    Include endian functions for PPC use, from work 
                            by <cort@cs.nmt.edu>.
       0.451  28-Dec-96    Added fix to allow autoprobe for modules after
-                           suggestion from <mjacob@feral.com>
+                           suggestion from <mjacob@feral.com>.
+      0.5    30-Jan-97    Added SROM decoding functions.
+                          Updated debug flags.
+                         Fix sleep/wakeup calls for PCI cards, bug reported
+                          by <cross@gweep.lkg.dec.com>.
+                         Added multi-MAC, one SROM feature from discussion
+                          with <mjacob@feral.com>.
+                         Added full module autoprobe capability.
+                         Added attempt to use an SMC9332 with broken SROM.
+                         Added fix for ZYNX multi-mac cards that didn't
+                          get their IRQs wired correctly.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.451 96/12/28 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -280,6 +309,12 @@ struct mii_phy {
        int value;
     } spd;
     int addr;               /* MII address for the PHY */
+    u_char  *gep;           /* Start of GEP sequence block in SROM */
+    u_char  *rst;           /* Start of reset sequence in SROM */
+    u_int mc;               /* Media Capabilities */
+    u_int ana;              /* NWay Advertisement */
+    u_int fdx;              /* Full DupleX capabilites for each media */
+    u_int ttm;              /* Transmit Threshold Mode for each media */
 };
 
 #define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
@@ -306,11 +341,23 @@ static c_char enet_det[][ETH_ALEN] = {
 #define SMC    1
 #define ACCTON 2
 
+/*
+** SROM Repair definitions. If a broken SROM is detected a card may
+** use this information to help figure out what to do. This is a
+** "stab in the dark" and so far for SMC9332's only.
+*/
+static c_char srom_repair_info[][100] = {
+    {0x00,0x1e,0x00,0x00,0x00,0x08,             /* SMC9332 */
+     0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02,
+     0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50,
+     0x00,0x18,}
+};
+
 
 #ifdef DE4X5_DEBUG
 static int de4x5_debug = DE4X5_DEBUG;
 #else
-static int de4x5_debug = 1;
+static int de4x5_debug = (0);
 #endif
 
 #ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
@@ -374,7 +421,7 @@ static s32 de4x5_full_duplex = 0;
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
 ** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
 ** DESC_ALIGN. ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
+** and hence the RX descriptor ring's first entry. 
 */
 #define ALIGN4      ((u_long)4 - 1)     /* 1 longword align */
 #define ALIGN8      ((u_long)8 - 1)     /* 2 longword align */
@@ -455,7 +502,7 @@ struct de4x5_srom {
     char id_block_crc;
     char reserved2;
     char version;
-    char num_adapters;
+    char num_controllers;
     char ieee_addr[6];
     char info[100];
     short chksum;
@@ -500,7 +547,7 @@ struct de4x5_private {
     int tx_new, tx_old;                     /* TX descriptor ring pointers  */
     char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
     char frame[64];                         /* Min sized packet for loopback*/
-    struct enet_statistics stats;           /* Public stats                 */
+    struct net_device_stats stats;           /* Public stats                 */
     struct {
        u_int bins[DE4X5_PKT_STAT_SZ];      /* Private stats counters       */
        u_int unicast;
@@ -518,16 +565,17 @@ struct de4x5_private {
     char txRingSize;
     int  bus;                               /* EISA or PCI                  */
     int  bus_num;                           /* PCI Bus number               */
+    int  device;                            /* Device number on PCI bus     */
     int  state;                             /* Adapter OPENED or CLOSED     */
     int  chipset;                           /* DC21040, DC21041 or DC21140  */
     s32  irq_mask;                          /* Interrupt Mask (Enable) bits */
     s32  irq_en;                            /* Summary interrupt bits       */
     int  media;                             /* Media (eg TP), mode (eg 100B)*/
     int  c_media;                           /* Remember the last media conn */
+    int  fdx;                               /* media full duplex flag       */
     int  linkOK;                            /* Link is OK                   */
     int  autosense;                         /* Allow/disallow autosensing   */
     int  tx_enable;                         /* Enable descriptor polling    */
-    int  lostMedia;                         /* Possibly lost media          */
     int  setup_f;                           /* Setup frame filtering type   */
     int  local_state;                       /* State within a 'media' state */
     struct mii_phy phy[DE4X5_MAX_PHY];      /* List of attached PHY devices */
@@ -543,13 +591,31 @@ struct de4x5_private {
        s32 csr0;                           /* Saved Bus Mode Register      */
        s32 csr6;                           /* Saved Operating Mode Reg.    */
        s32 csr7;                           /* Saved IRQ Mask Register      */
+       s32 gep;                            /* Saved General Purpose Reg.   */
+       s32 gepc;                           /* Control info for GEP         */
        s32 csr13;                          /* Saved SIA Connectivity Reg.  */
        s32 csr14;                          /* Saved SIA TX/RX Register     */
        s32 csr15;                          /* Saved SIA General Register   */
        int save_cnt;                       /* Flag if state already saved  */
        struct sk_buff *skb;                /* Save the (re-ordered) skb's  */
     } cache;
+    struct de4x5_srom srom;                 /* A copy of the SROM           */
+    struct device *next_module;             /* Link to the next module      */
     int rx_ovf;                             /* Check for 'RX overflow' tag  */
+    int useSROM;                            /* For non-DEC card use SROM    */
+    int useMII;                             /* Infoblock using the MII      */
+    int asBitValid;                         /* Autosense bits in GEP?       */
+    int asPolarity;                         /* 0 => asserted high           */
+    int asBit;                              /* Autosense bit number in GEP  */
+    int defMedium;                          /* SROM default medium          */
+    int tcount;                             /* Last infoblock number        */
+    int infoblock_init;                     /* Initialised this infoblock?  */
+    int infoleaf_offset;                    /* SROM infoleaf for controller */
+    s32 infoblock_csr6;                     /* csr6 value in SROM infoblock */
+    int infoblock_media;                    /* infoblock media              */
+    int (*infoleaf_fn)(struct device *);    /* Pointer to infoleaf function */
+    u_char *rst;                            /* Pointer to Type 5 reset info */
+    u_char  ibn;                            /* Infoblock number             */
 };
 
 /*
@@ -564,8 +630,28 @@ static struct bus_type {
     int chipset;
     struct de4x5_srom srom;
     int autosense;
+    int useSROM;
 } bus;
 
+/*
+** To get around certain poxy cards that don't provide an SROM
+** for the second and more DECchip, I have to key off the first
+** chip's address. I'll assume there's not a bad SROM iff:
+**
+**      o the chipset is the same
+**      o the bus number is the same and > 0
+**      o the sum of all the returned hw address bytes is 0 or 0x5fa
+**
+** Also have to save the irq for those cards whose hardware designers
+** can't follow the PCI to PCI Bridge Architecture spec.
+*/
+struct {
+    int chipset;
+    int bus;
+    int irq;
+    u_char addr[ETH_ALEN];
+} last = {0,};
+
 /*
 ** The transmit ring full condition is described by the tx_old and tx_new
 ** pointers by:
@@ -586,7 +672,7 @@ static int     de4x5_open(struct device *dev);
 static int     de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
 static void    de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int     de4x5_close(struct device *dev);
-static struct  enet_statistics *de4x5_get_stats(struct device *dev);
+static struct  net_device_stats *de4x5_get_stats(struct device *dev);
 static void    de4x5_local_stats(struct device *dev, char *buf, int pkt_len);
 static void    set_multicast_list(struct device *dev);
 static int     de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
@@ -611,6 +697,7 @@ static void    load_packet(struct device *dev, char *buf, u32 flags, struct sk_b
 static int     dc21040_autoconf(struct device *dev);
 static int     dc21041_autoconf(struct device *dev);
 static int     dc21140m_autoconf(struct device *dev);
+static int     srom_autoconf(struct device *dev);
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
@@ -648,6 +735,10 @@ static short   srom_data(u_int command, u_long address);
 /*static void    srom_busy(u_int command, u_long address);*/
 static void    sendto_srom(u_int command, u_long addr);
 static int     getfrom_srom(u_long addr);
+static void    srom_map_media(struct device *dev);
+static int     srom_infoleaf_info(struct device *dev);
+static void    srom_init(struct device *dev);
+static void    srom_exec(struct device *dev, u_char *p);
 static int     mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr);
 static void    mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr);
 static int     mii_rdata(u_long ioaddr);
@@ -661,6 +752,8 @@ static int     mii_get_oui(u_char phyaddr, u_long ioaddr);
 static int     mii_get_phy(struct device *dev);
 static void    SetMulticastFilter(struct device *dev);
 static int     get_hw_addr(struct device *dev);
+static void    srom_repair(struct device *dev, int card);
+static int     test_bad_enet(struct device *dev, int status);
 
 static void    eisa_probe(struct device *dev, u_long iobase);
 static void    pci_probe(struct device *dev, u_long iobase);
@@ -670,16 +763,29 @@ static struct  device *insert_device(struct device *dev, u_long iobase,
 static char    *build_setup_frame(struct device *dev, int mode);
 static void    disable_ast(struct device *dev);
 static void    enable_ast(struct device *dev, u32 time_out);
-static long    de4x5_switch_to_srl(struct device *dev);
-static long    de4x5_switch_to_mii(struct device *dev);
+static long    de4x5_switch_mac_port(struct device *dev);
 static void    timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec);
+static void    yawn(struct device *dev, int state);
 static int     de4x5_dev_index(char *s);
+static void    link_modules(struct device *dev, struct device *tmp);
+static struct  device *unlink_modules(struct device *p);
 static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
 static void    de4x5_dbg_srom(struct de4x5_srom *p);
 static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
 static int     de4x5_strncmp(char *a, char *b, int n);
+static int     dc21041_infoleaf(struct device *dev);
+static int     dc21140_infoleaf(struct device *dev);
+static int     dc21142_infoleaf(struct device *dev);
+static int     dc21143_infoleaf(struct device *dev);
+static int     type0_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type1_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type2_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type3_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type4_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type5_infoblock(struct device *dev, u_char count, u_char *p);
+static int     compact_infoblock(struct device *dev, u_char count, u_char *p);
 
 #ifdef MODULE
 int  init_module(void);
@@ -692,7 +798,37 @@ static int autoprobed = 0, loading_module = 0;
 static char name[DE4X5_NAME_LENGTH + 1];
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 static int num_de4x5s = 0, num_eth = 0;
-static int cfrv = 0;
+static int cfrv = 0, useSROM = 0;
+
+/*
+** List the SROM infoleaf functions and chipsets
+*/
+struct InfoLeaf {
+    int chipset;
+    int (*fn)(struct device *);
+};
+struct InfoLeaf infoleaf_array[] = {
+    {DC21041, dc21041_infoleaf},
+    {DC21140, dc21140_infoleaf},
+    {DC21142, dc21142_infoleaf},
+    {DC21143, dc21143_infoleaf}
+};
+#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
+
+/*
+** List the SROM info block functions
+*/
+static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = {
+    type0_infoblock,
+    type1_infoblock,
+    type2_infoblock,
+    type3_infoblock,
+    type4_infoblock,
+    type5_infoblock,
+    compact_infoblock
+};
+
+#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
 
 /*
 ** Miscellaneous defines...
@@ -709,6 +845,13 @@ static int cfrv = 0;
     de4x5_ms_delay(1);\
 }
 
+#define PHY_HARD_RESET {\
+    outl(GEP_HRST, DE4X5_GEP);           /* Hard RESET the PHY dev. */\
+    udelay(1000);                        /* Assert for 1ms */\
+    outl(0x00, DE4X5_GEP);\
+    udelay(2000);                        /* Wait for 2ms */\
+}
+
 \f
 /*
 ** Autoprobing in modules is allowed here. See the top of the file for
@@ -718,23 +861,18 @@ static int cfrv = 0;
 int
 de4x5_probe(struct device *dev)
 {
-    int tmp = num_de4x5s, status = -ENODEV;
+    int status = -ENODEV;
     u_long iobase = dev->base_addr;
 
     eisa_probe(dev, iobase);
     pci_probe(dev, iobase);
-
-    if ((tmp == num_de4x5s) && (iobase != 0) && loading_module) {
-       printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name,
-              iobase);
-    }
-
+    
     /*
     ** Walk the device list to check that at least one device
     ** initialised OK
     */
     for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
-
+    
     if (dev->priv) status = 0;
     if (iobase == 0) autoprobed = 1;
 
@@ -745,70 +883,70 @@ static int
 de4x5_hw_init(struct device *dev, u_long iobase)
 {
     struct bus_type *lp = &bus;
-    int tmpbus, tmpchs, status=0;
-    int i, media = *((char *)&(lp->srom) + *((char *)&(lp->srom) + 19) * 3);
+    int i, status=0;
     char *tmp;
-
+    
     /* Ensure we're not sleeping */
-    if (lp->chipset == DC21041) {
-       outl(0, PCI_CFDA);
-       de4x5_ms_delay(10);
+    if (lp->bus == EISA) {
+       outb(WAKEUP, PCI_CFPM);
+    } else {
+       pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+                                 PCI_CFDA_PSM, WAKEUP);
     }
-
+    de4x5_ms_delay(10);
+    
     RESET_DE4X5;
-
+    
     if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
        return -ENXIO;                       /* Hardware could not reset */
     }
-
-    /*
+    
+    /* 
     ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
     */
+    useSROM = FALSE;
     if (lp->bus == PCI) {
        PCI_signature(name, lp);
     } else {
        EISA_signature(name, EISA_ID0);
     }
-
+    
     if (*name == '\0') {                     /* Not found a board signature */
        return -ENXIO;
     }
-
+    
     dev->base_addr = iobase;
     if (lp->bus == EISA) {
-       printk("%s: %s at 0x%04lx (EISA slot %ld)",
+       printk("%s: %s at 0x%04lx (EISA slot %ld)", 
               dev->name, name, iobase, ((iobase>>12)&0x0f));
     } else {                                 /* PCI port address */
        printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
               iobase, lp->bus_num, lp->device);
     }
-
+    
     printk(", h/w address ");
     status = get_hw_addr(dev);
     for (i = 0; i < ETH_ALEN - 1; i++) {     /* get the ethernet addr. */
        printk("%2.2x:", dev->dev_addr[i]);
     }
     printk("%2.2x,\n", dev->dev_addr[i]);
-
-    tmpbus = lp->bus;
-    tmpchs = lp->chipset;
-
+    
     if (status != 0) {
        printk("      which has an Ethernet PROM CRC error.\n");
        return -ENXIO;
     } else {
        struct de4x5_private *lp;
-
-       /*
+       
+       /* 
        ** Reserve a section of kernel memory for the adapter
        ** private area and the TX/RX descriptor rings.
        */
-       dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN,
+       dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, 
                                     GFP_KERNEL);
        if (dev->priv == NULL) {
            return -ENOMEM;
        }
-
+       
        /*
        ** Align to a longword boundary
        */
@@ -816,26 +954,20 @@ de4x5_hw_init(struct device *dev, u_long iobase)
        dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
        lp = (struct de4x5_private *)dev->priv;
        memset(dev->priv, 0, sizeof(struct de4x5_private));
-       lp->bus = tmpbus;
-       lp->chipset = tmpchs;
+       lp->bus = bus.bus;
+       lp->bus_num = bus.bus_num;
+       lp->device = bus.device;
+       lp->chipset = bus.chipset;
        lp->cache.priv = tmp;
-
-       /*
-       ** Check for an MII interface
-       */
-       if (media & MEDIA_MII) {                   /* MII interface? */
-           if (!mii_get_phy(dev)) {
-               printk("%s: MII search failed, no device found when one was expected\n", dev->name);
-               return -ENXIO;
-           }
-       } else {
-           mii_get_phy(dev);                      /* Search the MII anyway! */
-       }
+       lp->cache.gepc = GEP_INIT;
+       lp->timeout = -1;
+       lp->useSROM = useSROM;
+       memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
 
        /*
        ** Choose correct autosensing in case someone messed up
        */
-       if (de4x5_autosense & AUTO) {
+       if ((de4x5_autosense & AUTO) || lp->useSROM) {
            lp->autosense = AUTO;
        } else {
            if (lp->chipset != DC21140) {
@@ -850,12 +982,12 @@ de4x5_hw_init(struct device *dev, u_long iobase)
                lp->autosense = de4x5_autosense & 0x00c0;
            }
        }
-
+       lp->fdx = de4x5_full_duplex;
        sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
-
+       
        /*
        ** Set up the RX descriptor ring (Intels)
-       ** Allocate contiguous receive buffers, long word aligned (Alphas)
+       ** Allocate contiguous receive buffers, long word aligned (Alphas) 
        */
 #if !defined(__alpha__) && !defined(__powerpc__) && !defined(DE4X5_DO_MEMCPY)
        for (i=0; i<NUM_RX_DESC; i++) {
@@ -867,7 +999,7 @@ de4x5_hw_init(struct device *dev, u_long iobase)
        }
 
 #else
-       if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN,
+       if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
                                   GFP_KERNEL)) == NULL) {
            kfree(lp->cache.priv);
            return -ENOMEM;
@@ -885,22 +1017,22 @@ de4x5_hw_init(struct device *dev, u_long iobase)
 #endif
 
        barrier();
-
+           
        request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-                               DE4X5_EISA_TOTAL_SIZE),
+                               DE4X5_EISA_TOTAL_SIZE), 
                       lp->adapter_name);
-
+           
        lp->rxRingSize = NUM_RX_DESC;
        lp->txRingSize = NUM_TX_DESC;
-
+           
        /* Write the end of list marker to the descriptor lists */
        lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
        lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
-
+           
        /* Tell the adapter where the TX/RX rings are located. */
        outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
        outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
+           
        /* Initialise the IRQ mask and Enable/Disable */
        lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
        lp->irq_en   = IMR_NIM | IMR_AIM;
@@ -909,23 +1041,40 @@ de4x5_hw_init(struct device *dev, u_long iobase)
        create_packet(dev, lp->frame, sizeof(lp->frame));
 
        /* Check if the RX overflow bug needs testing for */
-       tmpchs = cfrv & 0x000000fe;
-       if ((lp->chipset == DC21140) && (tmpchs == 0x20)) {
+       i = cfrv & 0x000000fe;
+       if ((lp->chipset == DC21140) && (i == 0x20)) {
            lp->rx_ovf = 1;
        }
 
-       /* Initialise the adapter state */
+       /* Initialise the SROM pointers if possible */
+       if (lp->useSROM) {
+           lp->state = INITIALISED;
+           de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
+           if (srom_infoleaf_info(dev)) {
+               return -ENXIO;
+           }
+           srom_init(dev);
+       }
+
        lp->state = CLOSED;
 
+       /*
+       ** Check for an MII interface
+       */
+       if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
+           mii_get_phy(dev);
+       }
+       
        printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
               ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
 
+       printk("INFOLEAF_SIZE: %d\nCOMPACT: %d\n", INFOLEAF_SIZE, COMPACT);
     }
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_VERSION) {
        printk(version);
     }
-
+    
     /* The DE4X5-specific entries in the device structure. */
     dev->open = &de4x5_open;
     dev->hard_start_xmit = &de4x5_queue_pkt;
@@ -933,18 +1082,15 @@ de4x5_hw_init(struct device *dev, u_long iobase)
     dev->get_stats = &de4x5_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     dev->do_ioctl = &de4x5_ioctl;
-
+    
     dev->mem_start = 0;
-
-    /* Fill in the generic field of the device structure. */
+    
+    /* Fill in the generic fields of the device structure. */
     ether_setup(dev);
-
+    
     /* Let the adapter sleep to save power */
-    if (lp->chipset == DC21041) {
-       outl(0, DE4X5_SICR);
-       outl(CFDA_PSM, PCI_CFDA);
-    }
-
+    yawn(dev, SLEEP);
+    
     return status;
 }
 
@@ -956,7 +1102,7 @@ de4x5_open(struct device *dev)
     u_long iobase = dev->base_addr;
     int i, status = 0;
     s32 omr;
-
+    
     /* Allocate the RX buffers */
     for (i=0; i<lp->rxRingSize; i++) {
        if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
@@ -968,35 +1114,32 @@ de4x5_open(struct device *dev)
     /*
     ** Wake up the adapter
     */
-    if (lp->chipset == DC21041) {
-       outl(0, PCI_CFDA);
-       de4x5_ms_delay(10);
-    }
+    yawn(dev, WAKEUP);
 
-    /*
-    ** Re-initialize the DE4X5...
+    /* 
+    ** Re-initialize the DE4X5... 
     */
     status = de4x5_init(dev);
-
+    
     lp->state = OPEN;
     de4x5_dbg_open(dev);
-
-    if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
+    
+    if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
                                                     lp->adapter_name, dev)) {
        printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
        status = -EAGAIN;
     } else {
-       dev->tbusy = 0;
+       dev->tbusy = 0;                         
        dev->start = 1;
        dev->interrupt = UNMASK_INTERRUPTS;
        dev->trans_start = jiffies;
-
+       
        START_DE4X5;
-
+       
        de4x5_setup_intr(dev);
     }
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_OPEN) {
        printk("\tsts:  0x%08x\n", inl(DE4X5_STS));
        printk("\tbmr:  0x%08x\n", inl(DE4X5_BMR));
        printk("\timr:  0x%08x\n", inl(DE4X5_IMR));
@@ -1006,9 +1149,9 @@ de4x5_open(struct device *dev)
        printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
        printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
     }
-
+    
     MOD_INC_USE_COUNT;
-
+    
     return status;
 }
 
@@ -1022,15 +1165,15 @@ de4x5_open(struct device *dev)
 */
 static int
 de4x5_init(struct device *dev)
-{
+{  
     /* Lock out other processes whilst setting up the hardware */
     set_bit(0, (void *)&dev->tbusy);
-
+    
     de4x5_sw_reset(dev);
-
+    
     /* Autoconfigure the connected port */
     autoconf_media(dev);
-
+    
     return 0;
 }
 
@@ -1041,22 +1184,25 @@ de4x5_sw_reset(struct device *dev)
     u_long iobase = dev->base_addr;
     int i, j, status = 0;
     s32 bmr, omr;
-
+    
     /* Select the MII or SRL port now and RESET the MAC */
-    if (lp->phy[lp->active].id == 0) {
-       de4x5_switch_to_srl(dev);
-    } else {
-       de4x5_switch_to_mii(dev);
+    if (!lp->useSROM) {
+       if (lp->phy[lp->active].id != 0) {
+           lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+       } else {
+           lp->infoblock_csr6 = OMR_TTM;
+       }
+       de4x5_switch_mac_port(dev);
     }
 
-    /*
+    /* 
     ** Set the programmable burst length to 8 longwords for all the DC21140
     ** Fasternet chips and 4 longwords for all others: DMA errors result
     ** without these values. Cache align 16 long.
     */
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
     outl(bmr, DE4X5_BMR);
-
+    
     omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
     if (lp->chipset == DC21140) {
        omr |= (OMR_SDP | OMR_SB);
@@ -1064,26 +1210,26 @@ de4x5_sw_reset(struct device *dev)
     lp->setup_f = PERFECT;
     outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
     outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
+    
     lp->rx_new = lp->rx_old = 0;
     lp->tx_new = lp->tx_old = 0;
-
+    
     for (i = 0; i < lp->rxRingSize; i++) {
        lp->rx_ring[i].status = cpu_to_le32(R_OWN);
     }
-
+    
     for (i = 0; i < lp->txRingSize; i++) {
        lp->tx_ring[i].status = cpu_to_le32(0);
     }
-
+    
     barrier();
-
+    
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
-
+    
     load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
-
+    
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
     sti();                                       /* Ensure timer interrupts */
     for (j=0, i=0;(i<500) && (j==0);i++) {       /* Upto 500ms delay */
@@ -1091,20 +1237,20 @@ de4x5_sw_reset(struct device *dev)
        if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
     }
     outl(omr, DE4X5_OMR);                        /* Stop everything! */
-
+    
     if (j == 0) {
-       printk("%s: Setup frame timed out, status %08x\n", dev->name,
+       printk("%s: Setup frame timed out, status %08x\n", dev->name, 
               inl(DE4X5_STS));
        status = -EIO;
     }
-
+    
     lp->tx_new = (++lp->tx_new) % lp->txRingSize;
     lp->tx_old = lp->tx_new;
-
+    
     return status;
 }
 
-/*
+/* 
 ** Writes a socket buffer address to the next available transmit descriptor
 */
 static int
@@ -1121,9 +1267,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
 
     set_bit(0, (void*)&dev->tbusy);              /* Stop send re-tries */
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
-       return -1;
+       return -1;                                
     }
-
+    
     /*
     ** Clean out the TX ring asynchronously to interrupts - sometimes the
     ** interrupts are lost by delayed descriptor status updates relative to
@@ -1143,8 +1289,8 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
        } else {
            de4x5_put_cache(dev, skb);
        }
-       if (de4x5_debug > 1) {
-           printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
+       if (de4x5_debug & DEBUG_TX) {
+           printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
        }
     } else if (skb->len > 0) {
        /* If we already have stuff queued locally, use that first */
@@ -1158,10 +1304,10 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
            set_bit(0, (void*)&dev->tbusy);
            load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
            outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
-
+               
            lp->tx_new = (++lp->tx_new) % lp->txRingSize;
            dev->trans_start = jiffies;
-
+                   
            if (TX_BUFFS_AVAIL) {
                dev->tbusy = 0;         /* Another pkt may be queued */
            }
@@ -1170,15 +1316,15 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
        }
        if (skb) de4x5_putb_cache(dev, skb);
     }
-
+    
     lp->cache.lock = 0;
 
     return status;
 }
 
 /*
-** The DE4X5 interrupt handler.
-**
+** The DE4X5 interrupt handler. 
+** 
 ** I/O Read/Writes through intermediate PCI bridges are never 'posted',
 ** so that the asserted interrupt always has some real data to work with -
 ** if these I/O accesses are ever changed to memory accesses, ensure the
@@ -1194,41 +1340,40 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     struct de4x5_private *lp;
     s32 imr, omr, sts, limit;
     u_long iobase;
-
+    
     if (dev == NULL) {
        printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
        return;
     }
     lp = (struct de4x5_private *)dev->priv;
     iobase = dev->base_addr;
-
+       
     if (dev->interrupt)
       printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
+       
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
     dev->interrupt = MASK_INTERRUPTS;
-
+       
     for (limit=0; limit<8; limit++) {
        sts = inl(DE4X5_STS);            /* Read IRQ status */
        outl(sts, DE4X5_STS);            /* Reset the board interrupts */
-
+           
        if (!(sts & lp->irq_mask)) break;/* All done */
-
+           
        if (sts & (STS_RI | STS_RU))     /* Rx interrupt (packet[s] arrived) */
          de4x5_rx(dev);
-
+           
        if (sts & (STS_TI | STS_TU))     /* Tx interrupt (packet sent) */
-         de4x5_tx(dev);
-
+         de4x5_tx(dev); 
+           
        if (sts & STS_LNF) {             /* TP Link has failed */
-           lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
            lp->irq_mask &= ~IMR_LFM;
        }
-
+           
        if (sts & STS_UNF) {             /* Transmit underrun */
            de4x5_txur(dev);
        }
-
+           
        if (sts & STS_SE) {              /* Bus Error */
            STOP_DE4X5;
            printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
@@ -1247,7 +1392,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
     dev->interrupt = UNMASK_INTERRUPTS;
     ENABLE_IRQs;
-
+    
     return;
 }
 
@@ -1258,11 +1403,11 @@ de4x5_rx(struct device *dev)
     u_long iobase = dev->base_addr;
     int entry;
     s32 status;
-
+    
     for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0;
                                                            entry=lp->rx_new) {
        status = (s32)le32_to_cpu(lp->rx_ring[entry].status);
-
+       
        if (lp->rx_ovf) {
            if (inl(DE4X5_MFC) & MFC_FOCM) {
                de4x5_rx_ovfc(dev);
@@ -1273,9 +1418,9 @@ de4x5_rx(struct device *dev)
        if (status & RD_FS) {                 /* Remember the start of frame */
            lp->rx_old = entry;
        }
-
+       
        if (status & RD_LS) {                 /* Valid frame status */
-           lp->linkOK++;
+           if (lp->tx_enable) lp->linkOK++;
            if (status & RD_ES) {             /* There was an error. */
                lp->stats.rx_errors++;        /* Update the error stats. */
                if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++;
@@ -1290,9 +1435,9 @@ de4x5_rx(struct device *dev)
                struct sk_buff *skb;
                short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status)
                                                                    >> 16) - 4;
-
+               
                if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
-                   printk("%s: Insufficient memory; nuking packet.\n",
+                   printk("%s: Insufficient memory; nuking packet.\n", 
                                                                    dev->name);
                    lp->stats.rx_dropped++;   /* Really, deferred. */
                    break;
@@ -1302,12 +1447,12 @@ de4x5_rx(struct device *dev)
                /* Push up the protocol stack */
                skb->protocol=eth_type_trans(skb,dev);
                netif_rx(skb);
-
+                   
                /* Update stats */
                lp->stats.rx_packets++;
                de4x5_local_stats(dev, skb->data, pkt_len);
            }
-
+           
            /* Change buffer ownership for this frame, back to the adapter */
            for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
                lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
@@ -1316,13 +1461,13 @@ de4x5_rx(struct device *dev)
            lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
            barrier();
        }
-
+       
        /*
        ** Update entry information
        */
        lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
     }
-
+    
     return 0;
 }
 
@@ -1336,33 +1481,29 @@ de4x5_tx(struct device *dev)
     u_long iobase = dev->base_addr;
     int entry;
     s32 status;
-
+    
     for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
        status = (s32)le32_to_cpu(lp->tx_ring[entry].status);
        if (status < 0) {                     /* Buffer not sent yet */
            break;
        } else if (status != 0x7fffffff) {    /* Not setup frame */
            if (status & TD_ES) {             /* An error happened */
-               lp->stats.tx_errors++;
+               lp->stats.tx_errors++; 
                if (status & TD_NC) lp->stats.tx_carrier_errors++;
                if (status & TD_LC) lp->stats.tx_window_errors++;
                if (status & TD_UF) lp->stats.tx_fifo_errors++;
                if (status & TD_EC) lp->pktStats.excessive_collisions++;
                if (status & TD_DE) lp->stats.tx_aborted_errors++;
-
-               if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
-                   lp->lostMedia++;
-               }
+           
                if (TX_PKT_PENDING) {
                    outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
                }
            } else {                      /* Packet sent */
                lp->stats.tx_packets++;
-               lp->lostMedia = 0;        /* Remove transient problem */
-               lp->linkOK++;
+               if (lp->tx_enable) lp->linkOK++;
            }
            /* Update the collision counter */
-           lp->stats.collisions += ((status & TD_EC) ? 16 :
+           lp->stats.collisions += ((status & TD_EC) ? 16 : 
                                                      ((status & TD_CC) >> 3));
 
            /* Free the buffer. */
@@ -1371,7 +1512,7 @@ de4x5_tx(struct device *dev)
                lp->tx_skb[entry] = NULL;
            }
        }
-
+       
        /* Update all the pointers */
        lp->tx_old = (++lp->tx_old) % lp->txRingSize;
     }
@@ -1380,7 +1521,7 @@ de4x5_tx(struct device *dev)
        dev->tbusy = 0;                  /* Clear TX busy flag */
        if (dev->interrupt) mark_bh(NET_BH);
     }
-
+       
     return 0;
 }
 
@@ -1389,10 +1530,12 @@ de4x5_ast(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int next_tick = DE4X5_AUTOSENSE_MS;
-
+    
     disable_ast(dev);
-
-    if (lp->chipset == DC21140) {
+    
+    if (lp->useSROM) {
+       next_tick = srom_autoconf(dev);
+    } else if (lp->chipset == DC21140) {
        next_tick = dc21140m_autoconf(dev);
     } else if (lp->chipset == DC21041) {
        next_tick = dc21041_autoconf(dev);
@@ -1401,7 +1544,7 @@ de4x5_ast(struct device *dev)
     }
     lp->linkOK = 0;
     enable_ast(dev, next_tick);
-
+    
     return 0;
 }
 
@@ -1424,11 +1567,11 @@ de4x5_txur(struct device *dev)
        }
        outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
     }
-
+    
     return 0;
 }
 
-static int
+static int 
 de4x5_rx_ovfc(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -1445,7 +1588,7 @@ de4x5_rx_ovfc(struct device *dev)
     }
 
     outl(omr, DE4X5_OMR);
-
+    
     return 0;
 }
 
@@ -1455,22 +1598,22 @@ de4x5_close(struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 imr, omr;
-
+    
     disable_ast(dev);
     dev->start = 0;
     dev->tbusy = 1;
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_CLOSE) {
        printk("%s: Shutting down ethercard, status was %8.8x.\n",
               dev->name, inl(DE4X5_STS));
     }
-
-    /*
+    
+    /* 
     ** We stop the DE4X5 here... mask interrupts and stop TX & RX
     */
     DISABLE_IRQs;
     STOP_DE4X5;
-
+    
     /* Free the associated irq */
     free_irq(dev->irq, dev);
     lp->state = CLOSED;
@@ -1478,26 +1621,22 @@ de4x5_close(struct device *dev)
     /* Free any socket buffers */
     de4x5_free_rx_buffs(dev);
     de4x5_free_tx_buffs(dev);
-
+    
     MOD_DEC_USE_COUNT;
-
+    
     /* Put the adapter to sleep to save power */
-    if (lp->chipset == DC21041) {
-       outl(0, DE4X5_SICR);
-       outl(CFDA_PSM, PCI_CFDA);
-    }
-
+    yawn(dev, SLEEP);
+    
     return 0;
 }
 
-static struct enet_statistics *
-de4x5_get_stats(struct device *dev)
+static struct net_device_stats *de4x5_get_stats(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
+    
     lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
-
+    
     return &lp->stats;
 }
 
@@ -1523,7 +1662,7 @@ de4x5_local_stats(struct device *dev, char *buf, int pkt_len)
               (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
         lp->pktStats.unicast++;
     }
-
+               
     lp->pktStats.bins[0]++;       /* Duplicates stats.rx_packets */
     if (lp->pktStats.bins[0] == 0) { /* Reset counters */
         memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
@@ -1536,7 +1675,7 @@ static void
 load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+    
     lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf));
     lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
     lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
@@ -1544,7 +1683,7 @@ load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
     barrier();
     lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
     barrier();
-
+    
     return;
 }
 
@@ -1564,17 +1703,17 @@ set_multicast_list(struct device *dev)
            omr = inl(DE4X5_OMR);
            omr |= OMR_PR;
            outl(omr, DE4X5_OMR);
-       } else {
+       } else { 
            SetMulticastFilter(dev);
-           load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+           load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
                                                        SETUP_FRAME_LEN, NULL);
-
+           
            lp->tx_new = (++lp->tx_new) % lp->txRingSize;
            outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
            dev->trans_start = jiffies;
        }
     }
-
+    
     return;
 }
 
@@ -1598,26 +1737,26 @@ SetMulticastFilter(struct device *dev)
     omr = inl(DE4X5_OMR);
     omr &= ~(OMR_PR | OMR_PM);
     pa = build_setup_frame(dev, ALL);        /* Build the basic frame */
-
+    
     if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
        omr |= OMR_PM;                       /* Pass all multicasts */
     } else if (lp->setup_f == HASH_PERF) {   /* Hash Filtering */
        for (i=0;i<dev->mc_count;i++) {      /* for each address in the list */
            addrs=dmi->dmi_addr;
            dmi=dmi->next;
-           if ((*addrs & 0x01) == 1) {      /* multicast address? */
+           if ((*addrs & 0x01) == 1) {      /* multicast address? */ 
                crc = 0xffffffff;            /* init CRC for each address */
                for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
-                                            /* process each address bit */
+                                            /* process each address bit */ 
                    for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
                        crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
                    }
                }
                hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
-
+               
                byte = hashcode >> 3;        /* bit[3-8] -> byte in filter */
                bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */
-
+               
                byte <<= 1;                  /* calc offset into setup frame */
                if (byte & 0x02) {
                    byte -= 1;
@@ -1629,14 +1768,14 @@ SetMulticastFilter(struct device *dev)
        for (j=0; j<dev->mc_count; j++) {
            addrs=dmi->dmi_addr;
            dmi=dmi->next;
-           for (i=0; i<ETH_ALEN; i++) {
+           for (i=0; i<ETH_ALEN; i++) { 
                *(pa + (i&1)) = *addrs++;
                if (i & 0x01) pa += 4;
            }
        }
     }
     outl(omr, DE4X5_OMR);
-
+    
     return;
 }
 
@@ -1647,18 +1786,18 @@ SetMulticastFilter(struct device *dev)
 static void
 eisa_probe(struct device *dev, u_long ioaddr)
 {
-    int i, maxSlots, status;
-    u_short vendor, device;
-    s32 cfid;
+    int i, maxSlots, status, device;
+    u_short vendor;
+    u32 cfid;
     u_long iobase;
     struct bus_type *lp = &bus;
     char name[DE4X5_STRLEN];
     struct device *tmp;
-
-    if (!ioaddr && autoprobed) return;     /* Been here before ! */
-
+    
+    if (autoprobed) return;                /* Been here before ! */
+    
     lp->bus = EISA;
-
+    
     if (ioaddr == 0) {                     /* Autoprobing */
        iobase = EISA_SLOT_INC;            /* Get the first slot address */
        i = 1;
@@ -1668,31 +1807,33 @@ eisa_probe(struct device *dev, u_long ioaddr)
        i = (ioaddr >> 12);
        maxSlots = i + 1;
     }
-
-    for (status = -ENODEV;
-        (i<maxSlots) && (dev!=NULL) && (!loading_module || (num_de4x5s == 0));
-        i++, iobase+=EISA_SLOT_INC) {
+    
+    for (status= -ENODEV;(i<maxSlots)&&(dev!=NULL);i++,iobase+=EISA_SLOT_INC) {
        if (EISA_signature(name, EISA_ID)) {
-           cfid = inl(PCI_CFID);
-           cfrv = inl(PCI_CFRV);
-           device = (u_short)(cfid >> 16);
+           cfid = (u32) inl(PCI_CFID);
+           cfrv = (u_short) inl(PCI_CFRV);
+           device = (cfid >> 8) & 0x00ffff00;
            vendor = (u_short) cfid;
-
+           
            /* Read the EISA Configuration Registers */
            dev->irq = inb(EISA_REG0);
            dev->irq = de4x5_irq[(dev->irq >> 1) & 0x03];
 
+           if (is_DC2114x) device |= (cfrv & 0x00f0);
            lp->chipset = device;
            DevicePresent(DE4X5_APROM);
            /* Write the PCI Configuration Registers */
            outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
            outl(0x00006000, PCI_CFLT);
            outl(iobase, PCI_CBIO);
-
+           
            if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
                if ((tmp = alloc_device(dev, iobase)) != NULL) {
                    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
                        num_de4x5s++;
+                       if (loading_module) link_modules(dev, tmp);
+                   } else if (loading_module && (tmp != dev)) {
+                       kfree(tmp);
                    }
                }
            } else if (autoprobed) {
@@ -1700,7 +1841,7 @@ eisa_probe(struct device *dev, u_long ioaddr)
            }
        }
     }
-
+    
     return;
 }
 
@@ -1724,18 +1865,18 @@ pci_probe(struct device *dev, u_long ioaddr)
 {
     u_char irq;
     u_char pb, pbus, dev_num, dnum, dev_fn;
-    u_short vendor, device, index, status;
+    u_short vendor, index, status;
     u_int class = DE4X5_CLASS_CODE;
-    u_int iobase;
+    u_int device, iobase;
     struct bus_type *lp = &bus;
     struct device *tmp;
 
-    if ((!ioaddr || !loading_module) && autoprobed) return;
-
+    if (autoprobed) return;
+    
     if (!pcibios_present()) return;          /* No PCI bus in this machine! */
-
+    
     lp->bus = PCI;
-
+    
     if ((ioaddr < 0x1000) && loading_module) {
        pbus = (u_short)(ioaddr >> 8);
        dnum = (u_short)(ioaddr & 0xff);
@@ -1744,26 +1885,35 @@ pci_probe(struct device *dev, u_long ioaddr)
        dnum = 0;
     }
 
-    for (index=0;
-        (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND) &&
-        (!loading_module || (num_de4x5s == 0));
+    for (index=0; 
+        (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
         index++) {
        dev_num = PCI_SLOT(dev_fn);
 
        if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
+           device = 0;
            pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
-           pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
-           if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue;
+           pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device);
+           device <<= 8;
+           if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
+               continue;
+           }
+
+           /* Get the chip configuration revision register */
+           pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
 
            /* Set the device number information */
            lp->device = dev_num;
            lp->bus_num = pb;
-
+           
            /* Set the chipset information */
+           if (is_DC2114x) device |= (cfrv & 0x00f0);
            lp->chipset = device;
 
-           /* Get the chip configuration revision register */
-           pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+           if (is_DC21142 || is_DC21143) {
+               printk("de4x5: Detected a %s chip. Currently this is unsupported in this driver.\nPlease email the author to request its inclusion!\n", (is_DC21142?"DC21142":"DC21143"));
+               continue;
+           }
 
            /* Get the board I/O address */
            pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
@@ -1772,7 +1922,7 @@ pci_probe(struct device *dev, u_long ioaddr)
            /* Fetch the IRQ to be used */
            pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
            if ((irq == 0) || (irq == (u_char) 0xff)) continue;
-
+           
            /* Check if I/O accesses and Bus Mastering are enabled */
            pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
            if (!(status & PCI_COMMAND_IO)) continue;
@@ -1789,15 +1939,18 @@ pci_probe(struct device *dev, u_long ioaddr)
                    tmp->irq = irq;
                    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
                        num_de4x5s++;
+                       if (loading_module) link_modules(dev, tmp);
+                   } else if (loading_module && (tmp != dev)) {
+                       kfree(tmp);
                    }
                }
            } else if (autoprobed) {
-               printk("%s: region already allocated at 0x%04x.\n", dev->name,
+               printk("%s: region already allocated at 0x%04x.\n", dev->name, 
                       (u_short)iobase);
            }
        }
     }
-
+    
     return;
 }
 
@@ -1813,8 +1966,16 @@ alloc_device(struct device *dev, u_long iobase)
     struct device *adev = NULL;
     int fixed = 0, new_dev = 0;
 
+    if (!dev) return dev;
     num_eth = de4x5_dev_index(dev->name);
-    if (loading_module) return dev;
+
+    if (loading_module) {
+       if (dev->priv) {
+           dev = insert_device(dev, iobase, de4x5_probe);
+       }
+       num_eth++;
+       return dev;
+    }
 
     while (1) {
        if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) {
@@ -1838,13 +1999,13 @@ alloc_device(struct device *dev, u_long iobase)
        new_dev = 0;
     }
 
-    if (((dev->next == NULL) &&
+    if (((dev->next == NULL) &&  
        ((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) ||
        new_dev) {
        num_eth++;                         /* New device */
        dev = insert_device(dev, iobase, de4x5_probe);
     }
-
+    
     return dev;
 }
 
@@ -1862,20 +2023,22 @@ insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))
        printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
        return NULL;
     } else {
-       new->next = dev->next;
-       dev->next = new;
-       dev = dev->next;               /* point to the new device */
-       dev->name = (char *)(dev + 1);
-       if (num_eth > 9999) {
-           sprintf(dev->name,"eth????");/* New device name */
-       } else {
-           sprintf(dev->name,"eth%d", num_eth);/* New device name */
+       memset((char *)new, 0, sizeof(struct device)+8);
+       new->name = (char *)(new + 1);
+       new->base_addr = iobase;       /* assign the io address */
+       new->init = init;              /* initialisation routine */
+       if (!loading_module) {
+           new->next = dev->next;
+           dev->next = new;
+           if (num_eth > 9999) {
+               sprintf(new->name,"eth????");/* New device name */
+           } else {
+               sprintf(new->name,"eth%d", num_eth);/* New device name */
+           }
        }
-       dev->base_addr = iobase;       /* assign the io address */
-       dev->init = init;              /* initialisation routine */
     }
 
-    return dev;
+    return new;
 }
 
 static int
@@ -1893,11 +2056,54 @@ de4x5_dev_index(char *s)
     return i;
 }
 
+static void
+link_modules(struct device *dev, struct device *tmp)
+{
+    struct device *p=dev;
+
+    if (p) {
+       while (((struct de4x5_private *)(p->priv))->next_module) {
+           p = ((struct de4x5_private *)(p->priv))->next_module;
+       }
+
+       if (dev != tmp) {
+           ((struct de4x5_private *)(p->priv))->next_module = tmp;
+       } else {
+           ((struct de4x5_private *)(p->priv))->next_module = NULL;
+       }
+    }
+
+    return;
+}
+
+static struct device *
+unlink_modules(struct device *p)
+{
+    struct device *next = NULL;
+
+    if (p->priv) {                          /* Private areas allocated?  */
+       struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+       next = lp->next_module;
+       if (lp->cache.buf) {                /* MAC buffers allocated?    */
+           kfree(lp->cache.buf);           /* Free the MAC buffers      */
+       }
+       kfree(lp->cache.priv);              /* Free the private area     */
+       release_region(p->base_addr, (lp->bus == PCI ? 
+                                     DE4X5_PCI_TOTAL_SIZE :
+                                     DE4X5_EISA_TOTAL_SIZE));
+    }
+    unregister_netdev(p);
+    kfree(p);                               /* Free the device structure */
+    
+    return next;
+}
+
 /*
 ** Auto configure the media here rather than setting the port at compile
 ** time. This routine is called by de4x5_init() and when a loss of media is
 ** detected (excessive collisions, loss of carrier, no carrier or link fail
-** [TP] or no recent receive activity) to check whether the user has been
+** [TP] or no recent receive activity) to check whether the user has been 
 ** sneaky and changed the port on us.
 */
 static int
@@ -1906,21 +2112,24 @@ autoconf_media(struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;;
-
+    
     lp->linkOK = 0;
     lp->c_media = AUTO;                     /* Bogus last media */
     disable_ast(dev);
     inl(DE4X5_MFC);                         /* Zero the lost frames counter */
     lp->media = INIT;
-    if (lp->chipset == DC21040) {
+    if (lp->useSROM) {
+       next_tick = srom_autoconf(dev);
+    } else if (lp->chipset == DC21040) {
        next_tick = dc21040_autoconf(dev);
     } else if (lp->chipset == DC21041) {
        next_tick = dc21041_autoconf(dev);
     } else if (lp->chipset == DC21140) {
        next_tick = dc21140m_autoconf(dev);
     }
-    enable_ast(dev, next_tick);
 
+    enable_ast(dev, next_tick);
+    
     return (lp->media);
 }
 
@@ -1943,7 +2152,7 @@ dc21040_autoconf(struct device *dev)
     u_long iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     s32 imr;
-
+    
     switch (lp->media) {
       case INIT:
        DISABLE_IRQs;
@@ -1962,36 +2171,36 @@ dc21040_autoconf(struct device *dev)
        lp->local_state = 0;
        next_tick = dc21040_autoconf(dev);
        break;
-
+       
       case TP:
-       next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI,
+       next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
                                                         TP_SUSPECT, test_tp);
        break;
-
+       
       case TP_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
        break;
-
+       
       case BNC:
       case AUI:
       case BNC_AUI:
-       next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA,
+       next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
                                                  BNC_AUI_SUSPECT, ping_media);
        break;
-
+       
       case BNC_AUI_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
        break;
-
+       
       case EXT_SIA:
-       next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000,
+       next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
                                              NC, EXT_SIA_SUSPECT, ping_media);
        break;
-
+       
       case EXT_SIA_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
        break;
-
+       
       case NC:
        /* default to TP for all */
        reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
@@ -2003,13 +2212,13 @@ dc21040_autoconf(struct device *dev)
        lp->tx_enable = NO;
        break;
     }
-
+    
     return next_tick;
 }
 
 static int
 dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
-             int next_state, int suspect_state,
+             int next_state, int suspect_state, 
              int (*fn)(struct device *, int))
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -2022,7 +2231,7 @@ dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
        lp->local_state++;
        next_tick = 500;
        break;
-
+           
       case 1:
        if (!lp->tx_enable) {
            linkBad = fn(dev, timeout);
@@ -2042,7 +2251,7 @@ dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
        }
        break;
     }
-
+    
     return next_tick;
 }
 
@@ -2057,7 +2266,7 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
 
     switch (lp->local_state) {
       case 1:
-       if (lp->linkOK && !LOST_MEDIA) {
+       if (lp->linkOK) {
            lp->media = prev_state;
        } else {
            lp->local_state++;
@@ -2096,7 +2305,7 @@ dc21041_autoconf(struct device *dev)
     u_long iobase = dev->base_addr;
     s32 sts, irqs, irq_mask, imr, omr;
     int next_tick = DE4X5_AUTOSENSE_MS;
-
+    
     switch (lp->media) {
       case INIT:
        DISABLE_IRQs;
@@ -2117,11 +2326,11 @@ dc21041_autoconf(struct device *dev)
        lp->local_state = 0;
        next_tick = dc21041_autoconf(dev);
        break;
-
+       
       case TP_NW:
        if (lp->timeout < 0) {
            omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
-           outl(omr | OMR_FD, DE4X5_OMR);
+           outl(omr | OMR_FDX, DE4X5_OMR);
        }
        irqs = STS_LNF | STS_LNP;
        irq_mask = IMR_LFM | IMR_LPM;
@@ -2137,7 +2346,7 @@ dc21041_autoconf(struct device *dev)
            next_tick = dc21041_autoconf(dev);
        }
        break;
-
+       
       case ANS:
        if (!lp->tx_enable) {
            irqs = STS_LNP;
@@ -2159,16 +2368,16 @@ dc21041_autoconf(struct device *dev)
            next_tick = 3000;
        }
        break;
-
+       
       case ANS_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
        break;
-
+       
       case TP:
        if (!lp->tx_enable) {
            if (lp->timeout < 0) {
                omr = inl(DE4X5_OMR);          /* Set up half duplex for TP */
-               outl(omr & ~OMR_FD, DE4X5_OMR);
+               outl(omr & ~OMR_FDX, DE4X5_OMR);
            }
            irqs = STS_LNF | STS_LNP;
            irq_mask = IMR_LFM | IMR_LPM;
@@ -2193,16 +2402,16 @@ dc21041_autoconf(struct device *dev)
            next_tick = 3000;
        }
        break;
-
+       
       case TP_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
        break;
-
+       
       case AUI:
        if (!lp->tx_enable) {
            if (lp->timeout < 0) {
                omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
-               outl(omr & ~OMR_FD, DE4X5_OMR);
+               outl(omr & ~OMR_FDX, DE4X5_OMR);
            }
            irqs = 0;
            irq_mask = 0;
@@ -2223,17 +2432,17 @@ dc21041_autoconf(struct device *dev)
            next_tick = 3000;
        }
        break;
-
+       
       case AUI_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
        break;
-
+       
       case BNC:
        switch (lp->local_state) {
          case 0:
            if (lp->timeout < 0) {
                omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
-               outl(omr & ~OMR_FD, DE4X5_OMR);
+               outl(omr & ~OMR_FDX, DE4X5_OMR);
            }
            irqs = 0;
            irq_mask = 0;
@@ -2245,7 +2454,7 @@ dc21041_autoconf(struct device *dev)
                next_tick = dc21041_autoconf(dev);
            }
            break;
-
+           
          case 1:
            if (!lp->tx_enable) {
                if ((sts = ping_media(dev, 3000)) < 0) {
@@ -2265,14 +2474,14 @@ dc21041_autoconf(struct device *dev)
            break;
        }
        break;
-
+       
       case BNC_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
        break;
-
+       
       case NC:
        omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
-       outl(omr | OMR_FD, DE4X5_OMR);
+       outl(omr | OMR_FDX, DE4X5_OMR);
        reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
        if (lp->media != lp->c_media) {
            de4x5_dbg_media(dev);
@@ -2282,7 +2491,7 @@ dc21041_autoconf(struct device *dev)
        lp->tx_enable = NO;
        break;
     }
-
+    
     return next_tick;
 }
 
@@ -2300,38 +2509,43 @@ dc21140m_autoconf(struct device *dev)
     u_long imr, omr;
 
     switch(lp->media) {
-      case INIT:
+      case INIT: 
        DISABLE_IRQs;
        lp->tx_enable = FALSE;
-       lp->timeout = -1;
+        lp->linkOK = 0;
+/*     lp->timeout = -1;*/
        if ((next_tick = de4x5_reset_phy(dev)) < 0) {
            next_tick &= ~TIMER_CB;
        } else {
            de4x5_save_skbs(dev);          /* Save non transmitted skb's */
-           lp->tmp = MII_SR_ASSC;         /* Fake out the MII speed set */
-           SET_10Mb;
-           if (lp->autosense == _100Mb) {
-               lp->media = _100Mb;
-           } else if (lp->autosense == _10Mb) {
-               lp->media = _10Mb;
-           } else if ((lp->autosense == AUTO) &&
-                                    ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
-               ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
-               ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM);
-               mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-               lp->media = ANS;
-           } else if (lp->autosense == AUTO) {
-               lp->media = SPD_DET;
-           } else if (is_spd_100(dev) && is_100_up(dev)) {
-               lp->media = _100Mb;
+           if (lp->useSROM) {
+               srom_map_media(dev);
            } else {
-               lp->media = NC;
+               lp->tmp = MII_SR_ASSC;     /* Fake out the MII speed set */
+               SET_10Mb;
+               if (lp->autosense == _100Mb) {
+                   lp->media = _100Mb;
+               } else if (lp->autosense == _10Mb) {
+                   lp->media = _10Mb;
+               } else if ((lp->autosense == AUTO) && 
+                                   ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+                   ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+                   ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+                   mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+                   lp->media = ANS;
+               } else if (lp->autosense == AUTO) {
+                   lp->media = SPD_DET;
+               } else if (is_spd_100(dev) && is_100_up(dev)) {
+                   lp->media = _100Mb;
+               } else {
+                   lp->media = NC;
+               }
            }
            lp->local_state = 0;
            next_tick = dc21140m_autoconf(dev);
        }
        break;
-
+       
       case ANS:
        switch (lp->local_state) {
          case 0:
@@ -2351,7 +2565,7 @@ dc21140m_autoconf(struct device *dev)
                next_tick = dc21140m_autoconf(dev);
            }
            break;
-
+           
          case 1:
            if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
                next_tick = sr & ~TIMER_CB;
@@ -2362,13 +2576,13 @@ dc21140m_autoconf(struct device *dev)
                    lp->tmp = MII_SR_ASSC;
                    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
                    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-                   if (!(anlpa & MII_ANLPA_RF) &&
+                   if (!(anlpa & MII_ANLPA_RF) && 
                         (cap = anlpa & MII_ANLPA_TAF & ana)) {
                        if (cap & MII_ANA_100M) {
-                           de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
                            lp->media = _100Mb;
                        } else if (cap & MII_ANA_10M) {
-                           de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
 
                            lp->media = _10Mb;
                        }
@@ -2379,7 +2593,7 @@ dc21140m_autoconf(struct device *dev)
            break;
        }
        break;
-
+       
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
         if (lp->timeout < 0) {
            lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
@@ -2399,9 +2613,9 @@ dc21140m_autoconf(struct device *dev)
            next_tick = dc21140m_autoconf(dev);
        }
        break;
-
+       
       case _100Mb:                               /* Set 100Mb/s */
-       next_tick = 3000;
+        next_tick = 3000;
        if (!lp->tx_enable) {
            SET_100Mb;
            de4x5_init_connection(dev);
@@ -2409,14 +2623,15 @@ dc21140m_autoconf(struct device *dev)
            if (!lp->linkOK && (lp->autosense == AUTO)) {
                if (!(is_spd_100(dev) && is_100_up(dev))) {
                    lp->media = INIT;
+                   lp->tcount++;
                    next_tick = DE4X5_AUTOSENSE_MS;
                }
            }
        }
        break;
-
+       
       case _10Mb:                                /* Set 10Mb/s */
-       next_tick = 3000;
+        next_tick = 3000;
        if (!lp->tx_enable) {
            SET_10Mb;
            de4x5_init_connection(dev);
@@ -2424,12 +2639,13 @@ dc21140m_autoconf(struct device *dev)
            if (!lp->linkOK && (lp->autosense == AUTO)) {
                if (!(!is_spd_100(dev) && is_10_up(dev))) {
                    lp->media = INIT;
+                   lp->tcount++;
                    next_tick = DE4X5_AUTOSENSE_MS;
                }
            }
        }
        break;
-
+       
       case NC:
         if (lp->media != lp->c_media) {
            de4x5_dbg_media(dev);
@@ -2439,10 +2655,76 @@ dc21140m_autoconf(struct device *dev)
        lp->tx_enable = FALSE;
        break;
     }
-
+    
     return next_tick;
 }
 
+static int
+srom_autoconf(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    return lp->infoleaf_fn(dev);
+}
+
+/*
+** This mapping keeps the original media codes and FDX flag unchanged.
+** While it isn't strictly necessary, it helps me for the moment...
+*/
+static void
+srom_map_media(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    lp->fdx = 0;
+    switch(lp->infoblock_media) {
+      case SROM_10BASETF:
+       lp->fdx = TRUE;
+      case SROM_10BASET:
+       if (lp->chipset == DC21140) {
+           lp->media = _10Mb;
+       } else {
+           lp->media = TP;
+       }
+       break;
+
+      case SROM_10BASE2:
+       lp->media = BNC;
+       break;
+
+      case SROM_10BASE5:
+       lp->media = AUI;
+       break;
+
+      case SROM_100BASETF:
+       lp->fdx = TRUE;
+      case SROM_100BASET:
+       lp->media = _100Mb;
+       break;
+
+      case SROM_100BASET4:
+       lp->media = _100Mb;
+       break;
+
+      case SROM_100BASEFF:
+       lp->fdx = TRUE;
+      case SROM_100BASEF: 
+       lp->media = _100Mb;
+       break;
+
+      case ANS:
+       lp->media = ANS;
+       break;
+
+      default: 
+       printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
+                                                         lp->infoblock_media);
+       break;
+    }
+
+    return;
+}
+
 static void
 de4x5_init_connection(struct device *dev)
 {
@@ -2457,7 +2739,6 @@ de4x5_init_connection(struct device *dev)
     cli();
     de4x5_rx(dev);
     de4x5_setup_intr(dev);
-    lp->lostMedia = 0;
     lp->tx_enable = YES;
     dev->tbusy = 0;
     sti();
@@ -2467,6 +2748,9 @@ de4x5_init_connection(struct device *dev)
     return;
 }
 
+/*
+** General PHY reset function.
+*/
 static int
 de4x5_reset_phy(struct device *dev)
 {
@@ -2474,15 +2758,26 @@ de4x5_reset_phy(struct device *dev)
     u_long iobase = dev->base_addr;
     int next_tick = 0;
 
-    if (lp->phy[lp->active].id) {
+    if ((lp->useSROM) || (lp->phy[lp->active].id)) {
        if (lp->timeout < 0) {
-           outl(GEP_HRST, DE4X5_GEP);           /* Hard RESET the PHY dev. */
-           udelay(1000);                        /* Assert for 1ms */
-           outl(0x00, DE4X5_GEP);
-           udelay(2000);                        /* Wait for 2ms */
-           mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+           if (lp->useSROM) {
+               if (lp->phy[lp->active].rst) { /* MII device specific reset */
+                   srom_exec(dev, lp->phy[lp->active].rst);
+               } else if (lp->rst) {          /* Type 5 infoblock reset */
+                   srom_exec(dev, lp->rst);
+               }
+           } else {
+               PHY_HARD_RESET;
+           }
+           if (lp->useMII) {
+               mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+            }
+        }
+       if (lp->useMII) {
+           next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
        }
-       next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
+    } else if (lp->chipset == DC21140) {
+       PHY_HARD_RESET;
     }
 
     return next_tick;
@@ -2494,7 +2789,7 @@ test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 sts, csr12;
-
+    
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
        reset_init_sia(dev, csr13, csr14, csr15);
@@ -2505,22 +2800,22 @@ test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32
        /* clear all pending interrupts */
        sts = inl(DE4X5_STS);
        outl(sts, DE4X5_STS);
-
+       
        /* clear csr12 NRA and SRA bits */
        if (lp->chipset == DC21041) {
            csr12 = inl(DE4X5_SISR);
            outl(csr12, DE4X5_SISR);
        }
     }
-
+    
     sts = inl(DE4X5_STS) & ~TIMER_CB;
-
+    
     if (!(sts & irqs) && --lp->timeout) {
        sts = 100 | TIMER_CB;
     } else {
        lp->timeout = -1;
     }
-
+    
     return sts;
 }
 
@@ -2530,11 +2825,11 @@ test_tp(struct device *dev, s32 msec)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int sisr;
-
+    
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
     }
-
+    
     sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
 
     if (sisr && --lp->timeout) {
@@ -2542,7 +2837,7 @@ test_tp(struct device *dev, s32 msec)
     } else {
        lp->timeout = -1;
     }
-
+    
     return sisr;
 }
 
@@ -2552,12 +2847,12 @@ test_sym_link(struct device *dev, int msec)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
     int gep = 0;
-
+    
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
     }
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->phy[lp->active].id || lp->useSROM) {
        gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
     } else {
        gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
@@ -2567,7 +2862,7 @@ test_sym_link(struct device *dev, int msec)
     } else {
        lp->timeout = -1;
     }
-
+    
     return gep;
 }
 
@@ -2580,21 +2875,21 @@ test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int test, iobase = dev->base_addr;
-
+    
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
     }
-
+    
     if (pol) pol = ~0;
     reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
     test = (reg ^ pol) & mask;
-
+    
     if (test && --lp->timeout) {
        reg = 100 | TIMER_CB;
     } else {
        lp->timeout = -1;
     }
-
+    
     return reg;
 }
 
@@ -2604,15 +2899,19 @@ is_spd_100(struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int spd;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->useSROM && !lp->useMII) {
+       spd = (lp->asBitValid & 
+              (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
+                (lp->linkOK & ~lp->asBitValid);
+    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
        spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
        spd = ~(spd ^ lp->phy[lp->active].spd.value);
        spd &= lp->phy[lp->active].spd.mask;
     } else {
        spd = ((~inl(DE4X5_GEP)) & GEP_SLNK);
     }
-
+    
     return spd;
 }
 
@@ -2621,8 +2920,12 @@ is_100_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->useSROM && !lp->useMII) {
+       return ((lp->asBitValid & 
+                (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
+               (lp->linkOK & ~lp->asBitValid));
+    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
        /* Double read for sticky bits & temporary drops */
        mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
@@ -2636,8 +2939,12 @@ is_10_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->useSROM && !lp->useMII) {
+       return ((lp->asBitValid & 
+                (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
+               (lp->linkOK & ~lp->asBitValid));
+    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
        /* Double read for sticky bits & temporary drops */
        mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
@@ -2651,8 +2958,8 @@ is_anc_capable(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
     } else {
        return 0;
@@ -2669,24 +2976,24 @@ ping_media(struct device *dev, int msec)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int sisr;
-
+    
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
-
+       
        lp->tmp = lp->tx_new;                /* Remember the ring position */
        load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL);
        lp->tx_new = (++lp->tx_new) % lp->txRingSize;
        outl(POLL_DEMAND, DE4X5_TPD);
     }
-
+    
     sisr = inl(DE4X5_SISR);
 
-    if ((!(sisr & SISR_NCR)) &&
-       ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) &&
+    if ((!(sisr & SISR_NCR)) && 
+       ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && 
         (--lp->timeout)) {
        sisr = 100 | TIMER_CB;
     } else {
-       if ((!(sisr & SISR_NCR)) &&
+       if ((!(sisr & SISR_NCR)) && 
            !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
            lp->timeout) {
            sisr = 0;
@@ -2695,7 +3002,7 @@ ping_media(struct device *dev, int msec)
        }
        lp->timeout = -1;
     }
-
+    
     return sisr;
 }
 
@@ -2742,15 +3049,15 @@ de4x5_alloc_rx_buff(struct device *dev, int index, int len)
     skb_reserve(p, 2);                                /* Align */
     if (index < lp->rx_old) {                          /* Wrapped buffer */
        short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-       memcpy(skb_put(p,tlen),
+       memcpy(skb_put(p,tlen), 
               bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),tlen);
-       memcpy(skb_put(p,len-tlen),
+       memcpy(skb_put(p,len-tlen), 
               bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len-tlen);
     } else {                                           /* Linear buffer */
-       memcpy(skb_put(p,len),
+       memcpy(skb_put(p,len), 
               bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),len);
     }
-
+                   
     return p;
 #endif
 }
@@ -2837,7 +3144,7 @@ de4x5_restore_skbs(struct device *dev)
        lp->cache.save_cnt--;
        START_DE4X5;
     }
-
+        
     return;
 }
 
@@ -2846,7 +3153,6 @@ de4x5_cache_state(struct device *dev, int flag)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    s32 gep;
 
     switch(flag) {
       case DE4X5_SAVE_STATE:
@@ -2865,14 +3171,10 @@ de4x5_cache_state(struct device *dev, int flag)
        outl(lp->cache.csr6, DE4X5_OMR);
        outl(lp->cache.csr7, DE4X5_IMR);
        if (lp->chipset == DC21140) {
-           outl(GEP_INIT, DE4X5_GEP);
-           gep = (lp->media == _100Mb ? GEP_MODE : 0);
-           if (!lp->phy[lp->active].id && !de4x5_full_duplex) {
-               gep |= GEP_FDXD;
-           }
-           outl(gep, DE4X5_GEP);
+           outl(lp->cache.gepc, DE4X5_GEP);
+           outl(lp->cache.gep, DE4X5_GEP);
        } else {
-           reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14,
+           reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, 
                                                              lp->cache.csr15);
        }
        break;
@@ -2934,25 +3236,25 @@ test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 sts, ans;
-
+    
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
        outl(irq_mask, DE4X5_IMR);
-
+       
        /* clear all pending interrupts */
        sts = inl(DE4X5_STS);
        outl(sts, DE4X5_STS);
     }
-
+    
     ans = inl(DE4X5_SISR) & SISR_ANS;
     sts = inl(DE4X5_STS) & ~TIMER_CB;
-
+    
     if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
        sts = 100 | TIMER_CB;
     } else {
        lp->timeout = -1;
     }
-
+    
     return sts;
 }
 
@@ -2962,7 +3264,7 @@ de4x5_setup_intr(struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 imr, sts;
-
+    
     if (inl(DE4X5_OMR) & OMR_SR) {   /* Only unmask if TX/RX is enabled */
        imr = 0;
        UNMASK_IRQs;
@@ -2970,7 +3272,7 @@ de4x5_setup_intr(struct device *dev)
        outl(sts, DE4X5_STS);
        ENABLE_IRQs;
     }
-
+    
     return;
 }
 
@@ -2982,7 +3284,7 @@ reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
+    
     RESET_SIA;
     outl(sigr, DE4X5_SIGR);
     outl(strr, DE4X5_STRR);
@@ -2992,24 +3294,24 @@ reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 }
 
 /*
-** Create a loopback ethernet packet with an invalid CRC
+** Create a loopback ethernet packet
 */
 static void
 create_packet(struct device *dev, char *frame, int len)
 {
     int i;
     char *buf = frame;
-
+    
     for (i=0; i<ETH_ALEN; i++) {             /* Use this source address */
        *buf++ = dev->dev_addr[i];
     }
     for (i=0; i<ETH_ALEN; i++) {             /* Use this destination address */
        *buf++ = dev->dev_addr[i];
     }
-
+    
     *buf++ = 0;                              /* Packet length (2 bytes) */
     *buf++ = 1;
-
+    
     return;
 }
 
@@ -3020,7 +3322,7 @@ static void
 de4x5_us_delay(u32 usec)
 {
     udelay(usec);
-
+    
     return;
 }
 
@@ -3031,11 +3333,11 @@ static void
 de4x5_ms_delay(u32 msec)
 {
     u_int i;
-
+    
     for (i=0; i<msec; i++) {
        de4x5_us_delay(1000);
     }
-
+    
     return;
 }
 
@@ -3053,17 +3355,17 @@ EISA_signature(char *name, s32 eisa_id)
        char Id[4];
     } Eisa;
     int i, status = 0, siglen = sizeof(signatures)/sizeof(c_char *);
-
+    
     *name = '\0';
     Eisa.ID = inl(eisa_id);
-
+    
     ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
     ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
     ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
     ManCode[3]=((Eisa.Id[2]&0x0f)+0x30);
     ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
     ManCode[5]='\0';
-
+    
     for (i=0;i<siglen;i++) {
        if (strstr(ManCode, signatures[i]) != NULL) {
            strcpy(name,ManCode);
@@ -3071,7 +3373,7 @@ EISA_signature(char *name, s32 eisa_id)
            break;
        }
     }
-
+    
     return status;                         /* return the device name string */
 }
 
@@ -3083,16 +3385,13 @@ PCI_signature(char *name, struct bus_type *lp)
 {
     c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
     int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
-
+    
     if (lp->chipset == DC21040) {
        strcpy(name, "DE434/5");
-    } else {
+       return status;
+    } else {                           /* Search for a DEC name in the SROM */
        int i = *((char *)&lp->srom + 19) * 3;
-       if (lp->chipset == DC21041) {
-           strncpy(name, (char *)&lp->srom + 26 + i, 8);
-       } else if (lp->chipset == DC21140) {
-           strncpy(name, (char *)&lp->srom + 26 + i, 8);
-       }
+       strncpy(name, (char *)&lp->srom + 26 + i, 8);
     }
     name[8] = '\0';
     for (i=0; i<siglen; i++) {
@@ -3104,11 +3403,16 @@ PCI_signature(char *name, struct bus_type *lp)
        } else {                        /* Use chip name to avoid confusion */
            strcpy(name, (((lp->chipset == DC21040) ? "DC21040" :
                           ((lp->chipset == DC21041) ? "DC21041" :
-                           ((lp->chipset == DC21140) ? "DC21140" : "UNKNOWN"
-                            )))));
+                           ((lp->chipset == DC21140) ? "DC21140" :
+                            ((lp->chipset == DC21142) ? "DC21142" :
+                             ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN"
+                            )))))));
+       }
+       if (lp->chipset != DC21041) {
+           useSROM = TRUE;             /* card is not recognisably DEC */
        }
     }
-
+    
     return status;
 }
 
@@ -3121,7 +3425,7 @@ DevicePresent(u_long aprom_addr)
 {
     int i;
     struct bus_type *lp = &bus;
-
+    
     if (lp->chipset == DC21040) {
        outl(0, aprom_addr);           /* Reset Ethernet Address ROM Pointer */
     } else {                           /* Read new srom */
@@ -3131,10 +3435,16 @@ DevicePresent(u_long aprom_addr)
        }
        de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
     }
-
+    
     return;
 }
 
+/*
+** For the bad status case and no SROM, then add one to the previous
+** address. However, need to add one backwards in case we have 0xff
+** as one or more of the bytes. Only the last 3 bytes should be checked
+** as the first three are invariant - assigned to an organisation.
+*/
 static int
 get_hw_addr(struct device *dev)
 {
@@ -3147,7 +3457,7 @@ get_hw_addr(struct device *dev)
     for (i=0,k=0,j=0;j<3;j++) {
        k <<= 1;
        if (k > 0xffff) k-=0xffff;
-
+       
        if (lp->bus == PCI) {
            if (lp->chipset == DC21040) {
                while ((tmp = inl(DE4X5_APROM)) < 0);
@@ -3169,11 +3479,11 @@ get_hw_addr(struct device *dev)
            k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
            dev->dev_addr[i++] = (u_char) tmp;
        }
-
+       
        if (k > 0xffff) k-=0xffff;
     }
     if (k == 0xffff) k=0;
-
+    
     if (lp->bus == PCI) {
        if (lp->chipset == DC21040) {
            while ((tmp = inl(DE4X5_APROM)) < 0);
@@ -3188,6 +3498,12 @@ get_hw_addr(struct device *dev)
        if ((k != chksum) && (dec_only)) status = -1;
     }
 
+    /* If possible, try to fix a broken card - SMC only so far */
+    srom_repair(dev, broken);
+
+    /* Test for a bad enet address */
+    status = test_bad_enet(dev, status);
+
     return status;
 }
 
@@ -3227,6 +3543,55 @@ de4x5_strncmp(char *a, char *b, int n)
     return ret;
 }
 
+static void
+srom_repair(struct device *dev, int card)
+{
+    struct bus_type *lp = &bus;
+
+    switch(card) {
+      case SMC:
+       memset((char *)&bus.srom, 0, sizeof(struct de4x5_srom));
+       memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
+       memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
+       useSROM = TRUE;
+       break;
+    }
+
+    return;
+}
+
+static int
+test_bad_enet(struct device *dev, int status)
+{
+    struct bus_type *lp = &bus;
+    int i, tmp;
+
+    for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
+    if ((tmp == 0) || (tmp == 0x5fa)) {
+       if ((lp->chipset == last.chipset) && 
+           (lp->bus_num == last.bus) && (lp->bus_num > 0)) {
+           for (i=0; i<ETH_ALEN; i++) dev->dev_addr[i] = last.addr[i];
+           for (i=ETH_ALEN-1; i>2; --i) {
+               dev->dev_addr[i] += 1;
+               if (dev->dev_addr[i] != 0) break;
+           }
+           for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+           if (((*((int *)dev->dev_addr) & 0x00ffffff) == 0x95c000) &&
+               (lp->chipset == DC21040)) {
+               dev->irq = last.irq;
+           }
+           status = 0;
+       }
+    } else if (!status) {
+       last.chipset = lp->chipset;
+       last.bus = lp->bus_num;
+       last.irq = dev->irq;
+       for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+    }
+
+    return status;
+}
+
 /*
 ** SROM Read
 */
@@ -3234,11 +3599,11 @@ static short
 srom_rd(u_long addr, u_char offset)
 {
     sendto_srom(SROM_RD | SROM_SR, addr);
-
+    
     srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
     srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
     srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
-
+    
     return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
@@ -3248,7 +3613,7 @@ srom_latch(u_int command, u_long addr)
     sendto_srom(command, addr);
     sendto_srom(command | DT_CLK, addr);
     sendto_srom(command, addr);
-
+    
     return;
 }
 
@@ -3258,7 +3623,7 @@ srom_command(u_int command, u_long addr)
     srom_latch(command, addr);
     srom_latch(command, addr);
     srom_latch((command & 0x0000ff00) | DT_CS, addr);
-
+    
     return;
 }
 
@@ -3267,18 +3632,18 @@ srom_address(u_int command, u_long addr, u_char offset)
 {
     int i;
     char a;
-
+    
     a = (char)(offset << 2);
     for (i=0; i<6; i++, a <<= 1) {
        srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
     }
     de4x5_us_delay(1);
-
+    
     i = (getfrom_srom(addr) >> 3) & 0x01;
     if (i != 0) {
        printk("Bad SROM address phase.....\n");
     }
-
+    
     return;
 }
 
@@ -3288,17 +3653,17 @@ srom_data(u_int command, u_long addr)
     int i;
     short word = 0;
     s32 tmp;
-
+    
     for (i=0; i<16; i++) {
        sendto_srom(command  | DT_CLK, addr);
        tmp = getfrom_srom(addr);
        sendto_srom(command, addr);
-
+       
        word = (word << 1) | ((tmp >> 3) & 0x01);
     }
-
+    
     sendto_srom(command & 0x0000ff00, addr);
-
+    
     return word;
 }
 
@@ -3307,13 +3672,13 @@ static void
 srom_busy(u_int command, u_long addr)
 {
    sendto_srom((command & 0x0000ff00) | DT_CS, addr);
-
+   
    while (!((getfrom_srom(addr) >> 3) & 0x01)) {
        de4x5_ms_delay(1);
    }
-
+   
    sendto_srom(command & 0x0000ff00, addr);
-
+   
    return;
 }
 */
@@ -3323,7 +3688,7 @@ sendto_srom(u_int command, u_long addr)
 {
     outl(command, addr);
     udelay(1);
-
+    
     return;
 }
 
@@ -3331,13 +3696,406 @@ static int
 getfrom_srom(u_long addr)
 {
     s32 tmp;
-
+    
     tmp = inl(addr);
     udelay(1);
-
+    
     return tmp;
 }
 
+static int
+srom_infoleaf_info(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i, count;
+    u_char *p;
+
+    /* Find the infoleaf decoder function that matches this chipset */
+    for (i=0; i<INFOLEAF_SIZE; i++) {
+       if (lp->chipset == infoleaf_array[i].chipset) break;
+    }
+    if (i == INFOLEAF_SIZE) {
+       lp->useSROM = FALSE;
+       printk("%s: Cannot find correct chipset for SROM decoding!\n", 
+                                                                 dev->name);
+       return -ENXIO;
+    }
+
+    lp->infoleaf_fn = infoleaf_array[i].fn;
+
+    /* Find the information offset that this function should use */
+    count = *((u_char *)&lp->srom + 19);
+    p  = (u_char *)&lp->srom + 26;
+
+    if (count > 1) {
+       for (i=count; i; --i, p+=3) {
+           if (lp->device == *p) break;
+       }
+       if (i == 0) {
+           lp->useSROM = FALSE;
+           printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", 
+                                                      dev->name, lp->device);
+           return -ENXIO;
+       }
+    }
+
+    lp->infoleaf_offset = (u_short)*((u_short *)(p+1));
+
+    return 0;
+}
+
+/*
+** This routine loads any type 1 or 3 MII info into the mii device
+** struct and executes any type 5 code to reset PHY devices for this
+** controller.
+** The info for the MII devices will be valid since the index used
+** will follow the discovery process from MII address 1-31 then 0.
+*/
+static void
+srom_init(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    u_char count;
+
+    if (lp->chipset == DC21140) {
+       p+=2;
+       lp->cache.gepc = (*p++ | GEP_CTRL);
+       outl(lp->cache.gepc, DE4X5_GEP);
+    } else if (lp->chipset == DC21142) {
+       p+=2;
+    } else if (lp->chipset == DC21143) {
+       p+=2;
+    }
+
+    /* Block count */
+    count = *p++;
+
+    /* Jump the infoblocks to find types */
+    for (;count; --count) {
+       if (*p < 128) {
+           p += COMPACT_LEN;
+       } else if (*(p+1) == 5) {
+           type5_infoblock(dev, 1, p);
+           p += ((*p & BLOCK_LEN) + 1);
+       } else if (*(p+1) == 3) {
+           type3_infoblock(dev, 1, p);
+           p += ((*p & BLOCK_LEN) + 1);
+       } else if (*(p+1) == 1) {
+           type1_infoblock(dev, 1, p);
+           p += ((*p & BLOCK_LEN) + 1);
+       } else {
+           p += ((*p & BLOCK_LEN) + 1);
+       }
+    }
+
+    return;
+}
+
+static void
+srom_exec(struct device *dev, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char count = *p++;
+
+    while (count--) {
+       if (lp->chipset == DC21140) {
+           outl(*p++, DE4X5_GEP);
+       }
+       udelay(2000);                       /* 2ms per action */
+    }
+
+    return;
+}
+
+/*
+** Basically this function is a NOP since it will never be called,
+** unless I implement the DC21041 SROM functions. There's no need
+** since the existing code will be satisfactory for all boards.
+*/
+static int 
+dc21041_infoleaf(struct device *dev)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+dc21140_infoleaf(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* GEP control */
+    lp->cache.gepc = (*p++ | GEP_CTRL);
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+       next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+       next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+
+    if (lp->tcount == count) {
+       lp->media = NC;
+        if (lp->media != lp->c_media) {
+           de4x5_dbg_media(dev);
+           lp->c_media = lp->media;
+       }
+       lp->media = INIT;
+       lp->tcount = 0;
+       lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
+}
+
+static int 
+dc21142_infoleaf(struct device *dev)
+{
+printk("dc21142_infoleaf()\n");
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+dc21143_infoleaf(struct device *dev)
+{
+printk("dc21143_infoleaf()\n");
+    return DE4X5_AUTOSENSE_MS;
+}
+
+/*
+** The compact infoblock is only designed for DC21140[A] chips, so
+** we'll reuse the dc21140m_autoconf function. Non MII media only.
+*/
+static int 
+compact_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char flags, csr6;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+COMPACT_LEN) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN);
+       } else {
+           return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN);
+       }
+    }
+
+    if (lp->media == INIT) {
+        outl(lp->cache.gepc, DE4X5_GEP);
+       lp->infoblock_media = (*p++) & COMPACT_MC;
+       lp->cache.gep = *p++;
+       csr6 = *p++;
+       flags = *p++;
+
+       lp->asBitValid = (flags & 0x80) ? 0 : -1;
+       lp->defMedium = (flags & 0x40) ? -1 : 0;
+       lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+       lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+       lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+       lp->useMII = FALSE;
+
+       de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+/*
+** This block describes non MII media for the DC21140[A] only.
+ */
+static int 
+type0_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+len) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+len);
+       } else {
+           return dc_infoblock[*(p+len+1)](dev, count, p+len);
+       }
+    }
+
+    if (lp->media == INIT) {
+        outl(lp->cache.gepc, DE4X5_GEP);
+       p+=2;
+       lp->infoblock_media = (*p++) & BLOCK0_MC;
+       lp->cache.gep = *p++;
+       csr6 = *p++;
+       flags = *p++;
+
+       lp->asBitValid = (flags & 0x80) ? 0 : -1;
+       lp->defMedium = (flags & 0x40) ? -1 : 0;
+       lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+       lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+       lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+       lp->useMII = FALSE;
+
+       de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+/* These functions are under construction! */
+
+static int 
+type1_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char len = (*p & BLOCK_LEN)+1;
+    int ana;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+len) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+len);
+       } else {
+           return dc_infoblock[*(p+len+1)](dev, count, p+len);
+       }
+    }
+
+    if (lp->state == INITIALISED) {
+       lp->ibn = 1; p += 2;
+       lp->active = *p++;
+       lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
+       lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+       lp->phy[lp->active].mc  = *(u_short *)p; p += 2;
+       lp->phy[lp->active].ana = *(u_short *)p; p += 2;
+       lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
+       lp->phy[lp->active].ttm = *(u_short *)p;
+       return 0;
+    } else if (lp->media == INIT) {
+       if (lp->phy[lp->active].gep) {
+           srom_exec(dev, lp->phy[lp->active].gep);
+       }
+        ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+       mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+       lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+       lp->useMII = TRUE;
+       lp->infoblock_media = ANS;
+       de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+static int 
+type2_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+type3_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+len) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+len);
+       } else {
+           return dc_infoblock[*(p+len+1)](dev, count, p+len);
+       }
+    }
+
+    if (lp->state == INITIALISED) {
+       lp->ibn = 3; p += 2;
+        lp->active = *p++;
+       lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
+       lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+       lp->phy[lp->active].mc  = *(u_short *)p; p += 2;
+       lp->phy[lp->active].ana = *(u_short *)p; p += 2;
+       lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
+       lp->phy[lp->active].ttm = *(u_short *)p;
+       return 0;
+    } else if (lp->media == INIT) {
+       p+=2;
+       lp->infoblock_media = (*p++) & BLOCK0_MC;
+       lp->cache.gep = *p++;
+       csr6 = *p++;
+       flags = *p++;
+
+       lp->asBitValid = (flags & 0x80) ? 0 : -1;
+       lp->defMedium = (flags & 0x40) ? -1 : 0;
+       lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+       lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+       lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+       lp->useMII = TRUE;
+
+       de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+static int 
+type4_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+/*
+** This block type provides information for resetting external devices
+** (chips) through the General Purpose Register.
+*/
+static int 
+type5_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char i, j, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+len) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+len);
+       } else {
+           return dc_infoblock[*(p+len+1)](dev, count, p+len);
+       }
+    }
+
+    /* Must be initializing to run this code */
+    if ((lp->state == INITIALISED) || (lp->media == INIT)) {
+       p+=2;
+        lp->rst = p;
+       i = *p++;
+       for (j=0;i;--i) {
+           if (lp->chipset == DC21140) {
+               if (!j) {
+                   outl(*p++ | GEP_CTRL, DE4X5_GEP);
+                   j++;
+               }
+               outl(*p++, DE4X5_GEP);
+           } else if (lp->chipset == DC21142) {
+           } else if (lp->chipset == DC21143) {
+           }
+       }
+           
+    }
+
+    return DE4X5_AUTOSENSE_MS;
+}
+
 /*
 ** MII Read/Write
 */
@@ -3351,7 +4109,7 @@ mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
     mii_address(phyaddr, ioaddr);          /* PHY address to be accessed     */
     mii_address(phyreg, ioaddr);           /* PHY Register to read           */
     mii_ta(MII_STRD, ioaddr);              /* Turn around time - 2 MDC       */
-
+    
     return mii_rdata(ioaddr);              /* Read data                      */
 }
 
@@ -3366,7 +4124,7 @@ mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
     mii_ta(MII_STWR, ioaddr);              /* Turn around time - 2 MDC       */
     data = mii_swap(data, 16);             /* Swap data bit ordering         */
     mii_wdata(data, 16, ioaddr);           /* Write data                     */
-
+    
     return;
 }
 
@@ -3375,12 +4133,12 @@ mii_rdata(u_long ioaddr)
 {
     int i;
     s32 tmp = 0;
-
+    
     for (i=0; i<16; i++) {
        tmp <<= 1;
        tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
     }
-
+    
     return tmp;
 }
 
@@ -3388,12 +4146,12 @@ static void
 mii_wdata(int data, int len, u_long ioaddr)
 {
     int i;
-
+    
     for (i=0; i<len; i++) {
        sendto_mii(MII_MWR | MII_WR, data, ioaddr);
        data >>= 1;
     }
-
+    
     return;
 }
 
@@ -3401,13 +4159,13 @@ static void
 mii_address(u_char addr, u_long ioaddr)
 {
     int i;
-
+    
     addr = mii_swap(addr, 5);
     for (i=0; i<5; i++) {
        sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
        addr >>= 1;
     }
-
+    
     return;
 }
 
@@ -3415,12 +4173,12 @@ static void
 mii_ta(u_long rw, u_long ioaddr)
 {
     if (rw == MII_STWR) {
-       sendto_mii(MII_MWR | MII_WR, 1, ioaddr);
-       sendto_mii(MII_MWR | MII_WR, 0, ioaddr);
+       sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
+       sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
     } else {
        getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
     }
-
+    
     return;
 }
 
@@ -3428,13 +4186,13 @@ static int
 mii_swap(int data, int len)
 {
     int i, tmp = 0;
-
+    
     for (i=0; i<len; i++) {
        tmp <<= 1;
        tmp |= (data & 1);
        data >>= 1;
     }
-
+    
     return tmp;
 }
 
@@ -3442,13 +4200,13 @@ static void
 sendto_mii(u32 command, int data, u_long ioaddr)
 {
     u32 j;
-
+    
     j = (data & 1) << 17;
     outl(command | j, ioaddr);
     udelay(1);
     outl(command | MII_MDC | j, ioaddr);
     udelay(1);
-
+    
     return;
 }
 
@@ -3459,7 +4217,7 @@ getfrom_mii(u32 command, u_long ioaddr)
     udelay(1);
     outl(command | MII_MDC, ioaddr);
     udelay(1);
-
+    
     return ((inl(ioaddr) >> 19) & 1);
 }
 
@@ -3511,24 +4269,26 @@ mii_get_oui(u_char phyaddr, u_long ioaddr)
     return r2;                                  /* (I did it) My way */
 }
 
+/*
+** The SROM spec forces us to search addresses [1-31 0]. Bummer.
+*/
 static int
 mii_get_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
-    int i, j, k, limit=sizeof(phy_info)/sizeof(struct phy_table);
+    int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
     int id;
-
-    /* Issue a hard PHY reset - Broadcom is screwed up otherwise */
-    outl(GEP_HRST, DE4X5_GEP);
-    udelay(1000);                                  /* Assert for 1ms */
-    outl(0x00, DE4X5_GEP);
-    udelay(2000);                                  /* Wait for 2ms */
+    
+    lp->active = 0;
+    lp->useMII = TRUE;
 
     /* Search the MII address space for possible PHY devices */
-    lp->active = 0;
-    for (lp->mii_cnt=0, i=1; i<DE4X5_MAX_MII; i++) {
-       id = mii_get_oui(i, DE4X5_MII);
+    for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
+       lp->phy[lp->active].addr = i;
+       if (i==0) n++;                             /* Count cycles */
+       while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
+       id = mii_get_oui(i, DE4X5_MII); 
        if ((id == 0) || (id == -1)) continue;     /* Valid ID? */
        for (j=0; j<limit; j++) {                  /* Search PHY table */
            if (id != phy_info[j].id) continue;    /* ID match? */
@@ -3538,21 +4298,23 @@ mii_get_phy(struct device *dev)
                       (char *)&phy_info[j], sizeof(struct phy_table));
                lp->phy[k].addr = i;
                lp->mii_cnt++;
+               lp->active++;
            } else {
                i = DE4X5_MAX_MII;                 /* Stop the search */
                j = limit;
            }
        }
     }
-    if (lp->phy[lp->active].id) {                  /* Reset the PHY devices */
+    lp->active = 0;
+    if (lp->phy[0].id) {                           /* Reset the PHY devices */
        for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
            mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
            while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
-
+           
            de4x5_dbg_mii(dev, k);
        }
     }
-
+    
     return lp->mii_cnt;
 }
 
@@ -3562,12 +4324,12 @@ build_setup_frame(struct device *dev, int mode)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
     char *pa = lp->setup_frame;
-
+    
     /* Initialise the setup frame */
     if (mode == ALL) {
        memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
     }
-
+    
     if (lp->setup_f == HASH_PERF) {
        for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
            *(pa + i) = dev->dev_addr[i];                 /* Host address */
@@ -3584,7 +4346,7 @@ build_setup_frame(struct device *dev, int mode)
            if (i & 0x01) pa += 4;
        }
     }
-
+    
     return pa;                     /* Points to the next entry */
 }
 
@@ -3592,7 +4354,7 @@ static void
 enable_ast(struct device *dev, u32 time_out)
 {
     timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
-
+    
     return;
 }
 
@@ -3600,60 +4362,33 @@ static void
 disable_ast(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+    
     del_timer(&lp->timer);
-
+    
     return;
 }
 
 static long
-de4x5_switch_to_mii(struct device *dev)
+de4x5_switch_mac_port(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
-    long omr;
+    s32 omr;
 
     /* Assert the OMR_PS bit in CSR6 */
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
-    omr |= (OMR_PS | OMR_HBD);
-    outl(omr, DE4X5_OMR);
-
-    /* Soft Reset */
-    RESET_DE4X5;
-
-    /* Restore the GEP */
-    if (lp->chipset == DC21140) {
-       outl(GEP_INIT, DE4X5_GEP);
-       outl(0, DE4X5_GEP);
-    }
-
-    /* Restore CSR6 */
-    outl(omr, DE4X5_OMR);
-
-    /* Reset CSR8 */
-    inl(DE4X5_MFC);
-
-    return omr;
-}
-
-static long
-de4x5_switch_to_srl(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
-    long omr;
-
-    /* Deassert the OMR_PS bit in CSR6 */
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
+                                                                    OMR_FDX));
+    omr |= lp->infoblock_csr6;
+    if (omr & OMR_PS) omr |= OMR_HBD;
     outl(omr, DE4X5_OMR);
-
+    
     /* Soft Reset */
     RESET_DE4X5;
-
+    
     /* Restore the GEP */
     if (lp->chipset == DC21140) {
-       outl(GEP_INIT, DE4X5_GEP);
-       outl(0, DE4X5_GEP);
+       outl(lp->cache.gepc, DE4X5_GEP);
+       outl(lp->cache.gep, DE4X5_GEP);
     }
 
     /* Restore CSR6 */
@@ -3670,19 +4405,67 @@ timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int dt;
-
+    
     /* First, cancel any pending timer events */
     del_timer(&lp->timer);
-
+    
     /* Convert msec to ticks */
     dt = (msec * HZ) / 1000;
     if (dt==0) dt=1;
-
+    
     /* Set up timer */
     lp->timer.expires = jiffies + dt;
     lp->timer.function = fn;
     lp->timer.data = data;
     add_timer(&lp->timer);
+    
+    return;
+}
+
+static void
+yawn(struct device *dev, int state)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+
+    if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
+
+    if(lp->bus == EISA) {
+       switch(state) {
+         case WAKEUP:
+           outb(WAKEUP, PCI_CFPM);
+           de4x5_ms_delay(10);
+           break;
+
+         case SNOOZE:
+           outb(SNOOZE, PCI_CFPM);
+           break;
+
+         case SLEEP:
+           outl(0, DE4X5_SICR);
+           outb(SLEEP, PCI_CFPM);
+           break;
+       }
+    } else {
+       switch(state) {
+         case WAKEUP:
+           pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+                                     PCI_CFDA_PSM, WAKEUP);
+           de4x5_ms_delay(10);
+           break;
+
+         case SNOOZE:
+           pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+                                     PCI_CFDA_PSM, SNOOZE);
+           break;
+
+         case SLEEP:
+           outl(0, DE4X5_SICR);
+           pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+                                     PCI_CFDA_PSM, SLEEP);
+           break;
+       }
+    }
 
     return;
 }
@@ -3692,8 +4475,8 @@ de4x5_dbg_open(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_OPEN) {
        printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq);
        printk("\tphysical address: ");
        for (i=0;i<6;i++) {
@@ -3730,11 +4513,11 @@ de4x5_dbg_open(struct device *dev)
            }
        }
        printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
-       printk("Ring size: \nRX: %d\nTX: %d\n",
-              (short)lp->rxRingSize,
-              (short)lp->txRingSize);
+       printk("Ring size: \nRX: %d\nTX: %d\n", 
+              (short)lp->rxRingSize, 
+              (short)lp->txRingSize); 
     }
-
+    
     return;
 }
 
@@ -3743,8 +4526,8 @@ de4x5_dbg_mii(struct device *dev, int k)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
-
-    if (de4x5_debug > 2) {
+    
+    if (de4x5_debug & DEBUG_MII) {
        printk("\nMII CR:  %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
        printk("MII SR:  %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII));
        printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII));
@@ -3761,7 +4544,7 @@ de4x5_dbg_mii(struct device *dev, int k)
            printk("MII 20:  %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
        }
     }
-
+    
     return;
 }
 
@@ -3769,18 +4552,18 @@ static void
 de4x5_dbg_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+    
     if (lp->media != lp->c_media) {
-       if (de4x5_debug > 0) {
+       if (de4x5_debug & DEBUG_MEDIA) {
            if (lp->chipset != DC21140) {
                printk("%s: media is %s\n", dev->name,
                       (lp->media == NC  ? "unconnected!" :
                        (lp->media == TP  ? "TP." :
                         (lp->media == ANS ? "TP/Nway." :
-                         (lp->media == BNC ? "BNC." :
-                          (lp->media == AUI ? "AUI." :
-                           (lp->media == BNC_AUI ? "BNC/AUI." :
-                            (lp->media == EXT_SIA ? "EXT SIA." :
+                         (lp->media == BNC ? "BNC." : 
+                          (lp->media == AUI ? "AUI." : 
+                           (lp->media == BNC_AUI ? "BNC/AUI." : 
+                            (lp->media == EXT_SIA ? "EXT SIA." : 
                              "???."
                              ))))))));
            } else {
@@ -3794,7 +4577,7 @@ de4x5_dbg_media(struct device *dev)
        }
        lp->c_media = lp->media;
     }
-
+    
     return;
 }
 
@@ -3803,10 +4586,12 @@ de4x5_dbg_srom(struct de4x5_srom *p)
 {
     int i;
 
-    if (de4x5_debug > 1) {
-       printk("Sub-system Vendor ID: %04x\n", (u_short)*(p->sub_vendor_id));
-       printk("Sub-system ID:        %04x\n", (u_short)*(p->sub_system_id));
+    if (de4x5_debug & DEBUG_SROM) {
+       printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
+       printk("Sub-system ID:        %04x\n", *((u_short *)p->sub_system_id));
        printk("ID Block CRC:         %02x\n", (u_char)(p->id_block_crc));
+       printk("SROM version:         %02x\n", (u_char)(p->version));
+       printk("# controllers:         %02x\n", (u_char)(p->num_controllers));
 
        printk("Hardware Address:     ");
        for (i=0;i<ETH_ALEN-1;i++) {
@@ -3827,7 +4612,7 @@ de4x5_dbg_rx(struct sk_buff *skb, int len)
 {
     int i, j;
 
-    if (de4x5_debug > 2) {
+    if (de4x5_debug & DEBUG_RX) {
        printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
               (u_char)skb->data[0],
               (u_char)skb->data[1],
@@ -3844,7 +4629,7 @@ de4x5_dbg_rx(struct sk_buff *skb, int len)
               (u_char)skb->data[12],
               (u_char)skb->data[13],
               len);
-       if (de4x5_debug > 3) {
+       if (de4x5_debug & DEBUG_RX) {
            for (j=0; len>0;j+=16, len-=16) {
                printk("    %03x: ",j);
                for (i=0; i<16 && i<len; i++) {
@@ -3875,7 +4660,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
        u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
     } tmp;
-
+    
     switch(ioc->cmd) {
       case DE4X5_GET_HWADDR:           /* Get the hardware address */
        ioc->len = ETH_ALEN;
@@ -3886,7 +4671,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
            tmp.addr[i] = dev->dev_addr[i];
        }
        copy_to_user(ioc->data, tmp.addr, ioc->len);
-
+       
        break;
       case DE4X5_SET_HWADDR:           /* Set the hardware address */
        status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
@@ -3903,12 +4688,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        build_setup_frame(dev, PHYS_ADDR_ONLY);
        /* Set up the descriptor and give ownership to the card */
        while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
-       load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+       load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
                                                        SETUP_FRAME_LEN, NULL);
        lp->tx_new = (++lp->tx_new) % lp->txRingSize;
        outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
        dev->tbusy = 0;                              /* Unlock the TX ring */
-
+       
        break;
       case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
        if (suser()) {
@@ -3918,7 +4703,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
        if (suser()) {
@@ -3928,19 +4713,19 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
        printk("%s: Boo!\n", dev->name);
-
+       
        break;
       case DE4X5_GET_MCA:              /* Get the multicast address table */
        ioc->len = (HASH_TABLE_LEN >> 3);
        status = verify_area(VERIFY_WRITE, ioc->data, ioc->len);
        if (!status) {
-           copy_to_user(ioc->data, lp->setup_frame, ioc->len);
+           copy_to_user(ioc->data, lp->setup_frame, ioc->len); 
        }
-
+       
        break;
       case DE4X5_SET_MCA:              /* Set a multicast address */
        if (suser()) {
@@ -3956,7 +4741,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_CLR_MCA:              /* Clear all multicast addresses */
        if (suser()) {
@@ -3965,7 +4750,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
        if (suser()) {
@@ -3975,18 +4760,18 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_GET_STATS:            /* Get the driver statistics */
        ioc->len = sizeof(lp->pktStats);
        status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
        if (status)
          break;
-
+       
        cli();
-       copy_to_user(ioc->data, &lp->pktStats, ioc->len);
+       copy_to_user(ioc->data, &lp->pktStats, ioc->len); 
        sti();
-
+       
        break;
       case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
        if (suser()) {
@@ -3996,14 +4781,14 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_GET_OMR:              /* Get the OMR Register contents */
        tmp.addr[0] = inl(DE4X5_OMR);
        if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
            copy_to_user(ioc->data, tmp.addr, 1);
        }
-
+       
        break;
       case DE4X5_SET_OMR:              /* Set the OMR Register contents */
        if (suser()) {
@@ -4014,7 +4799,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        } else {
            status = -EPERM;
        }
-
+       
        break;
       case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
        j = 0;
@@ -4031,9 +4816,9 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
            copy_to_user(ioc->data, tmp.addr, ioc->len);
        }
        break;
-
+       
 #define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
-
+       
       case DE4X5_DUMP:
        j = 0;
        tmp.addr[j++] = dev->irq;
@@ -4043,7 +4828,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        tmp.addr[j++] = lp->rxRingSize;
        tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
        tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
-
+       
        for (i=0;i<lp->rxRingSize-1;i++){
            if (i < 3) {
                tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
@@ -4056,7 +4841,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
            }
        }
        tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
+       
        for (i=0;i<lp->rxRingSize-1;i++){
            if (i < 3) {
                tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
@@ -4069,14 +4854,14 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
            }
        }
        tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
-
+       
        for (i=0;i<lp->rxRingSize;i++){
            tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
        }
        for (i=0;i<lp->txRingSize;i++){
            tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
        }
-
+       
        tmp.lval[j>>2] = inl(DE4X5_BMR);  j+=4;
        tmp.lval[j>>2] = inl(DE4X5_TPD);  j+=4;
        tmp.lval[j>>2] = inl(DE4X5_RPD);  j+=4;
@@ -4085,18 +4870,18 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        tmp.lval[j>>2] = inl(DE4X5_STS);  j+=4;
        tmp.lval[j>>2] = inl(DE4X5_OMR);  j+=4;
        tmp.lval[j>>2] = inl(DE4X5_IMR);  j+=4;
-       tmp.lval[j>>2] = lp->chipset; j+=4;
+       tmp.lval[j>>2] = lp->chipset; j+=4; 
        if (lp->chipset == DC21140) {
            tmp.lval[j>>2] = inl(DE4X5_GEP);  j+=4;
        } else {
            tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
            tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
            tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
-           tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
+           tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; 
        }
-       tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4;
-       if (lp->phy[lp->active].id) {
-           tmp.lval[j>>2] = lp->active; j+=4;
+       tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; 
+       if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+           tmp.lval[j>>2] = lp->active; j+=4; 
            tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
            tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
            tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
@@ -4113,20 +4898,20 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
            }
        }
-
+       
        tmp.addr[j++] = lp->txRingSize;
        tmp.addr[j++] = dev->tbusy;
-
+       
        ioc->len = j;
        if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
            copy_to_user(ioc->data, tmp.addr, ioc->len);
        }
-
+       
        break;
       default:
        status = -EOPNOTSUPP;
     }
-
+    
     return status;
 }
 
@@ -4135,82 +4920,34 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 ** Note now that module autoprobing is allowed under EISA and PCI. The
 ** IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
 ** to "do the right thing".
-**
-** The module autoprobe will only load one instance of the driver and
-** hardware.
 */
-static char devicename[9] = { 0, };
-static struct device thisDE4X5 = {
-    devicename,   /* device name inserted by /linux/drivers/net/net_init.c  */
-    0, 0, 0, 0,
-    0, 0,         /* I/O address, IRQ                                       */
-    0, 0, 0, NULL, de4x5_probe };
-
-static int io=0x0; /* EDIT THESE LINES FOR YOUR CONFIGURATION              */
-MODULE_PARM(io, "i");
+#define LP(a) ((struct de4x5_private *)(a))
+static struct device *mdev = NULL;
+static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
 
 int
 init_module(void)
 {
-    struct device *p  = (struct device *)&thisDE4X5;
+    struct device *p;
 
-    thisDE4X5.base_addr = io;                   /* Now autoprobe the module */
-    thisDE4X5.irq = 0;
+    if ((mdev = insert_device(NULL, io, de4x5_probe)) == NULL) 
+      return -ENOMEM;
 
-    for (; p!=NULL; p=p->next) {
+    for (p = mdev; p != NULL; p = LP(p->priv)->next_module) {
        if (register_netdev(p) != 0)
          return -EIO;
     }
-    io=0;
+
     return 0;
 }
 
 void
 cleanup_module(void)
 {
-    struct de4x5_private *lp = (struct de4x5_private *) thisDE4X5.priv;
-    struct device *p  = (struct device *)&thisDE4X5;
-    int keep_loaded = 0;
-
-    for (; p!=NULL; p=p->next) {
-       keep_loaded += (p->flags & IFF_UP);     /* Is an interface up?       */
-    }
-
-    if (keep_loaded) {
-       printk("de4x5: Cannot unload modules - %d interface%s%s still active.\n",
-              keep_loaded, (keep_loaded>1 ? "s ": " "),
-              (keep_loaded>1 ? "are": "is"));
-       return;
+    while (mdev != NULL) {
+       mdev = unlink_modules(mdev);
     }
 
-    for (p=thisDE4X5.next; p!=NULL; p=p->next) {
-       if (p->priv) {                          /* Private area allocated?   */
-           struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-           if (lp->cache.buf) {                /* MAC buffers allocated?    */
-               kfree(lp->cache.buf);           /* Free the MAC buffers      */
-           }
-           release_region(p->base_addr, (lp->bus == PCI ?
-                                         DE4X5_PCI_TOTAL_SIZE :
-                                         DE4X5_EISA_TOTAL_SIZE));
-           kfree(lp->cache.priv);              /* Free the private area     */
-       }
-       unregister_netdev(p);
-       kfree(p);                               /* Free the device structure */
-    }
-
-    if (thisDE4X5.priv) {
-       if (lp->cache.buf) {                    /* Are MAC buffers allocated */
-            kfree(lp->cache.buf);
-       }
-       release_region(thisDE4X5.base_addr,
-                     (lp->bus == PCI ?
-                      DE4X5_PCI_TOTAL_SIZE :
-                      DE4X5_EISA_TOTAL_SIZE));
-       kfree(lp->cache.priv);
-       thisDE4X5.priv = NULL;
-    }
-    unregister_netdev(&thisDE4X5);
-
     return;
 }
 #endif /* MODULE */
index 3ad781c6014143f04210762e332738a93604efa3..bda97578c044ed588a24d775f945e637b56dc5cb 100644 (file)
@@ -62,6 +62,8 @@
 #define PCI_CBER     iobase+0x0030   /* PCI Expansion ROM Base Address Reg. */
 #define PCI_CFIT     iobase+0x003c   /* PCI Configuration Interrupt Register */
 #define PCI_CFDA     iobase+0x0040   /* PCI Driver Area Register */
+#define PCI_CFDD     iobase+0x0041   /* PCI Driver Dependent Area Register */
+#define PCI_CFPM     iobase+0x0043   /* PCI Power Management Area Register */
 
 /*
 ** EISA Configuration Register 0 bit definitions
 #define ER3_LSR       0x02           /* Local Software Reset */
 
 /*
-** PCI Configuration ID Register (PCI_CFID)
+** PCI Configuration ID Register (PCI_CFID). The Device IDs are left
+** shifted 8 bits to allow detection of DC21142 and DC21143 variants with
+** the configuration revision register step number.
 */
 #define CFID_DID    0xff00           /* Device ID */
 #define CFID_VID    0x00ff           /* Vendor ID */
-#define DC21040_DID 0x0002           /* Unique Device ID # */
+#define DC21040_DID 0x0200           /* Unique Device ID # */
 #define DC21040_VID 0x1011           /* DC21040 Manufacturer */
-#define DC21041_DID 0x0014           /* Unique Device ID # */
+#define DC21041_DID 0x1400           /* Unique Device ID # */
 #define DC21041_VID 0x1011           /* DC21041 Manufacturer */
-#define DC21140_DID 0x0009           /* Unique Device ID # */
+#define DC21140_DID 0x0900           /* Unique Device ID # */
 #define DC21140_VID 0x1011           /* DC21140 Manufacturer */
+#define DC2114x_DID 0x1900           /* Unique Device ID # */
+#define DC2114x_VID 0x1011           /* DC2114[23] Manufacturer */
 
 /*
 ** Chipset defines
 #define DC21040     DC21040_DID
 #define DC21041     DC21041_DID
 #define DC21140     DC21140_DID
+#define DC2114x     DC2114x_DID
+#define DC21142     (DC2114x_DID | 0x0010)
+#define DC21143     (DC2114x_DID | 0x0020)
 
 #define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
 #define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
 #define is_DC21140 ((vendor == DC21140_VID) && (device == DC21140_DID))
+#define is_DC2114x ((vendor == DC2114x_VID) && (device == DC2114x_DID))
+#define is_DC21142 ((vendor == DC2114x_VID) && (device == DC21142))
+#define is_DC21143 ((vendor == DC2114x_VID) && (device == DC21143))
 
 /*
 ** PCI Configuration Command/Status Register (PCI_CFCS)
 #define CBER_ROME   0x00000001       /* ROM Enable */
 
 /*
-** PCI Configuration Driver Area Register (PCI_CFDA)
+** PCI Configuration Power Management Area Register (PCI_CFPM)
 */
-#define CFDA_PSM    0x80000000       /* Power Saving Mode */
+#define SLEEP       0x80             /* Power Saving Sleep Mode */
+#define SNOOZE      0x40             /* Power Saving Snooze Mode */
+#define WAKEUP      0x00             /* Power Saving Wakeup */
+
+#define PCI_CFDA_DSU 0x41            /* 8 bit Configuration Space Address */
+#define PCI_CFDA_PSM 0x43            /* 8 bit Configuration Space Address */
 
 /*
 ** DC21040 Bus Mode Register (DE4X5_BMR)
 #define OMR_ST     0x00002000       /* Start/Stop Transmission Command */
 #define OMR_FC     0x00001000       /* Force Collision Mode */
 #define OMR_OM     0x00000c00       /* Operating Mode */
-#define OMR_FD     0x00000200       /* Full Duplex Mode */
+#define OMR_FDX    0x00000200       /* Full Duplex Mode */
 #define OMR_FKD    0x00000100       /* Flaky Oscillator Disable */
 #define OMR_PM     0x00000080       /* Pass All Multicast */
 #define OMR_PR     0x00000040       /* Promiscuous Mode */
 #define MEDIA_TP       0x0002      /* TP Media present */
 #define MEDIA_BNC      0x0001      /* BNC Media present */
 
+/*
+** SROM Definitions (Digital Semiconductor Format)
+*/
+#define SROM_SSVID     0x0000      /* Sub-system Vendor ID offset */
+#define SROM_SSID      0x0002      /* Sub-system ID offset */
+#define SROM_CISPL     0x0004      /* CardBus CIS Pointer low offset */
+#define SROM_CISPH     0x0006      /* CardBus CIS Pointer high offset */
+#define SROM_IDCRC     0x0010      /* ID Block CRC offset*/
+#define SROM_RSVD2     0x0011      /* ID Reserved 2 offset */
+#define SROM_SFV       0x0012      /* SROM Format Version offset */
+#define SROM_CCNT      0x0013      /* Controller Count offset */
+#define SROM_HWADD     0x0014      /* Hardware Address offset */
+#define SROM_MRSVD     0x007c      /* Manufacturer Reserved offset*/
+#define SROM_CRC       0x007e      /* SROM CRC offset */
+
+/*
+** SROM Media Connection Definitions
+*/
+#define SROM_10BT      0x0000      /*  10BASE-T half duplex */
+#define SROM_10BTN     0x0100      /*  10BASE-T with Nway */
+#define SROM_10BTF     0x0204      /*  10BASE-T full duplex */
+#define SROM_10BTNLP   0x0400      /*  10BASE-T without Link Pass test */
+#define SROM_10B2      0x0001      /*  10BASE-2 (BNC) */
+#define SROM_10B5      0x0002      /*  10BASE-5 (AUI) */
+#define SROM_100BTH    0x0003      /*  100BASE-T half duplex */
+#define SROM_100BTF    0x0205      /*  100BASE-T full duplex */
+#define SROM_100BT4    0x0006      /*  100BASE-T4 */
+#define SROM_100BFX    0x0007      /*  100BASE-FX half duplex (Fiber) */
+#define SROM_M10BT     0x0009      /*  MII 10BASE-T half duplex */
+#define SROM_M10BTF    0x020a      /*  MII 10BASE-T full duplex */
+#define SROM_M100BT    0x000d      /*  MII 100BASE-T half duplex */
+#define SROM_M100BTF   0x020e      /*  MII 100BASE-T full duplex */
+#define SROM_M100BT4   0x000f      /*  MII 100BASE-T4 */
+#define SROM_M100BF    0x0010      /*  MII 100BASE-FX half duplex */
+#define SROM_M100BFF   0x0211      /*  MII 100BASE-FX full duplex */
+#define SROM_PDA       0x0800      /*  Powerup & Dynamic Autosense */
+#define SROM_PAO       0x8800      /*  Powerup Autosense Only */
+#define SROM_NSMI      0xffff      /*  No Selected Media Information */
+
+/*
+** SROM Media Definitions
+*/
+#define SROM_10BASET   0x0000      /*  10BASE-T half duplex */
+#define SROM_10BASE2   0x0001      /*  10BASE-2 (BNC) */
+#define SROM_10BASE5   0x0002      /*  10BASE-5 (AUI) */
+#define SROM_100BASET  0x0003      /*  100BASE-T half duplex */
+#define SROM_10BASETF  0x0004      /*  10BASE-T full duplex */
+#define SROM_100BASETF 0x0005      /*  100BASE-T full duplex */
+#define SROM_100BASET4 0x0006      /*  100BASE-T4 */
+#define SROM_100BASEF  0x0007      /*  100BASE-FX half duplex */
+#define SROM_100BASEFF 0x0008      /*  100BASE-FX full duplex */
+
+#define BLOCK_LEN      0x7f        /* Extended blocks length mask */
+
+/*
+** SROM Compact Format Block Masks
+*/
+#define COMPACT_FI      0x80       /* Format Indicator */
+#define COMPACT_LEN     0x04       /* Length */
+#define COMPACT_MC      0x3f       /* Media Code */
+
+/*
+** SROM Extended Format Block Type 0 Masks
+*/
+#define BLOCK0_FI      0x80        /* Format Indicator */
+#define BLOCK0_MCS     0x80        /* Media Code byte Sign */
+#define BLOCK0_MC      0x3f        /* Media Code */
+
 /*
 ** DC21040 Full Duplex Register (DE4X5_FDR)
 */
 #define GEP_FLED 0x00000002        /* Force Activity LED on   (output) */
 #define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s           */
 #define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1) */
-
+#define GEP_CTRL 0x00000100        /* GEP control bit                  */
 
 /*
 ** DC21040 SIA Status Register (DE4X5_SISR)
 #define AUTO            0x4000     /* Auto sense the media or speed */
 #define TIMER_CB        0x80000000 /* Timer callback detection */
 
+/*
+** DE4X5 DEBUG Options
+*/
+#define DEBUG_NONE      0x0000     /* No DEBUG messages */
+#define DEBUG_VERSION   0x0001     /* Print version message */
+#define DEBUG_MEDIA     0x0002     /* Print media messages */
+#define DEBUG_TX        0x0004     /* Print TX (queue_pkt) messages */
+#define DEBUG_RX        0x0008     /* Print RX (de4x5_rx) messages */
+#define DEBUG_SROM      0x0010     /* Print SROM messages */
+#define DEBUG_MII       0x0020     /* Print MII messages */
+#define DEBUG_OPEN      0x0040     /* Print de4x5_open() messages */
+#define DEBUG_CLOSE     0x0080     /* Print de4x5_close() messages */
+#define DEBUG_PCICFG    0x0100
+
 /*
 ** Miscellaneous
 */
 */
 #define NO                   0
 #define FALSE                0
-#define CLOSED               0
 
 #define YES                  ~0
 #define TRUE                 ~0
-#define OPEN                 ~0
+
+/*
+** Adapter state
+*/
+#define INITIALISED          0     /* After h/w initialised and mem alloc'd */
+#define CLOSED               1     /* Ready for opening */
+#define OPEN                 2     /* Running */
 
 /*
 ** IEEE OUIs for various PHY vendor/chip combos - Reg 2 values only. Since
 ** Speed Selection stuff
 */
 #define SET_10Mb {\
-  if (lp->phy[lp->active].id) {\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
     if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
-      mii_wr(MII_CR_10|(de4x5_full_duplex?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+      mii_wr(MII_CR_10|(lp->fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
     }\
-    omr |= ((de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM);\
+    omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
     outl(omr, DE4X5_OMR);\
-    outl(0, DE4X5_GEP);\
+    lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
-    omr |= (de4x5_full_duplex ? OMR_FD : 0);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
     outl(omr | OMR_TTM, DE4X5_OMR);\
-    outl((de4x5_full_duplex ? 0 : GEP_FDXD), DE4X5_GEP);\
+    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD);\
   }\
 }
 
 #define SET_100Mb {\
-  if (lp->phy[lp->active].id) {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
     int fdx=0;\
     if (lp->phy[lp->active].id == NATIONAL_TX) {\
         mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\
                       0x18, lp->phy[lp->active].addr, DE4X5_MII);\
     }\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
     sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\
-    if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) fdx=1;\
+    if (!(sr & MII_ANA_T4AM) && lp->fdx) fdx=1;\
     if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
       mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
     }\
-    if (fdx) omr |= OMR_FD;\
+    if (fdx) omr |= OMR_FDX;\
     outl(omr, DE4X5_OMR);\
+    lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | lp->infoblock_csr6 | OMR_HBD, DE4X5_OMR);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
-    omr |= (de4x5_full_duplex ? OMR_FD : 0);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
-    outl((de4x5_full_duplex ? 0 : GEP_FDXD) | GEP_MODE, DE4X5_GEP);\
+    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD) | GEP_MODE;\
   }\
 }
 
 /* FIX ME so I don't jam 10Mb networks */
 #define SET_100Mb_PDET {\
-  if (lp->phy[lp->active].id) {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
     mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    outl(omr, DE4X5_OMR);\
+    lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     outl(omr, DE4X5_OMR);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
-    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);\
+    lp->cache.gep = (GEP_FDXD | GEP_MODE);\
   }\
 }
 
index d52263cdca998fd92cd8f40e73afd3c4fcf8b54a..c248c876608497eef13723775006f8573857b093 100644 (file)
@@ -88,8 +88,6 @@ static const char *version =
 #define DE600_DEBUG 0
 #define PRINTK(x) /**/
 #endif
-unsigned int de600_debug = DE600_DEBUG;
-MODULE_PARM(de600_debug, "i");
 \f
 #include <linux/module.h>
 
@@ -111,12 +109,14 @@ MODULE_PARM(de600_debug, "i");
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+unsigned int de600_debug = DE600_DEBUG;
+MODULE_PARM(de600_debug, "i");
+
 #ifdef FAKE_SMALL_MAX
 static unsigned long de600_rspace(struct sock *sk);
 #include <net/sock.h>
 #endif
 
-#define netstats enet_statistics
 typedef unsigned char byte;
 
 /**************************************************
@@ -244,7 +244,7 @@ static byte de600_read_byte(unsigned char type, struct device *dev);
 /* Put in the device structure. */
 static int     de600_open(struct device *dev);
 static int     de600_close(struct device *dev);
-static struct netstats *get_stats(struct device *dev);
+static struct net_device_stats *get_stats(struct device *dev);
 static int     de600_start_xmit(struct sk_buff *skb, struct device *dev);
 
 /* Dispatch from interrupts. */
@@ -374,10 +374,10 @@ de600_close(struct device *dev)
        return 0;
 }
 
-static struct netstats *
+static struct net_device_stats *
 get_stats(struct device *dev)
 {
-    return (struct netstats *)(dev->priv);
+    return (struct net_device_stats *)(dev->priv);
 }
 
 static inline void
@@ -556,7 +556,7 @@ de600_tx_intr(struct device *dev, int irq_status)
        if (!(irq_status & TX_FAILED16)) {
                tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
                ++free_tx_pages;
-               ((struct netstats *)(dev->priv))->tx_packets++;
+               ((struct net_device_stats *)(dev->priv))->tx_packets++;
                dev->tbusy = 0;
        }
 
@@ -623,7 +623,7 @@ de600_rx_intr(struct device *dev)
        for (i = size; i > 0; --i, ++buffer)
                *buffer = de600_read_byte(READ_DATA, dev);
 
-       ((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */
+       ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
 
        skb->protocol=eth_type_trans(skb,dev);
 
@@ -639,8 +639,8 @@ int
 de600_probe(struct device *dev)
 {
        int     i;
-       static struct netstats de600_netstats;
-       /*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
+       static struct net_device_stats de600_netstats;
+       /*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/
 
        printk("%s: D-Link DE-600 pocket adapter", dev->name);
        /* Alpha testers must have the version number to report bugs. */
@@ -697,10 +697,9 @@ de600_probe(struct device *dev)
        printk("\n");
 
        /* Initialize the device structure. */
-       /*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
        dev->priv = &de600_netstats;
 
-       memset(dev->priv, 0, sizeof(struct netstats));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
        dev->get_stats = get_stats;
 
        dev->open = de600_open;
index caadf3b6289d461e3b9f04be63369a8029ceb377..ce3a3eea0b0d84b4f248d71b1ddfb7a836491a57 100644 (file)
@@ -140,7 +140,6 @@ static const char *version =
 /* Constant definitions for the DE-620 registers, commands and bits */
 #include "de620.h"
 
-#define netstats enet_statistics
 typedef unsigned char byte;
 
 /*******************************************************
@@ -212,7 +211,7 @@ MODULE_PARM(de620_debug, "i");
 /* Put in the device structure. */
 static int     de620_open(struct device *);
 static int     de620_close(struct device *);
-static struct netstats *get_stats(struct device *);
+static struct  net_device_stats *get_stats(struct device *);
 static void    de620_set_multicast_list(struct device *);
 static int     de620_start_xmit(struct sk_buff *, struct device *);
 
@@ -477,10 +476,9 @@ de620_close(struct device *dev)
  * Return current statistics
  *
  */
-static struct netstats *
-get_stats(struct device *dev)
+static struct net_device_stats *get_stats(struct device *dev)
 {
-       return (struct netstats *)(dev->priv);
+       return (struct net_device_stats *)(dev->priv);
 }
 
 /*********************************************
@@ -590,7 +588,7 @@ de620_start_xmit(struct sk_buff *skb, struct device *dev)
        dev->trans_start = jiffies;
        dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */
 
-       ((struct netstats *)(dev->priv))->tx_packets++;
+       ((struct net_device_stats *)(dev->priv))->tx_packets++;
 
        restore_flags(flags); /* interrupts maybe back on */
 
@@ -681,7 +679,7 @@ de620_rx_intr(struct device *dev)
                printk("%s: Ring overrun? Restoring...\n", dev->name);
                /* You win some, you loose some. And sometimes plenty... */
                adapter_init(dev);
-               ((struct netstats *)(dev->priv))->rx_over_errors++;
+               ((struct net_device_stats *)(dev->priv))->rx_over_errors++;
                return 0;
        }
 
@@ -701,7 +699,7 @@ de620_rx_intr(struct device *dev)
                next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
                de620_send_command(dev, W_DUMMY);
                de620_set_register(dev, W_NPRF, next_rx_page);
-               ((struct netstats *)(dev->priv))->rx_over_errors++;
+               ((struct net_device_stats *)(dev->priv))->rx_over_errors++;
                return 0;
        }
        next_rx_page = pagelink;
@@ -715,7 +713,7 @@ de620_rx_intr(struct device *dev)
                if (skb == NULL) { /* Yeah, but no place to put it... */
                        printk("%s: Couldn't allocate a sk_buff of size %d.\n",
                                dev->name, size);
-                       ((struct netstats *)(dev->priv))->rx_dropped++;
+                       ((struct net_device_stats *)(dev->priv))->rx_dropped++;
                }
                else { /* Yep! Go get it! */
                        skb_reserve(skb,2);     /* Align */
@@ -729,7 +727,7 @@ de620_rx_intr(struct device *dev)
                        skb->protocol=eth_type_trans(skb,dev);
                        netif_rx(skb); /* deliver it "upstairs" */
                        /* count all receives */
-                       ((struct netstats *)(dev->priv))->rx_packets++;
+                       ((struct net_device_stats *)(dev->priv))->rx_packets++;
                }
        }
 
@@ -838,7 +836,7 @@ adapter_init(struct device *dev)
 int
 de620_probe(struct device *dev)
 {
-       static struct netstats de620_netstats;
+       static struct net_device_stats de620_netstats;
        int i;
        byte checkbyte = 0xa5;
 
@@ -892,10 +890,9 @@ de620_probe(struct device *dev)
                printk(" UTP)\n");
 
        /* Initialize the device structure. */
-       /*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
        dev->priv = &de620_netstats;
 
-       memset(dev->priv, 0, sizeof(struct netstats));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
        dev->get_stats = get_stats;
        dev->open = de620_open;
        dev->stop = de620_close;
index c2eb8baf4da1209249323adabc332722250cdfca..fce95ff35593c04395e204ec9a3c53316fdb8347 100644 (file)
@@ -247,7 +247,7 @@ static void         dfx_int_type_0_process(DFX_board_t *bp);
 static void            dfx_int_common(DFX_board_t *bp);
 static void            dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
-static struct  enet_statistics *dfx_ctl_get_stats(struct device *dev);
+static struct          net_device_stats *dfx_ctl_get_stats(struct device *dev);
 static void            dfx_ctl_set_multicast_list(struct device *dev);
 static int             dfx_ctl_set_mac_address(struct device *dev, void *addr);
 static int             dfx_ctl_update_cam(DFX_board_t *bp);
@@ -1991,7 +1991,7 @@ void dfx_interrupt(
  *   None
  */
 
-struct enet_statistics *dfx_ctl_get_stats(
+struct net_device_stats *dfx_ctl_get_stats(
        struct device *dev
        )
 
@@ -2013,7 +2013,7 @@ struct enet_statistics *dfx_ctl_get_stats(
 
        bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET;
        if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
-               return((struct enet_statistics *) &bp->stats);
+               return((struct net_device_stats *) &bp->stats);
 
        /* Fill the bp->stats structure with the SMT MIB object values */
 
@@ -2114,7 +2114,7 @@ struct enet_statistics *dfx_ctl_get_stats(
 
        bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET;
        if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
-               return((struct enet_statistics *) &bp->stats);
+               return((struct net_device_stats *) &bp->stats);
 
        /* Fill the bp->stats structure with the FDDI counter values */
 
@@ -2130,7 +2130,7 @@ struct enet_statistics *dfx_ctl_get_stats(
        bp->stats.port_lem_cts[0]                       = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
        bp->stats.port_lem_cts[1]                       = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
 
-       return((struct enet_statistics *) &bp->stats);
+       return((struct net_device_stats *) &bp->stats);
        }
 
 \f
index 5d509e0fb3728ab346b449b40808bd8d553bddda..c1c4a299ecfdd9b9bc19963f6b07fe574116971e 100644 (file)
@@ -352,7 +352,7 @@ struct depca_private {
     u_long dma_buffs;             /* LANCE Rx and Tx buffers start address. */
     int        rx_new, tx_new;            /* The next free ring entry               */
     int rx_old, tx_old;                   /* The ring entries to be free()ed.       */
-    struct enet_statistics stats;
+    struct net_device_stats stats;
     struct {                       /* Private stats counters                 */
        u32 bins[DEPCA_PKT_STAT_SZ];
        u32 unicast;
@@ -387,7 +387,7 @@ static int    depca_start_xmit(struct sk_buff *skb, struct device *dev);
 static void   depca_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static int    depca_close(struct device *dev);
 static int    depca_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-static struct enet_statistics *depca_get_stats(struct device *dev);
+static struct net_device_stats *depca_get_stats(struct device *dev);
 static void   set_multicast_list(struct device *dev);
 
 /*
@@ -1113,7 +1113,7 @@ static int InitRestartDepca(struct device *dev)
   return status;
 }
 
-static struct enet_statistics *
+static struct net_device_stats *
 depca_get_stats(struct device *dev)
 {
     struct depca_private *lp = (struct depca_private *)dev->priv;
index a234a8555d9bec1cd4946bab44410708614c0aeb..7281f52448b713bd61a0ebb37a747479d1a85bc3 100644 (file)
@@ -195,7 +195,7 @@ typedef struct
         */
        char                    devname[8];     /* "ethN" string */
        struct device           *next_dev;
-       struct enet_statistics  stats;
+       struct net_device_stats stats;
 
        /*
         *      DGRS specific data
@@ -687,8 +687,8 @@ out:
  *     output port by setting the special "dstchan" member at the
  *     end of the traditional 82596 RFD structure.
  */
-static int
-dgrs_start_xmit(struct sk_buff *skb, struct device *devN)
+
+static int dgrs_start_xmit(struct sk_buff *skb, struct device *devN)
 {
        DGRS_PRIV       *privN = (DGRS_PRIV *) devN->priv;
        struct device   *dev0;
@@ -793,9 +793,9 @@ dgrs_open( struct device *dev )
        dev->interrupt = 0;
        dev->start = 1;
 
-       #ifdef MODULE
-               MOD_INC_USE_COUNT;
-       #endif
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
 
        return (0);
 }
@@ -803,15 +803,14 @@ dgrs_open( struct device *dev )
 /*
  *     Close the interface
  */
-static int
-dgrs_close( struct device *dev )
+static int dgrs_close( struct device *dev )
 {
        dev->start = 0;
        dev->tbusy = 1;
 
-       #ifdef MODULE
-               MOD_DEC_USE_COUNT;
-       #endif
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
 
        return (0);
 }
@@ -819,8 +818,7 @@ dgrs_close( struct device *dev )
 /*
  *     Get statistics
  */
-static struct enet_statistics *
-dgrs_get_stats( struct device *dev )
+static struct net_device_stats *dgrs_get_stats( struct device *dev )
 {
        DGRS_PRIV       *priv = (DGRS_PRIV *) dev->priv;
 
@@ -830,8 +828,8 @@ dgrs_get_stats( struct device *dev )
 /*
  *     Set multicast list and/or promiscuous mode
  */
-static void
-dgrs_set_multicast_list( struct device *dev)
+
+static void dgrs_set_multicast_list( struct device *dev)
 {
        DGRS_PRIV       *priv = (DGRS_PRIV *) dev->priv;
 
@@ -841,63 +839,60 @@ dgrs_set_multicast_list( struct device *dev)
 /*
  *     Unique ioctl's
  */
-static int
-dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd)
+static int dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd)
 {
        DGRS_PRIV       *privN = (DGRS_PRIV *) devN->priv;
        DGRS_IOCTL      ioc;
        int             i, rc;
 
-       rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(DGRS_IOCTL));
-       if (rc) return (rc);
-       if (cmd != DGRSIOCTL) return -EINVAL;
+       if (cmd != DGRSIOCTL)
+               return -EINVAL;
 
-       COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL));
+       if(COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
+               return -EFAULT;
 
        switch (ioc.cmd)
        {
-       case DGRS_GETMEM:
-               if (ioc.len != sizeof(ulong))
-                       return -EINVAL;
-               rc = verify_area(VERIFY_WRITE, (void *) ioc.data, ioc.len);
-               if (rc) return (rc);
-               COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len);
-               return (0);
-       case DGRS_SETFILTER:
-               rc = verify_area(VERIFY_READ, (void *) ioc.data, ioc.len);
-               if (rc) return (rc);
-               if (ioc.port > privN->bcomm->bc_nports)
-                       return -EINVAL;
-               if (ioc.filter >= NFILTERS)
-                       return -EINVAL;
-               if (ioc.len > privN->bcomm->bc_filter_area_len)
-                       return -EINVAL;
-
-               /* Wait for old command to finish */
-               for (i = 0; i < 1000; ++i)
-               {
-                       if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 )
-                               break;
-                       udelay(1);
-               }
-               if (i >= 1000)
-                       return -EIO;
-
-               privN->bcomm->bc_filter_port = ioc.port;
-               privN->bcomm->bc_filter_num = ioc.filter;
-               privN->bcomm->bc_filter_len = ioc.len;
+               case DGRS_GETMEM:
+                       if (ioc.len != sizeof(ulong))
+                               return -EINVAL;
+                       if(COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len))
+                               return -EFAULT;
+                       return (0);
+               case DGRS_SETFILTER:
+                       if (ioc.port > privN->bcomm->bc_nports)
+                               return -EINVAL;
+                       if (ioc.filter >= NFILTERS)
+                               return -EINVAL;
+                       if (ioc.len > privN->bcomm->bc_filter_area_len)
+                               return -EINVAL;
+
+                       /* Wait for old command to finish */
+                       for (i = 0; i < 1000; ++i)
+                       {
+                               if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 )
+                                       break;
+                               udelay(1);
+                       }
+                       if (i >= 1000)
+                               return -EIO;
 
-               if (ioc.len)
-               {
-                       COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area),
-                                       ioc.data, ioc.len);
-                       privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
-               }
-               else
-                       privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
-               return(0);
-       default:
-               return -EOPNOTSUPP;
+                       privN->bcomm->bc_filter_port = ioc.port;
+                       privN->bcomm->bc_filter_num = ioc.filter;
+                       privN->bcomm->bc_filter_len = ioc.len;
+       
+                       if (ioc.len)
+                       {
+                               if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area),
+                                       ioc.data, ioc.len))
+                                       return -EFAULT;
+                               privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
+                       }
+                       else
+                               privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
+                       return(0);
+               default:
+                       return -EOPNOTSUPP;
        }
 }
 
@@ -906,8 +901,8 @@ dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd)
  *
  *     dev, priv will always refer to the 0th device in Multi-NIC mode.
  */
-static void
-dgrs_intr(int irq, void *dev_id, struct pt_regs *regs)
+
+static void dgrs_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct device   *dev0 = (struct device *) dev_id;
        DGRS_PRIV       *priv0 = (DGRS_PRIV *) dev0->priv;
index eeb629c14103c4a818acae09206e140849f2c87e..4a14920415bbae9e7ccadfdac885565e29e0935e 100644 (file)
@@ -5,7 +5,7 @@
  *             interfaces.  Requires 'dlcicfg' program to create usable 
  *             interfaces, the initial one, 'dlci' is for IOCTL use only.
  *
- * Version:    @(#)dlci.c      0.30    12 Sep 1996
+ * Version:    @(#)dlci.c      0.35    4 Jan 1997
  *
  * Author:     Mike McLagan <mike.mclagan@linux.org>
  *
@@ -20,6 +20,7 @@
  *                                     sent back to Linux for re-transmission
  *             0.25    Mike McLagan    Converted to use SIOC IOCTL calls
  *             0.30    Jim Freeman     Fixed to allow IPX traffic
+ *             0.35    Michael Elizabeth       Fixed incorrect memcpy_fromfs
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -55,7 +56,7 @@
 #include <net/sock.h>
 
 static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
+static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
 
 static struct device *open_dev[CONFIG_DLCI_COUNT];
 
@@ -66,51 +67,51 @@ int dlci_init(struct device *dev);
 /* allow FRAD's to register their name as a valid FRAD */
 int register_frad(const char *name)
 {
-   int i;
+       int i;
 
-   if (!name)
-      return(-EINVAL);
+       if (!name)
+               return(-EINVAL);
 
-   for (i=0;i<sizeof(basename) / sizeof(char *);i++)
-   {
-      if (!basename[i])
-         break;
+       for (i=0;i<sizeof(basename) / sizeof(char *);i++)
+       {
+               if (!basename[i])
+                       break;
 
-      /* take care of multiple registrations */
-      if (strcmp(basename[i], name) == 0)
-         return(0);
-   }
+               /* take care of multiple registrations */
+               if (strcmp(basename[i], name) == 0)
+                       return(0);
+       }
 
-   if (i == sizeof(basename) / sizeof(char *))
-      return(-EMLINK);
+       if (i == sizeof(basename) / sizeof(char *))
+               return(-EMLINK);
 
-   basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
-   if (!basename[i])
-      return(-ENOMEM);
+       basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
+       if (!basename[i])
+               return(-ENOMEM);
 
-   strcpy(basename[i], name);
+       strcpy(basename[i], name);
 
-   return(0);
+       return(0);
 }
 
 int unregister_frad(const char *name)
 {
-   int i;
+       int i;
 
-   if (!name)
-      return(-EINVAL);
+       if (!name)
+               return(-EINVAL);
 
-   for (i=0;i<sizeof(basename) / sizeof(char *);i++)
-      if (basename[i] && (strcmp(basename[i], name) == 0))
-         break;
+       for (i=0;i<sizeof(basename) / sizeof(char *);i++)
+               if (basename[i] && (strcmp(basename[i], name) == 0))
+                       break;
 
-   if (i == sizeof(basename) / sizeof(char *))
-      return(-EINVAL);
+       if (i == sizeof(basename) / sizeof(char *))
+               return(-EINVAL);
 
-   kfree(basename[i]);
-   basename[i] = NULL;
+       kfree(basename[i]);
+       basename[i] = NULL;
 
-   return(0);
+       return(0);
 }
 
 /* 
@@ -123,519 +124,501 @@ static int dlci_header(struct sk_buff *skb, struct device *dev,
                            unsigned short type, void *daddr, void *saddr, 
                            unsigned len)
 {
-   struct frhdr      hdr;
-   struct dlci_local *dlp;
-   unsigned          hlen;
-   char              *dest;
-
-   dlp = dev->priv;
-
-   hdr.control = FRAD_I_UI;
-   switch(type)
-   {
-      case ETH_P_IP:
-         hdr.IP_NLPID = FRAD_P_IP;
-         hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
-         break;
-
-      /* feel free to add other types, if necessary */
-
-      default:
-         hdr.pad = FRAD_P_PADDING;
-         hdr.NLPID = FRAD_P_SNAP;
-         memset(hdr.OUI, 0, sizeof(hdr.OUI));
-         hdr.PID = htons(type);
-         hlen = sizeof(hdr);
-         break;
-   }
-
-   dest = skb_push(skb, hlen);
-   if (!dest)
-      return(0);
-
-   memcpy(dest, &hdr, hlen);
-
-   return(hlen);
+       struct frhdr            hdr;
+       struct dlci_local       *dlp;
+       unsigned int            hlen;
+       char                    *dest;
+
+       dlp = dev->priv;
+
+       hdr.control = FRAD_I_UI;
+       switch(type)
+       {
+               case ETH_P_IP:
+                       hdr.IP_NLPID = FRAD_P_IP;
+                       hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
+                       break;
+
+               /* feel free to add other types, if necessary */
+
+               default:
+                       hdr.pad = FRAD_P_PADDING;
+                       hdr.NLPID = FRAD_P_SNAP;
+                       memset(hdr.OUI, 0, sizeof(hdr.OUI));
+                       hdr.PID = htons(type);
+                       hlen = sizeof(hdr);
+                       break;
+       }
+
+       dest = skb_push(skb, hlen);
+       if (!dest)
+               return(0);
+
+       memcpy(dest, &hdr, hlen);
+
+       return(hlen);
 }
 
 static void dlci_receive(struct sk_buff *skb, struct device *dev)
 {
-   struct dlci_local *dlp;
-   struct frhdr      *hdr;
-   int               process, header;
-
-   dlp = dev->priv;
-   hdr = (struct frhdr *) skb->data;
-   process = 0;
-   header = 0;
-   skb->dev = dev;
-
-   if (hdr->control != FRAD_I_UI)
-   {
-      printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
-      dlp->stats.rx_errors++;
-   }
-   else
-      switch(hdr->IP_NLPID)
-      {
-         case FRAD_P_PADDING:
-            if (hdr->NLPID != FRAD_P_SNAP)
-            {
-               printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
-               dlp->stats.rx_errors++;
-               break;
-            }
-    
-            if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
-            {
-               printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
-               dlp->stats.rx_errors++;
-               break;
-            }
-
-            /* at this point, it's an EtherType frame */
-            header = sizeof(struct frhdr);
-            /* Already in network order ! */
-            skb->protocol = hdr->PID;
-            process = 1;
-            break;
-
-         case FRAD_P_IP:
-            header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
-            skb->protocol = htons(ETH_P_IP);
-            process = 1;
-            break;
-
-         case FRAD_P_SNAP:
-         case FRAD_P_Q933:
-         case FRAD_P_CLNP:
-            printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
-            dlp->stats.rx_errors++;
-            break;
-
-         default:
-            printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
-            dlp->stats.rx_errors++;
-            break;            
-      }
-
-   if (process)
-   {
-      /* we've set up the protocol, so discard the header */
-      skb->mac.raw = skb->data; 
-      skb_pull(skb, header);
-      netif_rx(skb);
-      dlp->stats.rx_packets++;
-   }
-   else
-      dev_kfree_skb(skb, FREE_WRITE);
+       struct dlci_local *dlp;
+       struct frhdr            *hdr;
+       int                                     process, header;
+
+       dlp = dev->priv;
+       hdr = (struct frhdr *) skb->data;
+       process = 0;
+       header = 0;
+       skb->dev = dev;
+
+       if (hdr->control != FRAD_I_UI)
+       {
+               printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
+               dlp->stats.rx_errors++;
+       }
+       else
+               switch(hdr->IP_NLPID)
+               {
+                       case FRAD_P_PADDING:
+                               if (hdr->NLPID != FRAD_P_SNAP)
+                               {
+                                       printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
+                                       dlp->stats.rx_errors++;
+                                       break;
+                               }
+        
+                               if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
+                               {
+                                       printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
+                                       dlp->stats.rx_errors++;
+                                       break;
+                               }
+
+                               /* at this point, it's an EtherType frame */
+                               header = sizeof(struct frhdr);
+                               /* Already in network order ! */
+                               skb->protocol = hdr->PID;
+                               process = 1;
+                               break;
+
+                       case FRAD_P_IP:
+                               header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
+                               skb->protocol = htons(ETH_P_IP);
+                               process = 1;
+                               break;
+
+                       case FRAD_P_SNAP:
+                       case FRAD_P_Q933:
+                       case FRAD_P_CLNP:
+                               printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
+                               dlp->stats.rx_errors++;
+                               break;
+
+                       default:
+                               printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
+                               dlp->stats.rx_errors++;
+                               break;                          
+               }
+
+       if (process)
+       {
+               /* we've set up the protocol, so discard the header */
+               skb->mac.raw = skb->data; 
+               skb_pull(skb, header);
+               netif_rx(skb);
+               dlp->stats.rx_packets++;
+       }
+       else
+               dev_kfree_skb(skb, FREE_WRITE);
 }
 
 static int dlci_transmit(struct sk_buff *skb, struct device *dev)
 {
-   struct dlci_local *dlp;
-   int               ret;
+       struct dlci_local *dlp;
+       int                                     ret;
 
-   ret = 0;
+       ret = 0;
 
-   if (!skb || !dev)
-      return(0);
+       if (!skb || !dev)
+               return(0);
 
-   if (dev->tbusy)
-      return(1);
+       if (dev->tbusy)
+               return(1);
 
-   dlp = dev->priv;
+       dlp = dev->priv;
 
-   if (set_bit(0, (void*)&dev->tbusy) != 0)
-      printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-   else
-   {
-      ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
-      switch (ret)
-      {
-         case DLCI_RET_OK:
-            dlp->stats.tx_packets++;
-            ret = 0;
-            break;
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
+       else
+       {
+               ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
+               switch (ret)
+               {
+                       case DLCI_RET_OK:
+                               dlp->stats.tx_packets++;
+                               ret = 0;
+                               break;
 
-         case DLCI_RET_ERR:
-            dlp->stats.tx_errors++;
-            ret = 0;
-            break;
+                       case DLCI_RET_ERR:
+                               dlp->stats.tx_errors++;
+                               ret = 0;
+                               break;
 
-         case DLCI_RET_DROP:
-            dlp->stats.tx_dropped++;
-            ret = 1;
-            break;
-      }
+                       case DLCI_RET_DROP:
+                               dlp->stats.tx_dropped++;
+                               ret = 1;
+                               break;
+               }
 
-      /* Alan Cox recommends always returning 0, and always freeing the packet */
-      /* experience suggest a slightly more conservative approach */
+               /* Alan Cox recommends always returning 0, and always freeing the packet */
+               /* experience suggest a slightly more conservative approach */
 
-      if (!ret)
-         dev_kfree_skb(skb, FREE_WRITE);
+               if (!ret)
+                       dev_kfree_skb(skb, FREE_WRITE);
 
-      dev->tbusy = 0;
-   }
+               dev->tbusy = 0;
+       }
 
-   return(ret);
+       return(ret);
 }
 
 int dlci_config(struct device *dev, struct dlci_conf *conf, int get)
 {
-   struct dlci_conf  config;
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   int               err;
-
-   dlp = dev->priv;
-
-   flp = dlp->slave->priv;
-
-   if (!get)
-   {
-      err = verify_area(VERIFY_READ, conf, sizeof(struct dlci_conf));
-      if (err)
-         return(err);
-
-      copy_from_user(&config, conf, sizeof(struct dlci_conf));
-      if (config.flags & ~DLCI_VALID_FLAGS)
-         return(-EINVAL);
-      memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
-      dlp->configured = 1;
-   }
-
-   err = (*flp->dlci_conf)(dlp->slave, dev, get);
-   if (err)
-      return(err);
-
-   if (get)
-   {
-      err = verify_area(VERIFY_WRITE, conf, sizeof(struct dlci_conf));
-      if (err)
-         return(err);
-
-      copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf));
-   }
-
-   return(0);
+       struct dlci_conf        config;
+       struct dlci_local       *dlp;
+       struct frad_local       *flp;
+       int                     err;
+
+       dlp = dev->priv;
+
+       flp = dlp->slave->priv;
+
+       if (!get)
+       {
+               if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
+                       return -FAULT;
+               if (config.flags & ~DLCI_VALID_FLAGS)
+                       return(-EINVAL);
+               memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
+               dlp->configured = 1;
+       }
+
+       err = (*flp->dlci_conf)(dlp->slave, dev, get);
+       if (err)
+               return(err);
+
+       if (get)
+       {
+               if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
+                       return -EFAULT;
+       }
+
+       return(0);
 }
 
 int dlci_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
-   struct dlci_local *dlp;
-   int               err, len;
+       struct dlci_local *dlp;
 
-   if (!suser())
-      return(-EPERM);
+       if (!suser())
+               return(-EPERM);
 
-   dlp = dev->priv;
+       dlp = dev->priv;
 
-   switch(cmd)
-   {
-      case DLCI_GET_SLAVE:
-         if (!*(short *)(dev->dev_addr))
-            return(-EINVAL);
+       switch(cmd)
+       {
+               case DLCI_GET_SLAVE:
+                       if (!*(short *)(dev->dev_addr))
+                               return(-EINVAL);
 
-         len = strlen(dlp->slave->name) + 1;
-         err = verify_area(VERIFY_WRITE, ifr->ifr_slave, len);
-         if (err)
-            return err;
+                       strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
+                       break;
 
-         copy_to_user(ifr->ifr_slave, dlp->slave->name, len);
-         break;
+               case DLCI_GET_CONF:
+               case DLCI_SET_CONF:
+                       if (!*(short *)(dev->dev_addr))
+                               return(-EINVAL);
 
-      case DLCI_GET_CONF:
-      case DLCI_SET_CONF:
-         if (!*(short *)(dev->dev_addr))
-            return(-EINVAL);
+                       return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
+                       break;
 
-         return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
-         break;
-
-      default: 
-         return(-EOPNOTSUPP);
-   }
-   return(0);
+               default: 
+                       return(-EOPNOTSUPP);
+       }
+       return(0);
 }
 
 static int dlci_change_mtu(struct device *dev, int new_mtu)
 {
-   struct dlci_local *dlp;
+       struct dlci_local *dlp;
 
-   dlp = dev->priv;
+       dlp = dev->priv;
 
-   return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
+       return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
 }
 
 static int dlci_open(struct device *dev)
 {
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   int               err;
+       struct dlci_local       *dlp;
+       struct frad_local       *flp;
+       int                     err;
 
-   dlp = dev->priv;
+       dlp = dev->priv;
 
-   if (!*(short *)(dev->dev_addr))
-      return(-EINVAL);
+       if (!*(short *)(dev->dev_addr))
+               return(-EINVAL);
 
-   if (!dlp->slave->start)
-      return(-ENOTCONN);
+       if (!dlp->slave->start)
+               return(-ENOTCONN);
 
-   dev->flags = 0;
-   dev->tbusy = 0;
-   dev->interrupt = 0;
-   dev->start = 1;
+       dev->flags = 0;
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
 
-   flp = dlp->slave->priv;
-   err = (*flp->activate)(dlp->slave, dev);
-   if (err)
-      return(err);
+       flp = dlp->slave->priv;
+       err = (*flp->activate)(dlp->slave, dev);
+       if (err)
+               return(err);
 
-   return 0;
+       return 0;
 }
 
 static int dlci_close(struct device *dev)
 {
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   int               err;
+       struct dlci_local       *dlp;
+       struct frad_local       *flp;
+       int                     err;
 
-   dlp = dev->priv;
+       dlp = dev->priv;
 
-   flp = dlp->slave->priv;
-   err = (*flp->deactivate)(dlp->slave, dev);
+       flp = dlp->slave->priv;
+       err = (*flp->deactivate)(dlp->slave, dev);
 
-   dev->start = 0;
-   dev->tbusy = 1;
+       dev->start = 0;
+       dev->tbusy = 1;
 
-   return 0;
+       return 0;
 }
 
-static struct enet_statistics *dlci_get_stats(struct device *dev)
+static struct net_device_stats *dlci_get_stats(struct device *dev)
 {
-   struct dlci_local *dlp;
+       struct dlci_local *dlp;
 
-   dlp = dev->priv;
+       dlp = dev->priv;
 
-   return(&dlp->stats);
+       return(&dlp->stats);
 }
 
 int dlci_add(struct dlci_add *dlci)
 {
-   struct device       *master, *slave;
-   struct dlci_local   *dlp;
-   struct frad_local   *flp;
-   int                 err, i;
-   char                buf[10];
-
-   /* validate slave device */
-   slave = dev_get(dlci->devname);
-   if (!slave)
-      return(-ENODEV);
-
-   if (slave->type != ARPHRD_FRAD)
-      return(-EINVAL);
-
-   /* check for registration */
-   for (i=0;i<sizeof(basename) / sizeof(char *); i++)
-      if ((basename[i]) && 
-          (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
-          (strlen(dlci->devname) > strlen(basename[i])))
-         break;
-
-   if (i == sizeof(basename) / sizeof(char *))
-      return(-EINVAL);
-
-   /* check for too many open devices : should this be dynamic ? */
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      if (!open_dev[i])
-         break;
-
-   if (i == CONFIG_DLCI_COUNT)
-      return(-ENOSPC);  /*  #### Alan: Comments on this?? */
-
-   /* create device name */
-   sprintf(buf, "%s%02i", devname, i);
-
-   master = kmalloc(sizeof(*master), GFP_KERNEL);
-   if (!master)
-      return(-ENOMEM);
-
-   memset(master, 0, sizeof(*master));
-   master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
-
-   if (!master->name)
-   {
-      kfree(master);
-      return(-ENOMEM);
-   }
-
-   strcpy(master->name, buf);
-   master->init = dlci_init;
-   master->flags = 0;
-
-   err = register_netdev(master);
-   if (err < 0)
-   {
-      kfree(master->name);
-      kfree(master);
-      return(err);
-   }
-
-   *(short *)(master->dev_addr) = dlci->dlci;
-
-   dlp = (struct dlci_local *) master->priv;
-   dlp->slave = slave;
-
-   flp = slave->priv;
-   err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
-   if (err < 0)
-   {
-      unregister_netdev(master);
-      kfree(master->priv);
-      kfree(master->name);
-      kfree(master);
-      return(err);
-   }
-
-   strcpy(dlci->devname, buf);
-   open_dev[i] = master;
-   MOD_INC_USE_COUNT;
-   return(0);
+       struct device           *master, *slave;
+       struct dlci_local       *dlp;
+       struct frad_local       *flp;
+       int                     err, i;
+       char                    buf[10];
+
+       /* validate slave device */
+       slave = dev_get(dlci->devname);
+       if (!slave)
+               return(-ENODEV);
+
+       if (slave->type != ARPHRD_FRAD)
+               return(-EINVAL);
+
+       /* check for registration */
+       for (i=0;i<sizeof(basename) / sizeof(char *); i++)
+               if ((basename[i]) && 
+                        (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
+                        (strlen(dlci->devname) > strlen(basename[i])))
+                       break;
+
+       if (i == sizeof(basename) / sizeof(char *))
+               return(-EINVAL);
+
+       /* check for too many open devices : should this be dynamic ? */
+       for(i=0;i<CONFIG_DLCI_COUNT;i++)
+               if (!open_dev[i])
+                       break;
+
+       if (i == CONFIG_DLCI_COUNT)
+               return(-ENOSPC);  /*  #### Alan: Comments on this?? */
+
+       /* create device name */
+       sprintf(buf, "%s%02i", devname, i);
+
+       master = kmalloc(sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return(-ENOMEM);
+
+       memset(master, 0, sizeof(*master));
+       master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
+
+       if (!master->name)
+       {
+               kfree(master);
+               return(-ENOMEM);
+       }
+
+       strcpy(master->name, buf);
+       master->init = dlci_init;
+       master->flags = 0;
+
+       err = register_netdev(master);
+       if (err < 0)
+       {
+               kfree(master->name);
+               kfree(master);
+               return(err);
+       }
+
+       *(short *)(master->dev_addr) = dlci->dlci;
+
+       dlp = (struct dlci_local *) master->priv;
+       dlp->slave = slave;
+
+       flp = slave->priv;
+       err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
+       if (err < 0)
+       {
+               unregister_netdev(master);
+               kfree(master->priv);
+               kfree(master->name);
+               kfree(master);
+               return(err);
+       }
+
+       strcpy(dlci->devname, buf);
+       open_dev[i] = master;
+       MOD_INC_USE_COUNT;
+       return(0);
 }
 
 int dlci_del(struct dlci_add *dlci)
 {
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   struct device     *master, *slave;
-   int               i, err;
+       struct dlci_local       *dlp;
+       struct frad_local       *flp;
+       struct device           *master, *slave;
+       int                     i, err;
 
-   /* validate slave device */
-   master = dev_get(dlci->devname);
-   if (!master)
-      return(-ENODEV);
+       /* validate slave device */
+       master = dev_get(dlci->devname);
+       if (!master)
+               return(-ENODEV);
 
-   if (master->start)
-      return(-EBUSY);
+       if (master->start)
+               return(-EBUSY);
 
-   dlp = master->priv;
-   slave = dlp->slave;
-   flp = slave->priv;
+       dlp = master->priv;
+       slave = dlp->slave;
+       flp = slave->priv;
 
-   err = (*flp->deassoc)(slave, master);
-   if (err)
-      return(err);
+       err = (*flp->deassoc)(slave, master);
+       if (err)
+               return(err);
 
-   unregister_netdev(master);
+       unregister_netdev(master);
 
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      if (master == open_dev[i])
-         break;
+       for(i=0;i<CONFIG_DLCI_COUNT;i++)
+               if (master == open_dev[i])
+                       break;
 
-   if (i<CONFIG_DLCI_COUNT)
-      open_dev[i] = NULL;
+       if (i<CONFIG_DLCI_COUNT)
+               open_dev[i] = NULL;
 
-   kfree(master->priv);
-   kfree(master->name);
-   kfree(master);
+       kfree(master->priv);
+       kfree(master->name);
+       kfree(master);
 
-   MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
 
-   return(0);
+       return(0);
 }
 
 int dlci_ioctl(unsigned int cmd, void *arg)
 {
-   int             err;
-   struct dlci_add add;
-
-   if (!suser())
-      return(-EPERM);
-
-   err=verify_area(VERIFY_READ, arg, sizeof(struct dlci_add));
-   if (err)
-      return(err);
-
-   copy_from_user(&add, arg, sizeof(struct dlci_add));
-
-   switch (cmd)
-   {
-      case SIOCADDDLCI:
-         err = verify_area(VERIFY_WRITE, arg, sizeof(struct dlci_add));
-         if (err)
-            return(err);
-
-         err = dlci_add(&add);
-
-         if (!err)
-            copy_to_user(arg, &add, sizeof(struct dlci_add));
-         break;
-
-      case SIOCDELDLCI:
-         err = dlci_del(&add);
-         break;
-
-      default:
-         err = -EINVAL;
-   }
-
-   return(err);
+       struct dlci_add add;
+       int err;
+       
+       if (!suser())
+               return(-EPERM);
+
+       if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
+               return -EFAULT;
+
+       switch (cmd)
+       {
+               case SIOCADDDLCI:
+                       err = dlci_add(&add);
+
+                       if (!err)
+                               if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
+                                       return -EFAULT;
+                       break;
+
+               case SIOCDELDLCI:
+                       err = dlci_del(&add);
+                       break;
+
+               default:
+                       err = -EINVAL;
+       }
+
+       return(err);
 }
 
 int dlci_init(struct device *dev)
 {
-   struct dlci_local *dlp;
-
-   dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
-   if (!dev->priv)
-      return(-ENOMEM);
-
-   memset(dev->priv, 0, sizeof(struct dlci_local));
-   dlp = dev->priv;
-
-   dev->flags           = 0;
-   dev->open            = dlci_open;
-   dev->stop            = dlci_close;
-   dev->do_ioctl        = dlci_dev_ioctl;
-   dev->hard_start_xmit = dlci_transmit;
-   dev->hard_header     = dlci_header;
-   dev->get_stats       = dlci_get_stats;
-   dev->change_mtu     = dlci_change_mtu;
-
-   dlp->receive         = dlci_receive;
-
-   dev->type            = ARPHRD_DLCI;
-   dev->family          = AF_INET;
-   dev->hard_header_len = sizeof(struct frhdr);
-   dev->pa_alen         = sizeof(unsigned long);
-   dev->addr_len        = sizeof(short);
-   memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
-
-   dev->pa_addr         = 0;
-   dev->pa_dstaddr      = 0;
-   dev->pa_brdaddr      = 0;
-   dev->pa_mask         = 0;
-
-   dev_init_buffers(dev);
-   
-   return(0);
+       struct dlci_local *dlp;
+
+       dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
+       if (!dev->priv)
+               return(-ENOMEM);
+
+       memset(dev->priv, 0, sizeof(struct dlci_local));
+       dlp = dev->priv;
+
+       dev->flags              = 0;
+       dev->open               = dlci_open;
+       dev->stop               = dlci_close;
+       dev->do_ioctl           = dlci_dev_ioctl;
+       dev->hard_start_xmit    = dlci_transmit;
+       dev->hard_header        = dlci_header;
+       dev->get_stats          = dlci_get_stats;
+       dev->change_mtu         = dlci_change_mtu;
+
+       dlp->receive            = dlci_receive;
+
+       dev->type               = ARPHRD_DLCI;
+       dev->family             = AF_INET;
+       dev->hard_header_len    = sizeof(struct frhdr);
+       dev->pa_alen            = 4;
+       dev->addr_len           = sizeof(short);
+       memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
+
+       dev->pa_addr            = 0;
+       dev->pa_dstaddr         = 0;
+       dev->pa_brdaddr         = 0;
+       dev->pa_mask            = 0;
+
+       dev_init_buffers(dev);
+       
+       return(0);
 }
 
 int dlci_setup(void)
 {
-   int i;
+       int i;
 
-   printk("%s.\n", version);
-   
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      open_dev[i] = NULL;
+       printk("%s.\n", version);
+       
+       for(i=0;i<CONFIG_DLCI_COUNT;i++)
+               open_dev[i] = NULL;
 
-   for(i=0;i<sizeof(basename) / sizeof(char *);i++)
-      basename[i] = NULL;
+       for(i=0;i<sizeof(basename) / sizeof(char *);i++)
+               basename[i] = NULL;
 
-   return(0);
+       return(0);
 }
 
 #ifdef MODULE
@@ -644,13 +627,13 @@ extern int (*dlci_ioctl_hook)(unsigned int, void *);
 
 int init_module(void)
 {
-   dlci_ioctl_hook = dlci_ioctl;
+       dlci_ioctl_hook = dlci_ioctl;
 
-   return(dlci_setup());
+       return(dlci_setup());
 }
 
 void cleanup_module(void)
 {
-   dlci_ioctl_hook = NULL;
+       dlci_ioctl_hook = NULL;
 }
 #endif /* MODULE */
index 331c1a618acc5417202cd8ca9755193111c61729..4df420482efd2dd4a7c10131fa8cd03f30323d19 100644 (file)
@@ -55,7 +55,7 @@
 
 static int dummy_xmit(struct sk_buff *skb, struct device *dev);
 #ifdef DUMMY_STATS
-static struct enet_statistics *dummy_get_stats(struct device *dev);
+static struct net_device_stats *dummy_get_stats(struct device *dev);
 #endif
 
 static int dummy_open(struct device *dev)
@@ -81,10 +81,10 @@ int dummy_init(struct device *dev)
        dev->hard_start_xmit    = dummy_xmit;
 
 #if DUMMY_STATS
-       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+       dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
        if (dev->priv == NULL)
                return -ENOMEM;
-       memset(dev->priv, 0, sizeof(struct enet_statistics));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
        dev->get_stats          = dummy_get_stats;
 #endif
 
@@ -103,16 +103,12 @@ static int
 dummy_xmit(struct sk_buff *skb, struct device *dev)
 {
 #if DUMMY_STATS
-       struct enet_statistics *stats;
+       struct net_device_stats *stats;
 #endif
-
-       if (skb == NULL || dev == NULL)
-               return 0;
-
        dev_kfree_skb(skb, FREE_WRITE);
 
 #if DUMMY_STATS
-       stats = (struct enet_statistics *)dev->priv;
+       stats = (struct net_device_stats *)dev->priv;
        stats->tx_packets++;
 #endif
 
@@ -120,10 +116,9 @@ dummy_xmit(struct sk_buff *skb, struct device *dev)
 }
 
 #if DUMMY_STATS
-static struct enet_statistics *
-dummy_get_stats(struct device *dev)
+static struct net_device_stats *dummy_get_stats(struct device *dev)
 {
-       struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
+       struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
        return stats;
 }
 #endif
index 099f0416ca5ebc4280710f4140830a99486509f1..4515a2092c7406bacdce76c488a980f376406823 100644 (file)
@@ -128,7 +128,7 @@ static unsigned int net_debug = NET_DEBUG;
 
 /* Information that need to be kept for each board. */
 struct eepro_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        unsigned rx_start;
        unsigned tx_start; /* start of the transmit chain */
        int tx_last;  /* pointer to last packet in the transmit chain */
@@ -156,7 +156,7 @@ static void eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void    eepro_rx(struct device *dev);
 static void    eepro_transmit_interrupt(struct device *dev);
 static int     eepro_close(struct device *dev);
-static struct enet_statistics *eepro_get_stats(struct device *dev);
+static struct net_device_stats *eepro_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 static int read_eeprom(int ioaddr, int location);
@@ -846,7 +846,7 @@ eepro_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *
+static struct net_device_stats *
 eepro_get_stats(struct device *dev)
 {
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
index d8736f72c7acb3b0629f0efb03c4e7e28bb88e44..3f5555f2076e9ecb13f57c371212ac9caee02dc4 100644 (file)
 
 struct net_local
 {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
        unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
        unsigned short rx_last;      /* last rx buf */
@@ -189,7 +189,7 @@ static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
 extern int express_probe(struct device *dev);
 static int eexp_open(struct device *dev);
 static int eexp_close(struct device *dev);
-static struct enet_statistics *eexp_stats(struct device *dev);
+static struct net_device_stats *eexp_stats(struct device *dev);
 static int eexp_xmit(struct sk_buff *buf, struct device *dev);
 
 static void eexp_irq(int irq, void *dev_addr, struct pt_regs *regs);
@@ -358,7 +358,7 @@ static int eexp_close(struct device *dev)
  * Return interface stats
  */
 
-static struct enet_statistics *eexp_stats(struct device *dev)
+static struct net_device_stats *eexp_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
 
index 7ea10dc233f0ff67677562c4c798bb72035e756c..17d27338138175c4a3567acb27df691941908062 100644 (file)
@@ -155,7 +155,7 @@ static int eql_close(struct device *dev); /*  */
 static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd); /*  */
 static int eql_slave_xmit(struct sk_buff *skb, struct device *dev); /*  */
 
-static struct enet_statistics *eql_get_stats(struct device *dev); /*  */
+static struct net_device_stats *eql_get_stats(struct device *dev); /*  */
 
 /* ioctl() handlers
    ---------------- */
@@ -225,14 +225,14 @@ int eql_init(struct device *dev)
        memset (dev->priv, 0, sizeof (equalizer_t));
        eql = (equalizer_t *) dev->priv;
 
-       eql->stats = kmalloc (sizeof (struct enet_statistics), GFP_KERNEL);
+       eql->stats = kmalloc (sizeof (struct net_device_stats), GFP_KERNEL);
        if (eql->stats == NULL) 
        {
                kfree(dev->priv);
                dev->priv = NULL;
                return -ENOMEM;
        }
-       memset (eql->stats, 0, sizeof (struct enet_statistics));
+       memset (eql->stats, 0, sizeof (struct net_device_stats));
 
        init_timer (&eql->timer);
        eql->timer.data         = (unsigned long) dev->priv;
@@ -398,7 +398,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct device *dev)
 }
 
 
-static struct enet_statistics * eql_get_stats(struct device *dev)
+static struct net_device_stats * eql_get_stats(struct device *dev)
 {
        equalizer_t *eql = (equalizer_t *) dev->priv;
        return eql->stats;
index a5727b2fe655b265545ee4bd938ff9861f723bd9..2d0a2147ee9767be691e68d9d5a01620434ecdb3 100644 (file)
@@ -275,21 +275,30 @@ static char *version =
 #define RESET                  ID_ROM_0
 
 /* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] =
-   { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
+static unsigned int eth16i_portlist[] = {
+       0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+};
 
-static unsigned int eth32i_portlist[] =
-   { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
-     0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
+static unsigned int eth32i_portlist[] = {
+       0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+       0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+};
 
 /* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15 };
+static unsigned int eth16i_irqmap[] = {
+       9, 10, 5, 15
+};
 
 /* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15 };
+static unsigned int eth32i_irqmap[] = {
+       3, 5, 7, 9, 10, 11, 12, 15
+};
+
 #define EISA_IRQ_REG   0xc89
 
-static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
+static unsigned int eth16i_tx_buf_map[] = {
+       2048, 2048, 4096, 8192 
+};
 unsigned int boot = 1;
 
 /* Use 0 for production, 1 for verification, >2 for debug */
@@ -299,13 +308,14 @@ unsigned int boot = 1;
 static unsigned int eth16i_debug = ETH16I_DEBUG;
 
 /* Information for each board */
-struct eth16i_local {
-  struct enet_statistics stats;
-  unsigned int tx_started:1;
-  unsigned char tx_queue;         /* Number of packets in transmit buffer */
-  unsigned short tx_queue_len;
-  unsigned int tx_buf_size;
-  unsigned long open_time;
+struct eth16i_local
+{
+       struct net_device_stats stats;
+       unsigned int tx_started:1;
+       unsigned char tx_queue;        /* Number of packets in transmit buffer */
+       unsigned short tx_queue_len;
+       unsigned int tx_buf_size;
+       unsigned long open_time;
 };
 
 /* Function prototypes */
@@ -330,7 +340,7 @@ static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void eth16i_multicast(struct device *dev);
 static void eth16i_select_regbank(unsigned char regbank, short ioaddr);
 static void eth16i_initialize(struct device *dev);
-static struct enet_statistics *eth16i_get_stats(struct device *dev);
+static struct net_device_stats *eth16i_get_stats(struct device *dev);
 
 static char *cardname = "ICL EtherTeam 16i/32";
 
@@ -342,837 +352,845 @@ static char *cardname = "ICL EtherTeam 16i/32";
 #else  /* Not HAVE_DEVLIST */
 int eth16i_probe(struct device *dev)
 {
-  int i;
-  int ioaddr;
-  int base_addr = dev ? dev->base_addr : 0;
-
-  if(eth16i_debug > 4)
-    printk("Probing started for %s\n", cardname);
-
-  if(base_addr > 0x1ff)           /* Check only single location */
-    return eth16i_probe1(dev, base_addr);
-  else if(base_addr != 0)         /* Don't probe at all */
-    return ENXIO;
-
-  /* Seek card from the ISA io address space */
-  for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) {
-    if(check_region(ioaddr, ETH16I_IO_EXTENT))
-      continue;
-    if(eth16i_probe1(dev, ioaddr) == 0)
-      return 0;
-  }
-
-  /* Seek card from the EISA io address space */
-  for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
-    if(check_region(ioaddr, ETH16I_IO_EXTENT))
+       int i;
+       int ioaddr;
+       int base_addr = dev ? dev->base_addr : 0;
+
+       if(eth16i_debug > 4)
+               printk("Probing started for %s\n", cardname);
+
+       if(base_addr > 0x1ff)           /* Check only single location */
+               return eth16i_probe1(dev, base_addr);
+       else if(base_addr != 0)         /* Don't probe at all */
+               return ENXIO;
+
+       /* Seek card from the ISA io address space */
+       for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) {
+               if(check_region(ioaddr, ETH16I_IO_EXTENT))
+                       continue;
+               if(eth16i_probe1(dev, ioaddr) == 0)
+                       return 0;
+       }
+
+       /* Seek card from the EISA io address space */
+       for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
+               if(check_region(ioaddr, ETH16I_IO_EXTENT))
        continue;
-    if(eth16i_probe1(dev, ioaddr) == 0)
+               if(eth16i_probe1(dev, ioaddr) == 0)
        return 0;
-   }
+        }
 
-  return ENODEV;
+       return ENODEV;
 }
-#endif  /* Not HAVE_DEVLIST */
+#endif /* Not HAVE_DEVLIST */
 
 static int eth16i_probe1(struct device *dev, short ioaddr)
 {
-  static unsigned version_printed = 0;
-  unsigned int irq = 0;
-  boot = 1;          /* To inform initialization that we are in boot probe */
+       static unsigned version_printed = 0;
+       unsigned int irq = 0;
+       boot = 1;          /* To inform initialization that we are in boot probe */
 
-  /*
-     The MB86985 chip has on register which holds information in which
-     io address the chip lies. First read this register and compare
-     it to our current io address and if match then this could
-     be our chip.
-  */
+       /*
+                The MB86985 chip has on register which holds information in which
+                io address the chip lies. First read this register and compare
+                it to our current io address and if match then this could
+                be our chip.
+       */
 
-  if(ioaddr < 0x1000) {
-    if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr)
-      return -ENODEV;
-  }
+       if(ioaddr < 0x1000) {
+               if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr)
+                       return -ENODEV;
+       }
 
-  /* Now we will go a bit deeper and try to find the chip's signature */
+       /* Now we will go a bit deeper and try to find the chip's signature */
 
-  if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */
-    return -ENODEV;
+       if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */
+               return -ENODEV;
 
-  /*
-     Now it seems that we have found an ethernet chip in this particular
-     ioaddr. The MB86985 chip has this feature, that when you read a
-     certain register it will increase its io base address to next
-     configurable slot. Now when we have found the chip, first thing is
-     to make sure that the chip's ioaddr will hold still here.
-  */
+       /*
+                Now it seems that we have found an ethernet chip in this particular
+                ioaddr. The MB86985 chip has this feature, that when you read a
+                certain register it will increase its io base address to next
+                configurable slot. Now when we have found the chip, first thing is
+                to make sure that the chip's ioaddr will hold still here.
+       */
 
-  eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-  outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
+       eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+       outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
 
-  outb(0x00, ioaddr + RESET);             /* Will reset some parts of chip */
-  BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* This will disable the data link */
+       outb(0x00, ioaddr + RESET);             /* Will reset some parts of chip */
+       BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* This will disable the data link */
 
-  if(dev == NULL)
-    dev = init_etherdev(0, sizeof(struct eth16i_local));
+       if(dev == NULL)
+               dev = init_etherdev(0, sizeof(struct eth16i_local));
 
-  if( (eth16i_debug & version_printed++) == 0)
-    printk(version);
+       if( (eth16i_debug & version_printed++) == 0)
+               printk(version);
 
-  dev->base_addr = ioaddr;
+       dev->base_addr = ioaddr;
 
-  irq = eth16i_get_irq(ioaddr);
-  dev->irq = irq;
+       irq = eth16i_get_irq(ioaddr);
+       dev->irq = irq;
 
-  /* Try to obtain interrupt vector */
-  if(request_irq(dev->irq, &eth16i_interrupt, 0, "eth16i", NULL)) {
-    printk("%s: %s at %#3x, but is unusable due
-           conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq);
-    return EAGAIN;
-  }
+       /* Try to obtain interrupt vector */
+       if(request_irq(dev->irq, &eth16i_interrupt, 0, "eth16i", NULL)) {
+               printk("%s: %s at %#3x, but is unusable due
+                      conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq);
+               return EAGAIN;
+       }
 
-  printk("%s: %s at %#3x, IRQ %d, ",
+       printk("%s: %s at %#3x, IRQ %d, ",
         dev->name, cardname, ioaddr, dev->irq);
 
-  /* Let's grab the region */
-  request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
+       /* Let's grab the region */
+       request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
 
-  /* Now we will have to lock the chip's io address */
-  eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-  outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
+       /* Now we will have to lock the chip's io address */
+       eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+       outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
 
-  eth16i_initialize(dev);   /* Initialize rest of the chip's registers */
+       eth16i_initialize(dev);  /* Initialize rest of the chip's registers */
 
-  /* Now let's same some energy by shutting down the chip ;) */
-  BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
+       /* Now let's same some energy by shutting down the chip ;) */
+       BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
 
-  /* Initialize the device structure */
-  if(dev->priv == NULL)
-    dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
-  memset(dev->priv, 0, sizeof(struct eth16i_local));
+       /* Initialize the device structure */
+       if(dev->priv == NULL)
+               dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
+       memset(dev->priv, 0, sizeof(struct eth16i_local));
 
-  dev->open               = eth16i_open;
-  dev->stop               = eth16i_close;
-  dev->hard_start_xmit    = eth16i_tx;
-  dev->get_stats          = eth16i_get_stats;
-  dev->set_multicast_list = &eth16i_multicast;
+       dev->open               = eth16i_open;
+       dev->stop               = eth16i_close;
+       dev->hard_start_xmit    = eth16i_tx;
+       dev->get_stats          = eth16i_get_stats;
+       dev->set_multicast_list = &eth16i_multicast;
 
-  /* Fill in the fields of the device structure with ethernet values. */
-  ether_setup(dev);
+       /* Fill in the fields of the device structure with ethernet values. */
+       ether_setup(dev);
 
-  boot = 0;
+       boot = 0;
 
-  return 0;
+       return 0;
 }
 
 
 static void eth16i_initialize(struct device *dev)
 {
-  short ioaddr = dev->base_addr;
-  int i, node_w = 0;
-  unsigned char node_byte = 0;
-
-  /* Setup station address */
-  eth16i_select_regbank(NODE_ID_RB, ioaddr);
-  for(i = 0 ; i < 3 ; i++) {
-    unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
-    ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
-  }
+       short ioaddr = dev->base_addr;
+       int i, node_w = 0;
+       unsigned char node_byte = 0;
+
+       /* Setup station address */
+       eth16i_select_regbank(NODE_ID_RB, ioaddr);
+       for(i = 0 ; i < 3 ; i++) {
+               unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
+               ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
+       }
 
-  for(i = 0; i < 6; i++) {
-    outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
-    if(boot) {
-      printk("%02x", inb(ioaddr + NODE_ID_0 + i));
-      if(i != 5)
-       printk(":");
-    }
-  }
+       for(i = 0; i < 6; i++) 
+       {
+               outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
+               if(boot) 
+               {
+                       printk("%02x", inb(ioaddr + NODE_ID_0 + i));
+                       if(i != 5)
+                               printk(":");
+               }
+       }
 
-  /* Now we will set multicast addresses to accept none */
-  eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
-  for(i = 0; i < 8; i++)
-    outb(0x00, ioaddr + HASH_TABLE_0 + i);
+       /* Now we will set multicast addresses to accept none */
+       eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
+       for(i = 0; i < 8; i++)
+               outb(0x00, ioaddr + HASH_TABLE_0 + i);
 
-  /*
-     Now let's disable the transmitter and receiver, set the buffer ram
-     cycle time, bus width and buffer data path width. Also we shall
-     set transmit buffer size and total buffer size.
-  */
+       /*
+                Now let's disable the transmitter and receiver, set the buffer ram
+                cycle time, bus width and buffer data path width. Also we shall
+                set transmit buffer size and total buffer size.
+       */
 
-  eth16i_select_regbank(2, ioaddr);
+       eth16i_select_regbank(2, ioaddr);
 
-  node_byte = 0;
-  node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
+       node_byte = 0;
+       node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
 
-  if( (node_w & 0xFF00) == 0x0800)
-    node_byte |= BUFFER_WIDTH_8;
+       if( (node_w & 0xFF00) == 0x0800)
+               node_byte |= BUFFER_WIDTH_8;
 
-  node_byte |= MBS1;
+       node_byte |= MBS1;
 
-  if( (node_w & 0x00FF) == 64)
-    node_byte |= MBS0;
+       if( (node_w & 0x00FF) == 64)
+               node_byte |= MBS0;
 
-  node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
+       node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
 
-  outb(node_byte, ioaddr + CONFIG_REG_0);
+       outb(node_byte, ioaddr + CONFIG_REG_0);
 
-  /* We shall halt the transmitting, if 16 collisions are detected */
-  outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG);
+       /* We shall halt the transmitting, if 16 collisions are detected */
+       outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG);
 
-  if(boot) /* Now set port type */
-  {
-    char *porttype[] = {"BNC", "DIX", "TP", "AUTO"};
+       if(boot) /* Now set port type */
+       {
+               char *porttype[] = {"BNC", "DIX", "TP", "AUTO"};
 
-    ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
-    dev->if_port = (ptype & 0x00FF);
+               ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
+               dev->if_port = (ptype & 0x00FF);
 
-    printk(" %s interface.\n", porttype[dev->if_port]);
+               printk(" %s interface.\n", porttype[dev->if_port]);
 
-    if(ptype == E_PORT_AUTO)
-      ptype = eth16i_probe_port(ioaddr);
+               if(ptype == E_PORT_AUTO)
+                       ptype = eth16i_probe_port(ioaddr);
 
-    eth16i_set_port(ioaddr, ptype);
-  }
+               eth16i_set_port(ioaddr, ptype);
+       }
 
-  /* Set Receive Mode to normal operation */
-  outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
+       /* Set Receive Mode to normal operation */
+       outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
 }
 
 static int eth16i_probe_port(short ioaddr)
 {
-  int i;
-  int retcode;
-  unsigned char dummy_packet[64] = { 0 };
-
-  /* Powerup the chip */
-  outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
-  BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
-  eth16i_select_regbank(NODE_ID_RB, ioaddr);
-
-  for(i = 0; i < 6; i++) {
-    dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
-    dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
-  }
-
-  dummy_packet[12] = 0x00;
-  dummy_packet[13] = 0x04;
-
-  eth16i_select_regbank(2, ioaddr);
-
-  for(i = 0; i < 3; i++) {
-    BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-    BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-    eth16i_set_port(ioaddr, i);
-
-    if(eth16i_debug > 1)
-       printk("Set port number %d\n", i);
-
-    retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
-    if(retcode == 0) {
-      retcode = eth16i_receive_probe_packet(ioaddr);
-      if(retcode != -1) {
-       if(eth16i_debug > 1)
-               printk("Eth16i interface port found at %d\n", i);
-       return i;
-      }
-    }
-    else {
-      if(eth16i_debug > 1)
-       printk("TRANSMIT_DONE timeout\n");
-    }
-  }
-
-  if( eth16i_debug > 1)
-       printk("Using default port\n");
-
- return E_PORT_BNC;
+       int i;
+       int retcode;
+       unsigned char dummy_packet[64] = { 0 };
+
+       /* Powerup the chip */
+       outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
+
+       BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+
+       eth16i_select_regbank(NODE_ID_RB, ioaddr);
+
+       for(i = 0; i < 6; i++) {
+               dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
+               dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
+       }
+
+       dummy_packet[12] = 0x00;
+       dummy_packet[13] = 0x04;
+
+       eth16i_select_regbank(2, ioaddr);
+
+       for(i = 0; i < 3; i++) {
+               BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+               BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+               eth16i_set_port(ioaddr, i);
+
+               if(eth16i_debug > 1)
+                       printk("Set port number %d\n", i);
+
+               retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
+               if(retcode == 0) 
+               {
+                       retcode = eth16i_receive_probe_packet(ioaddr);
+                       if(retcode != -1) 
+                       {
+                               if(eth16i_debug > 1)
+                                       printk("Eth16i interface port found at %d\n", i);
+                               return i;
+                       }
+               }
+               else {
+                       if(eth16i_debug > 1)
+                               printk("TRANSMIT_DONE timeout\n");
+               }
+       }
+
+       if( eth16i_debug > 1)
+               printk("Using default port\n");
+
+       return E_PORT_BNC;
 }
 
 static void eth16i_set_port(short ioaddr, int porttype)
 {
-    unsigned short temp = 0;
+       unsigned short temp = 0;
 
-    eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-    outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
+       eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+       outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
 
-    temp |= DIS_AUTO_PORT_SEL;
+       temp |= DIS_AUTO_PORT_SEL;
+       switch(porttype) 
+       {
 
-    switch(porttype) {
+               case E_PORT_BNC :
+                       temp |= AUI_SELECT;
+                       break;
 
-    case E_PORT_BNC :
-      temp |= AUI_SELECT;
-      break;
+               case E_PORT_TP :
+                       break;
 
-    case E_PORT_TP :
-      break;
-
-    case E_PORT_DIX :
-      temp |= AUI_SELECT;
-      BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
-      break;
-    }
-    outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
+               case E_PORT_DIX :
+                       temp |= AUI_SELECT;
+                       BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
+                       break;
+       }
+       outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
 
-    if(eth16i_debug > 1) {
-       printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
-       printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG));
-    }
+       if(eth16i_debug > 1) {
+               printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
+               printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG));
+       }
 }
 
 static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l)
 {
-  int starttime;
+       int starttime;
 
-  outb(0xff, ioaddr + TX_STATUS_REG);
+       outb(0xff, ioaddr + TX_STATUS_REG);
 
-  outw(l, ioaddr + DATAPORT);
-  outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
+       outw(l, ioaddr + DATAPORT);
+       outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
 
-  starttime = jiffies;
-  outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
+       starttime = jiffies;
+       outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
 
-  while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
-    if( (jiffies - starttime) > TIMEOUT_TICKS) {
-      break;
-    }
-  }
-
-  return(0);
+       while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) 
+               if( (jiffies - starttime) > TIMEOUT_TICKS)
+                       break;
+       return(0);
 }
 
 static int eth16i_receive_probe_packet(short ioaddr)
 {
-  int starttime;
-
-  starttime = jiffies;
-
-  while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
-    if( (jiffies - starttime) > TIMEOUT_TICKS) {
-
-      if(eth16i_debug > 1)
-       printk("Timeout occurred waiting transmit packet received\n");
-      starttime = jiffies;
-      while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
-       if( (jiffies - starttime) > TIMEOUT_TICKS) {
-       if(eth16i_debug > 1)
-         printk("Timeout occurred waiting receive packet\n");
-        return -1;
-        }
-      }
-
-      if(eth16i_debug > 1)
-       printk("RECEIVE_PACKET\n");
-      return(0); /* Found receive packet */
-    }
-  }
-
-  if(eth16i_debug > 1) {
-       printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
-       printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
-  }
-
-  return(0); /* Return success */
+       int starttime;
+
+       starttime = jiffies;
+
+       while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) 
+       {
+               if( (jiffies - starttime) > TIMEOUT_TICKS) 
+               {
+                       if(eth16i_debug > 1)
+                               printk("Timeout occurred waiting transmit packet received\n");
+                       starttime = jiffies;
+                       while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) 
+                       {
+                               if( (jiffies - starttime) > TIMEOUT_TICKS) 
+                               {
+                                       if(eth16i_debug > 1)
+                                               printk("Timeout occurred waiting receive packet\n");
+                                       return -1;
+                               }
+                       }
+
+                       if(eth16i_debug > 1)
+                               printk("RECEIVE_PACKET\n");
+                       return(0); /* Found receive packet */
+               }
+       }
+
+       if(eth16i_debug > 1) {
+               printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
+               printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
+       }
+
+       return(0); /* Return success */
 }
 
 static int eth16i_get_irq(short ioaddr)
 {
-  unsigned char cbyte;
+       unsigned char cbyte;
 
-  if( ioaddr < 0x1000) {
-       cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+       if( ioaddr < 0x1000) {
+               cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
        return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
-  } else {  /* Oh..the card is EISA so method getting IRQ different */
+       } else {        /* Oh..the card is EISA so method getting IRQ different */
        unsigned short index = 0;
        cbyte = inb(ioaddr + EISA_IRQ_REG);
        while( (cbyte & 0x01) == 0) {
                cbyte = cbyte >> 1;
                index++;
-        }
+                               }
        return( eth32i_irqmap[ index ] );
-  }
+       }
 }
 
 static int eth16i_check_signature(short ioaddr)
 {
-  int i;
-  unsigned char creg[4] = { 0 };
+       int i;
+       unsigned char creg[4] = { 0 };
 
-  for(i = 0; i < 4 ; i++) {
+       for(i = 0; i < 4 ; i++) {
 
-    creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
+               creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
 
-    if(eth16i_debug > 1)
+               if(eth16i_debug > 1)
        printk("eth16i: read signature byte %x at %x\n", creg[i],
-              ioaddr + TRANSMIT_MODE_REG + i);
-  }
+                                ioaddr + TRANSMIT_MODE_REG + i);
+       }
 
-  creg[0] &= 0x0F;      /* Mask collision cnr */
-  creg[2] &= 0x7F;      /* Mask DCLEN bit */
+       creg[0] &= 0x0F;      /* Mask collision cnr */
+       creg[2] &= 0x7F;      /* Mask DCLEN bit */
 
 #ifdef 0
 /*
        This was removed because the card was sometimes left to state
        from which it couldn't be find anymore. If there is need
-       to more strict chech still this have to be fixed.
+       to have a more strict check still this have to be fixed.
 */
-  if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) {
-    if(creg[1] != 0x42)
-      return -1;
-  }
+       if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) {
+               if(creg[1] != 0x42)
+                       return -1;
+       }
 #endif
 
-  if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
-      creg[2] &= 0x42;
-      creg[3] &= 0x03;
+       if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) 
+       {
+               creg[2] &= 0x42;
+               creg[3] &= 0x03;
 
-      if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) )
-       return -1;
-  }
+               if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) )
+                       return -1;
+       }
 
-  if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
-    return -1;
-  if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
-    return -1;
+       if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
+               return -1;
+       if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
+               return -1;
 
-  return 0;
+       return 0;
 }
 
 static int eth16i_read_eeprom(int ioaddr, int offset)
 {
-  int data = 0;
+       int data = 0;
 
-  eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
-  outb(CS_1, ioaddr + EEPROM_CTRL_REG);
-  data = eth16i_read_eeprom_word(ioaddr);
-  outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+       eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
+       outb(CS_1, ioaddr + EEPROM_CTRL_REG);
+       data = eth16i_read_eeprom_word(ioaddr);
+       outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
 
-  return(data);
+       return(data);
 }
 
 static int eth16i_read_eeprom_word(int ioaddr)
 {
-  int i;
-  int data = 0;
-
-  for(i = 16; i > 0; i--) {
-    outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-    outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-    data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
-    eeprom_slow_io();
-  }
-
-  return(data);
+       int i;
+       int data = 0;
+
+       for(i = 16; i > 0; i--) {
+               outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+               eeprom_slow_io();
+               outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+               eeprom_slow_io();
+               data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+               eeprom_slow_io();
+       }
+
+       return(data);
 }
 
 static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
 {
-  int i;
-
-  outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-  outb(DI_0, ioaddr + EEPROM_DATA_REG);
-  outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-  outb(DI_1, ioaddr + EEPROM_DATA_REG);
-  outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-
-  for(i = 7; i >= 0; i--) {
-    short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
-    outb(cmd, ioaddr + EEPROM_DATA_REG);
-    outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-    outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-  }
+       int i;
+
+       outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+       outb(DI_0, ioaddr + EEPROM_DATA_REG);
+       outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+       outb(DI_1, ioaddr + EEPROM_DATA_REG);
+       outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+
+       for(i = 7; i >= 0; i--) {
+               short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
+               outb(cmd, ioaddr + EEPROM_DATA_REG);
+               outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+               eeprom_slow_io();
+               outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+               eeprom_slow_io();
+       }
 }
 
 static int eth16i_open(struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
+       struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+       int ioaddr = dev->base_addr;
 
-  irq2dev_map[dev->irq] = dev;
+       irq2dev_map[dev->irq] = dev;
 
-  /* Powerup the chip */
-  outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
+       /* Powerup the chip */
+       outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
 
-  /* Initialize the chip */
-  eth16i_initialize(dev);
+       /* Initialize the chip */
+       eth16i_initialize(dev);
 
-  /* Set the transmit buffer size */
-  lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
+       /* Set the transmit buffer size */
+       lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
 
-  if(eth16i_debug > 3)
-    printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size);
+       if(eth16i_debug > 3)
+               printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size);
 
-  /* Now enable Transmitter and Receiver sections */
-  BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+       /* Now enable Transmitter and Receiver sections */
+       BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
 
-  /* Now switch to register bank 2, for run time operation */
-  eth16i_select_regbank(2, ioaddr);
+       /* Now switch to register bank 2, for run time operation */
+       eth16i_select_regbank(2, ioaddr);
 
-  lp->open_time = jiffies;
-  lp->tx_started = 0;
-  lp->tx_queue = 0;
-  lp->tx_queue_len = 0;
+       lp->open_time = jiffies;
+       lp->tx_started = 0;
+       lp->tx_queue = 0;
+       lp->tx_queue_len = 0;
 
-  /* Turn on interrupts*/
-  outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+       /* Turn on interrupts*/
+       outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
 
-  dev->tbusy = 0;
-  dev->interrupt = 0;
-  dev->start = 1;
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
 
 #ifdef MODULE
-  MOD_INC_USE_COUNT;
+       MOD_INC_USE_COUNT;
 #endif
 
-  return 0;
+       return 0;
 }
 
 static int eth16i_close(struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
+       struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+       int ioaddr = dev->base_addr;
 
-  lp->open_time = 0;
+       lp->open_time = 0;
 
-  dev->tbusy = 1;
-  dev->start = 0;
+       dev->tbusy = 1;
+       dev->start = 0;
 
-  /* Disable transmit and receive */
-  BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+       /* Disable transmit and receive */
+       BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
 
-  /* Reset the chip */
-  outb(0xff, ioaddr + RESET);
+       /* Reset the chip */
+       outb(0xff, ioaddr + RESET);
 
-  /* Save some energy by switching off power */
-  BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
+       /* Save some energy by switching off power */
+       BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
 
 #ifdef MODULE
-  MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
 #endif
 
-  return 0;
+       return 0;
 }
 
 static int eth16i_tx(struct sk_buff *skb, struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
-
-  if(dev->tbusy) {
-    /*
-       If we get here, some higher level has decided that we are broken.
-       There should really be a "kick me" function call instead.
-    */
-
-    int tickssofar = jiffies - dev->trans_start;
-    if(tickssofar < TIMEOUT_TICKS)  /* Let's not rush with our timeout, */
-      return 1;                     /* wait a couple of ticks first     */
-
-    printk("%s: transmit timed out with status %04x, %s ?\n", dev->name,
-          inw(ioaddr + TX_STATUS_REG),
-          (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
-          "IRQ conflict" : "network cable problem");
+       struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+       int ioaddr = dev->base_addr;
 
-    /* Let's dump all registers */
-    if(eth16i_debug > 0) {
-      printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
-            dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
-            inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
-            inb(ioaddr + 6), inb(ioaddr + 7));
+       if(dev->tbusy) {
+               /*
+                        If we get here, some higher level has decided that we are broken.
+                        There should really be a "kick me" function call instead.
+               */
 
+               int tickssofar = jiffies - dev->trans_start;
+               if(tickssofar < TIMEOUT_TICKS)  /* Let's not rush with our timeout, */
+                       return 1;                     /* wait a couple of ticks first     */
 
-      printk("lp->tx_queue = %d\n", lp->tx_queue);
-      printk("lp->tx_queue_len = %d\n", lp->tx_queue_len);
-      printk("lp->tx_started = %d\n", lp->tx_started);
+               printk("%s: transmit timed out with status %04x, %s ?\n", dev->name,
+                inw(ioaddr + TX_STATUS_REG),
+                (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+                "IRQ conflict" : "network cable problem");
 
-    }
+               /* Let's dump all registers */
+               if(eth16i_debug > 0) {
+                       printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+                        dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
+                        inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
+                        inb(ioaddr + 6), inb(ioaddr + 7));
 
-    lp->stats.tx_errors++;
 
-    /* Now let's try to restart the adaptor */
+                       printk("lp->tx_queue = %d\n", lp->tx_queue);
+                       printk("lp->tx_queue_len = %d\n", lp->tx_queue_len);
+                       printk("lp->tx_started = %d\n", lp->tx_started);
 
-    BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-    outw(0xffff, ioaddr + RESET);
-    eth16i_initialize(dev);
-    outw(0xffff, ioaddr + TX_STATUS_REG);
-    BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+               }
 
-    lp->tx_started = 0;
-    lp->tx_queue = 0;
-    lp->tx_queue_len = 0;
+               lp->stats.tx_errors++;
 
-    outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+               /* Now let's try to restart the adaptor */
 
-    dev->tbusy = 0;
-    dev->trans_start = jiffies;
-  }
+               BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+               outw(0xffff, ioaddr + RESET);
+               eth16i_initialize(dev);
+               outw(0xffff, ioaddr + TX_STATUS_REG);
+               BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
 
-  /*
-     If some higher layer thinks we've missed an tx-done interrupt
-     we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-     itself
-  */
-  if(skb == NULL) {
-    dev_tint(dev);
-    return 0;
-  }
+               lp->tx_started = 0;
+               lp->tx_queue = 0;
+               lp->tx_queue_len = 0;
 
-  /* Block a timer based transmitter from overlapping. This could better be
-     done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+               outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
 
-  /* Turn off TX interrupts */
-  outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-  if(set_bit(0, (void *)&dev->tbusy) != 0)
-    printk("%s: Transmitter access conflict.\n", dev->name);
-  else {
-    short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-    unsigned char *buf = skb->data;
-
-    outw(length, ioaddr + DATAPORT);
-
-    if( ioaddr < 0x1000 )
-       outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-    else {
-       unsigned char frag = length % 4;
-
-       outsl(ioaddr + DATAPORT, buf, length >> 2);
-
-       if( frag != 0 ) {
-         outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
-         if( frag == 3 )
-           outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1);
+               dev->tbusy = 0;
+               dev->trans_start = jiffies;
        }
-    }
-
-    lp->tx_queue++;
-    lp->tx_queue_len += length + 2;
-
-    if(lp->tx_started == 0) {
-      /* If the transmitter is idle..always trigger a transmit */
-      outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-      lp->tx_queue = 0;
-      lp->tx_queue_len = 0;
-      dev->trans_start = jiffies;
-      lp->tx_started = 1;
-      dev->tbusy = 0;
-    }
-    else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-      /* There is still more room for one more packet in tx buffer */
-      dev->tbusy = 0;
-    }
-
-    outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-    /* Turn TX interrupts back on */
-    /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
-  }
-  dev_kfree_skb(skb, FREE_WRITE);
-
-  return 0;
-}
 
-static void eth16i_rx(struct device *dev)
-{
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
-  int boguscount = MAX_RX_LOOP;
-
-  /* Loop until all packets have been read */
-  while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
-
-    /* Read status byte from receive buffer */
-    ushort status = inw(ioaddr + DATAPORT);
-
-    if(eth16i_debug > 4)
-      printk("%s: Receiving packet mode %02x status %04x.\n",
-            dev->name, inb(ioaddr + RECEIVE_MODE_REG), status);
-
-      if( !(status & PKT_GOOD) ) {
-       /* Hmm..something went wrong. Let's check what error occurred */
-       lp->stats.rx_errors++;
-       if( status & PKT_SHORT     ) lp->stats.rx_length_errors++;
-       if( status & PKT_ALIGN_ERR ) lp->stats.rx_frame_errors++;
-       if( status & PKT_CRC_ERR   ) lp->stats.rx_crc_errors++;
-       if( status & PKT_RX_BUF_OVERFLOW) lp->stats.rx_over_errors++;
-      }
-      else {   /* Ok so now we should have a good packet */
-       struct sk_buff *skb;
-
-       /* Get the size of the packet from receive buffer */
-       ushort pkt_len = inw(ioaddr + DATAPORT);
-
-       if(pkt_len > ETH_FRAME_LEN) {
-         printk("%s: %s claimed a very large packet, size of %d bytes.\n",
-                dev->name, cardname, pkt_len);
-         outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
-         lp->stats.rx_dropped++;
-         break;
-       }
+       /* Block a timer based transmitter from overlapping. This could better be
+                done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
 
-       skb = dev_alloc_skb(pkt_len + 3);
-       if( skb == NULL ) {
-         printk("%s: Couldn't allocate memory for packet (len %d)\n",
-                dev->name, pkt_len);
-         outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
-         lp->stats.rx_dropped++;
-         break;
-       }
-
-       skb->dev = dev;
-       skb_reserve(skb,2);
-       /*
-          Now let's get the packet out of buffer.
-          size is (pkt_len + 1) >> 1, cause we are now reading words
-          and it have to be even aligned.
-       */
+       /* Turn off TX interrupts */
+       outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
 
-       if( ioaddr < 0x1000)
-         insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1);
+       if(set_bit(0, (void *)&dev->tbusy) != 0)
+               printk("%s: Transmitter access conflict.\n", dev->name);
        else {
-         unsigned char *buf = skb_put(skb, pkt_len);
-         unsigned char frag = pkt_len % 4;
-
-         insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
-
-         if(frag != 0) {
-               unsigned short rest[2];
-               rest[0] = inw( ioaddr + DATAPORT );
-               if(frag == 3)
-                       rest[1] = inw( ioaddr + DATAPORT );
-
-               memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
-         }
+               short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+               unsigned char *buf = skb->data;
+
+               outw(length, ioaddr + DATAPORT);
+
+               if( ioaddr < 0x1000 )
+                       outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+               else 
+               {
+                       unsigned char frag = length % 4;
+
+                       outsl(ioaddr + DATAPORT, buf, length >> 2);
+
+                       if( frag != 0 ) 
+                       {
+                               outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+                               if( frag == 3 )
+                                       outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1);
+                       }
+               }
+
+               lp->tx_queue++;
+               lp->tx_queue_len += length + 2;
+
+               if(lp->tx_started == 0) {
+                       /* If the transmitter is idle..always trigger a transmit */
+                       outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+                       lp->tx_queue = 0;
+                       lp->tx_queue_len = 0;
+                       dev->trans_start = jiffies;
+                       lp->tx_started = 1;
+                       dev->tbusy = 0;
+               }
+               else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+                       /* There is still more room for one more packet in tx buffer */
+                       dev->tbusy = 0;
+               }
+
+               outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+
+               /* Turn TX interrupts back on */
+               /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
        }
+       dev_kfree_skb(skb, FREE_WRITE);
 
-        skb->protocol=eth_type_trans(skb, dev);
-       netif_rx(skb);
-       lp->stats.rx_packets++;
-
-       if( eth16i_debug > 5 ) {
-         int i;
-         printk("%s: Received packet of length %d.\n", dev->name, pkt_len);
-         for(i = 0; i < 14; i++)
-           printk(" %02x", skb->data[i]);
-         printk(".\n");
-       }
-
-      } /* else */
-
-    if(--boguscount <= 0)
-      break;
+       return 0;
+}
 
-  } /* while */
+static void eth16i_rx(struct device *dev)
+{
+       struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int boguscount = MAX_RX_LOOP;
+
+       /* Loop until all packets have been read */
+       while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) 
+       {
+               /* Read status byte from receive buffer */
+               ushort status = inw(ioaddr + DATAPORT);
+
+               if(eth16i_debug > 4)
+                       printk("%s: Receiving packet mode %02x status %04x.\n",
+                               dev->name, inb(ioaddr + RECEIVE_MODE_REG), status);
+
+               if( !(status & PKT_GOOD) ) 
+               {
+                       /* Hmm..something went wrong. Let's check what error occurred */
+                       lp->stats.rx_errors++;
+                       if( status & PKT_SHORT)
+                               lp->stats.rx_length_errors++;
+                       if( status & PKT_ALIGN_ERR )
+                               lp->stats.rx_frame_errors++;
+                       if( status & PKT_CRC_ERR )
+                               lp->stats.rx_crc_errors++;
+                       if( status & PKT_RX_BUF_OVERFLOW)
+                               lp->stats.rx_over_errors++;
+               }
+               else
+               {        /* Ok so now we should have a good packet */
+                       struct sk_buff *skb;
+                       /* Get the size of the packet from receive buffer */
+                       ushort pkt_len = inw(ioaddr + DATAPORT);
+
+                       if(pkt_len > ETH_FRAME_LEN) 
+                       {
+                               printk("%s: %s claimed a very large packet, size of %d bytes.\n",
+                               dev->name, cardname, pkt_len);
+                               outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+                               lp->stats.rx_dropped++;
+                               break;
+                       }
+
+                       skb = dev_alloc_skb(pkt_len + 3);
+                       if( skb == NULL ) 
+                       {
+                               printk("%s: Couldn't allocate memory for packet (len %d)\n",
+                               dev->name, pkt_len);
+                               outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+                               lp->stats.rx_dropped++;
+                               break;
+                       }
+                       skb->dev = dev;
+                       skb_reserve(skb,2);
+                       /*
+                               Now let's get the packet out of buffer.
+                               size is (pkt_len + 1) >> 1, cause we are now reading words
+                               and it has to be even aligned.
+                       */
+
+                       if( ioaddr < 0x1000)
+                               insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1);
+                       else 
+                       {
+                               unsigned char *buf = skb_put(skb, pkt_len);
+                               unsigned char frag = pkt_len % 4;
+
+                               insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
+
+                               if(frag != 0) 
+                               {
+                                       unsigned short rest[2];
+                                       rest[0] = inw( ioaddr + DATAPORT );
+                                       if(frag == 3)
+                                               rest[1] = inw( ioaddr + DATAPORT );
+
+                                       memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
+                               }
+                       }
+
+                       skb->protocol=eth_type_trans(skb, dev);
+                       netif_rx(skb);
+                       lp->stats.rx_packets++;
+
+                       if( eth16i_debug > 5 ) 
+                       {
+                               int i;
+                               printk("%s: Received packet of length %d.\n", dev->name, pkt_len);
+                               for(i = 0; i < 14; i++)
+                                       printk(" %02x", skb->data[i]);
+                               printk(".\n");
+                       }
+
+               } /* else */
+
+               if(--boguscount <= 0)
+                       break;
+
+       } /* while */
 
 #if 0
-  {
-    int i;
-
-    for(i = 0; i < 20; i++) {
-      if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY)
-       break;
-      inw(ioaddr + DATAPORT);
-      outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
-    }
-
-    if(eth16i_debug > 1)
-      printk("%s: Flushed receive buffer.\n", dev->name);
-  }
+       {
+               int i;
+
+               for(i = 0; i < 20; i++) 
+               {
+                       if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY)
+                               break;
+                       inw(ioaddr + DATAPORT);
+                       outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+               }
+
+               if(eth16i_debug > 1)
+                       printk("%s: Flushed receive buffer.\n", dev->name);
+       }
 #endif
 
-  return;
+       return;
 }
 
 static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-  struct device *dev = (struct device *)(irq2dev_map[irq]);
-  struct eth16i_local *lp;
-  int ioaddr = 0,
-      status;
-
-  if(dev == NULL) {
-    printk("eth16i_interrupt(): irq %d for unknown device. \n", irq);
-    return;
-  }
-
-  /* Turn off all interrupts from adapter */
-  outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-  dev->interrupt = 1;
-
-  ioaddr = dev->base_addr;
-  lp = (struct eth16i_local *)dev->priv;
-  status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */
-  outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */
-
-  if(eth16i_debug > 3)
-    printk("%s: Interrupt with status %04x.\n", dev->name, status);
-
-  if( status & 0x00ff ) {          /* Let's check the transmit status reg */
-
-    if(status & TX_DONE) {         /* The transmit has been done */
-      lp->stats.tx_packets++;
+       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       struct eth16i_local *lp;
+       int ioaddr = 0,
+                       status;
+
+       if(dev == NULL) {
+               printk("eth16i_interrupt(): irq %d for unknown device. \n", irq);
+               return;
+       }
 
-      if(lp->tx_queue) {           /* Is there still packets ? */
-         /* There was packet(s) so start transmitting and write also
-          how many packets there is to be sent */
-       outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-       lp->tx_queue = 0;
-       lp->tx_queue_len = 0;
-       dev->trans_start = jiffies;
-       dev->tbusy = 0;
-       mark_bh(NET_BH);
-      }
-      else {
-       lp->tx_started = 0;
-       dev->tbusy = 0;
-       mark_bh(NET_BH);
-      }
-    }
-  }
+       /* Turn off all interrupts from adapter */
+       outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+       dev->interrupt = 1;
+
+       ioaddr = dev->base_addr;
+       lp = (struct eth16i_local *)dev->priv;
+       status = inw(ioaddr + TX_STATUS_REG);                   /* Get the status */
+       outw(status, ioaddr + TX_STATUS_REG);                   /* Clear status bits */
+
+       if(eth16i_debug > 3)
+               printk("%s: Interrupt with status %04x.\n", dev->name, status);
+
+       if( status & 0x00ff ) {                 /* Let's check the transmit status reg */
+               if(status & TX_DONE) 
+               {       /* The transmit has been done */
+                       lp->stats.tx_packets++; 
+                       if(lp->tx_queue) 
+                       {       /* Are there still packets ? */
+                               /* There was packet(s) so start transmitting and write also
+                                  how many packets there is to be sent */
+                               outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+                               lp->tx_queue = 0;
+                               lp->tx_queue_len = 0;
+                               dev->trans_start = jiffies;
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);
+                       }
+                       else 
+                       {
+                               lp->tx_started = 0;
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);
+                       }
+               }
+       }
 
-  if( ( status & 0xff00 ) ||
-     ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
-    eth16i_rx(dev);  /* We have packet in receive buffer */
-  }
+       if( ( status & 0xff00 ) ||
+                ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
+               eth16i_rx(dev); /* We have packet in receive buffer */
+       }
 
-  dev->interrupt = 0;
+       dev->interrupt = 0;
 
-  /* Turn interrupts back on */
-  outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+       /* Turn interrupts back on */
+       outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
 
-  return;
+       return;
 }
 
 static void eth16i_multicast(struct device *dev)
 {
-  short ioaddr = dev->base_addr;
-
-  if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-  {
-    dev->flags|=IFF_PROMISC;   /* Must do this */
-    outb(3, ioaddr + RECEIVE_MODE_REG);
-  } else {
-    outb(2, ioaddr + RECEIVE_MODE_REG);
-  }
+       short ioaddr = dev->base_addr;
+
+       if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+       {
+               dev->flags|=IFF_PROMISC;        /* Must do this */
+               outb(3, ioaddr + RECEIVE_MODE_REG);
+       } else {
+               outb(2, ioaddr + RECEIVE_MODE_REG);
+       }
 }
 
-static struct enet_statistics *eth16i_get_stats(struct device *dev)
+static struct net_device_stats *eth16i_get_stats(struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+       struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
 
-  return &lp->stats;
+       return &lp->stats;
 }
 
 static void eth16i_select_regbank(unsigned char banknbr, short ioaddr)
 {
-  unsigned char data;
+       unsigned char data;
 
-  data = inb(ioaddr + CONFIG_REG_1);
-  outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
+       data = inb(ioaddr + CONFIG_REG_1);
+       outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
 }
 
 #ifdef MODULE
@@ -1181,7 +1199,8 @@ static struct device dev_eth16i = {
        devicename,
        0, 0, 0, 0,
        0, 0,
-       0, 0, 0, NULL, eth16i_probe };
+       0, 0, 0, NULL, eth16i_probe
+};
 
 int io = 0x2a0;
 int irq = 0;
index a5d6ec240d5a849c60243899e8d5a1e0f088efae..17b5c9bdf4b2484b4190e9d28f53c4b45f15ad7c 100644 (file)
@@ -257,7 +257,7 @@ struct ewrk3_private {
     char adapter_name[80];              /* Name exported to /proc/ioports */
     u_long shmem_base;                  /* Shared memory start address */
     u_long shmem_length;                /* Shared memory window length */
-    struct enet_statistics stats;       /* Public stats */
+    struct net_device_stats stats;       /* Public stats */
     struct {
       u32 bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */
       u32 unicast;
@@ -291,7 +291,7 @@ static int    ewrk3_open(struct device *dev);
 static int    ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev);
 static void   ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int    ewrk3_close(struct device *dev);
-static struct enet_statistics *ewrk3_get_stats(struct device *dev);
+static struct net_device_stats *ewrk3_get_stats(struct device *dev);
 static void   set_multicast_list(struct device *dev);
 static int    ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 
@@ -1159,21 +1159,18 @@ ewrk3_close(struct device *dev)
   return 0;
 }
 
-static struct enet_statistics *
-ewrk3_get_stats(struct device *dev)
+static struct net_device_stats *ewrk3_get_stats(struct device *dev)
 {
-  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
-
-  /* Null body since there is no framing error counter */
+       struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
 
-  return &lp->stats;
+       /* Null body since there is no framing error counter */
+       return &lp->stats;
 }
 
 /*
 ** Set or clear the multicast filter for this adapter.
 */
-static void
-set_multicast_list(struct device *dev)
+static void set_multicast_list(struct device *dev)
 {
   struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
   u_long iobase = dev->base_addr;
index eec4b45e256fa9dff5b593eeed64b7fc44279f7c..59fd4b9bcdc5c89e54e65fd6b162b144c18a427a 100644 (file)
@@ -70,7 +70,7 @@ typedef unsigned char uchar;
 
 /* Information that need to be kept for each board. */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        long open_time;                         /* Useless example local info. */
        uint tx_started:1;                      /* Number of packet on the Tx queue. */
        uchar tx_queue;                         /* Number of packet on the Tx queue. */
@@ -113,7 +113,7 @@ static int  net_send_packet(struct sk_buff *skb, struct device *dev);
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void net_rx(struct device *dev);
 static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 \f
@@ -578,8 +578,7 @@ static int net_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
 
@@ -596,8 +595,8 @@ net_get_stats(struct device *dev)
    num_addrs > 0       Multicast mode, receive normal and MC packets, and do
                        best-effort filtering.
  */
-static void
-set_multicast_list(struct device *dev)
+static void set_multicast_list(struct device *dev)
 {
        short ioaddr = dev->base_addr;
        if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
index eca6f6f626a01bc4edd80e2b15992fd73951d45b..267095ad95f1fbe240619400c46a3d8ed9bab677 100644 (file)
@@ -518,7 +518,7 @@ static int hdlcdrv_set_mac_address(struct device *dev, void *addr)
 
 /* --------------------------------------------------------------------- */
 
-static struct enet_statistics *hdlcdrv_get_stats(struct device *dev)
+static struct net_device_stats *hdlcdrv_get_stats(struct device *dev)
 {
        struct hdlcdrv_state *sm;
 
index 3392d811762e261ac961b4f6594e191c91ed1a46..d2f4bc7221435a96aa113ec652f0c72ddf9fcacf 100644 (file)
@@ -151,7 +151,7 @@ struct hp100_private {
   int hub_status;                  /* login to hub was successful? */
   u_char mac1_mode;
   u_char mac2_mode;
-  struct enet_statistics stats;
+  struct net_device_stats stats;
 };
 
 /*
@@ -192,7 +192,7 @@ static int hp100_open( struct device *dev );
 static int hp100_close( struct device *dev );
 static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
 static void hp100_rx( struct device *dev );
-static struct enet_statistics *hp100_get_stats( struct device *dev );
+static struct net_device_stats *hp100_get_stats( struct device *dev );
 static void hp100_update_stats( struct device *dev );
 static void hp100_clear_stats( int ioaddr );
 static void hp100_set_multicast_list( struct device *dev);
@@ -636,14 +636,6 @@ static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
       return -EAGAIN;
     }
 
-  if ( skb == NULL )
-    {
-      dev_tint( dev );
-      return 0;
-    }
-
-  if ( skb -> len <= 0 ) return 0;
-
   for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
     {
 #ifdef HP100_DEBUG_TX
@@ -798,7 +790,7 @@ static void hp100_rx( struct device *dev )
  *  statistics
  */
 
-static struct enet_statistics *hp100_get_stats( struct device *dev )
+static struct net_device_stats *hp100_get_stats( struct device *dev )
 {
   int ioaddr = dev -> base_addr;
 
index d1f9eb3bb483d476b811240d17003fde369440b4..daff3ecf6b842b532bffaba59879cf25504b76e7 100644 (file)
 #undef HYDRA_DEBUG        /* define this for (lots of) debugging information */
 
 #if 0                         /* currently hardwired to one transmit buffer */
#define TX_RING_SIZE  5
#define RX_RING_SIZE  16
      #define TX_RING_SIZE    5
      #define RX_RING_SIZE    16
 #else
- #define TX_RING_SIZE 1
- #define RX_RING_SIZE 8
      #define TX_RING_SIZE 1
      #define RX_RING_SIZE 8
 #endif
 
 #define ETHER_MIN_LEN 64
@@ -65,8 +65,8 @@
  * the CIA accesses here are uses to make sure the minimum time
  * requirement between NIC chip selects is met.
  */
-#define WRITE_REG(reg, val) (ciaa.pra, ((u_char)(*(nicbase+(reg))=val)))
-#define READ_REG(reg) (ciaa.pra, ((u_char)(*(nicbase+(reg)))))
+#define WRITE_REG(reg, val) (ciaa.pra, ((u8)(*(nicbase+(reg))=val)))
+#define READ_REG(reg) (ciaa.pra, ((u8)(*(nicbase+(reg)))))
 
 /* mask value for the interrupts we use */
 #define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)
  *   Private Device Data
  */
 struct hydra_private
-    {
-    u_char *hydra_base;
-    u_char *hydra_nic_base;
-    u_short tx_page_start;
-    u_short rx_page_start;
-    u_short rx_page_stop;
-    u_short next_pkt;
-    struct enet_statistics stats;
-    int key;
-    };
+{
+       u8 *hydra_base;
+       u8 *hydra_nic_base;
+       u16 tx_page_start;
+       u16 rx_page_start;
+       u16 rx_page_stop;
+       u16 next_pkt;
+       struct net_device_stats stats;
+       int key;
+};
 
 static int hydra_open(struct device *dev);
 static int hydra_start_xmit(struct sk_buff *skb, struct device *dev);
 static void hydra_interrupt(int irq, void *data, struct pt_regs *fp);
-static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u_char *nicbase);
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u8 *nicbase);
 static int hydra_close(struct device *dev);
-static struct enet_statistics *hydra_get_stats(struct device *dev);
+static struct net_device_stats *hydra_get_stats(struct device *dev);
 #ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 #endif
@@ -106,8 +106,8 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 
 #if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
 
-static __inline__ void *memcpyw(u_short *dest, u_short *src, int len)
-    {
+static __inline__ void *memcpyw(u16 *dest, u16 *src, int len)
+{
     __asm__("   move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t"
            "   cmpi.l #2,%/d0 \n\t"
            "1: bcs.s  2f \n\t"
@@ -133,462 +133,460 @@ static __inline__ void *memcpyw(u_short *dest, u_short *src, int len)
 /* this one here relies on the fact that _writes_ to hydra memory   */
 /* are guaranteed to be of even length. (reads can be arbitrary)    */
 
-static void memcpyw(u_short *dest, u_short *src, int len)
+/*
+ *     FIXME: Surely we should be using the OS generic stuff and do
+ *
+ *     memcpy(dest,src,(len+1)&~1);
+ *
+ *     Can a 68K guy with this card check that ? - better yet
+ *     use a copy/checksum on it.
+ */
+static void memcpyw(u16 *dest, u16 *src, int len)
 {
-  if(len & 1)
-    len++;
+       if(len & 1)
+               len++;
 
-  while (len >= 2) {
-    *(dest++) = *(src++);
-    len -= 2;
-  }
-    
+       while (len >= 2) 
+       {
+               *(dest++) = *(src++);
+               len -= 2;
+       }
 }
 
 #endif
 
 int hydra_probe(struct device *dev)
-    {
-    struct hydra_private *priv;
-    u_long board;
-    int key;
-    struct ConfigDev *cd;
-    int j;
+{
+       struct hydra_private *priv;
+       u32 board;
+       int key;
+       struct ConfigDev *cd;
+       int j;
 
 #ifdef HYDRA_DEBUG
  printk("hydra_probe(%x)\n", dev);
 #endif
 
-    if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) {
-       cd = zorro_get_board(key);
-       if((board = (u_long) cd->cd_BoardAddr))
-           {
-           for(j = 0; j < ETHER_ADDR_LEN; j++)
-                dev->dev_addr[j] = *((u_char *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
+       if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) 
+       {
+               cd = zorro_get_board(key);
+               if((board = (u32) cd->cd_BoardAddr))
+               {
+                       for(j = 0; j < ETHER_ADDR_LEN; j++)
+                               dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
            
-           printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
-                  dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-                  dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-
-           init_etherdev(dev, 0);
+                       printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
+                               dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+                               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+                       init_etherdev(dev, 0);
            
-           dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
-           priv = (struct hydra_private *)dev->priv;
-           memset(priv, 0, sizeof(struct hydra_private));
+                       dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
+                       priv = (struct hydra_private *)dev->priv;
+                       memset(priv, 0, sizeof(struct hydra_private));
            
-           priv->hydra_base = (u_char *) ZTWO_VADDR(board);
-           priv->hydra_nic_base = (u_char *) ZTWO_VADDR(board) + HYDRA_NIC_BASE;
-           priv->key = key;
+                       priv->hydra_base = (u8 *) ZTWO_VADDR(board);
+                       priv->hydra_nic_base = (u8 *) ZTWO_VADDR(board) + HYDRA_NIC_BASE;
+                       priv->key = key;
            
-           dev->open = &hydra_open;
-           dev->stop = &hydra_close;
-           dev->hard_start_xmit = &hydra_start_xmit;
-           dev->get_stats = &hydra_get_stats;
-#ifdef HAVE_MULTICAST
-           dev->set_multicast_list = &hydra_set_multicast_list;
-#endif
-           zorro_config_board(key, 0);
-           return(0);
-            }
-        }
-    return(ENODEV);
-    }
+                       dev->open = &hydra_open;
+                       dev->stop = &hydra_close;
+                       dev->hard_start_xmit = &hydra_start_xmit;
+                       dev->get_stats = &hydra_get_stats;
+                       dev->set_multicast_list = &hydra_set_multicast_list;
+                       
+                       /*
+                        *      Cannot yet do multicast
+                        */
+                       dev->flags&=~IFF_MULTICAST;
+                       zorro_config_board(key, 0);
+                       return(0);
+               }
+       }
+       return(ENODEV);
+}
 
 
 static int hydra_open(struct device *dev)
-  {
-    struct hydra_private *priv = (struct hydra_private *)dev->priv;
-    volatile u_char *nicbase = priv->hydra_nic_base;
-#ifdef HAVE_MULTICAST
-    int i;
-#endif
+{
+       struct hydra_private *priv = (struct hydra_private *)dev->priv;
+       volatile u8 *nicbase = priv->hydra_nic_base;
+       int i;
     
 #ifdef HYDRA_DEBUG
- printk("hydra_open(0x%x)\n", dev);
      printk("hydra_open(0x%x)\n", dev);
 #endif
 
-    /* first, initialize the private structure */
-    priv->tx_page_start = 0;   /* these are 256 byte buffers for NS8390 */
-    priv->rx_page_start = 6;
-    priv->rx_page_stop  = 62;  /* these values are hard coded for now */
+       /* first, initialize the private structure */
+       priv->tx_page_start = 0;   /* these are 256 byte buffers for NS8390 */
+       priv->rx_page_start = 6;
+       priv->rx_page_stop  = 62;  /* these values are hard coded for now */
 
-    /* Reset the NS8390 NIC */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+        /* Reset the NS8390 NIC */
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
 
-    /* be sure that the NIC is in stopped state */
-    while(!(READ_REG(NIC_ISR) & ISR_RST));
+       /* be sure that the NIC is in stopped state */
+       while(!(READ_REG(NIC_ISR) & ISR_RST));
 
-    /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */
-    WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+       /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */
+       WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
 
-    /* clear remote byte count registers */
-    WRITE_REG(NIC_RBCR0, 0);
-    WRITE_REG(NIC_RBCR1, 0);
+       /* clear remote byte count registers */
+       WRITE_REG(NIC_RBCR0, 0);
+       WRITE_REG(NIC_RBCR1, 0);
 
-    /* accept packets addressed to this card and also broadcast packets */
-    WRITE_REG(NIC_RCR, NIC_RCRBITS);
+       /* accept packets addressed to this card and also broadcast packets */
+       WRITE_REG(NIC_RCR, NIC_RCRBITS);
 
-    /* enable loopback mode 1 */
-    WRITE_REG(NIC_TCR, TCR_LB1);
+       /* enable loopback mode 1 */
+       WRITE_REG(NIC_TCR, TCR_LB1);
 
-    /* initialize receive buffer ring */
-    WRITE_REG(NIC_PSTART, priv->rx_page_start);
-    WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
-    WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+       /* initialize receive buffer ring */
+       WRITE_REG(NIC_PSTART, priv->rx_page_start);
+       WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+       WRITE_REG(NIC_BNDRY, priv->rx_page_start);
 
-    /* clear interrupts */
-    WRITE_REG(NIC_ISR, 0xff);
+       /* clear interrupts */
+       WRITE_REG(NIC_ISR, 0xff);
 
-    /* enable interrupts */
-    WRITE_REG(NIC_IMR, NIC_INTS);
+       /* enable interrupts */
+       WRITE_REG(NIC_IMR, NIC_INTS);
 
-    /* set the ethernet hardware address */
-    WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */
+       /* set the ethernet hardware address */
+       WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */
 
-    WRITE_REG(NIC_PAR0, dev->dev_addr[0]);
-    WRITE_REG(NIC_PAR1, dev->dev_addr[1]);
-    WRITE_REG(NIC_PAR2, dev->dev_addr[2]);
-    WRITE_REG(NIC_PAR3, dev->dev_addr[3]);
-    WRITE_REG(NIC_PAR4, dev->dev_addr[4]);
-    WRITE_REG(NIC_PAR5, dev->dev_addr[5]);
+       WRITE_REG(NIC_PAR0, dev->dev_addr[0]);
+       WRITE_REG(NIC_PAR1, dev->dev_addr[1]);
+       WRITE_REG(NIC_PAR2, dev->dev_addr[2]);
+       WRITE_REG(NIC_PAR3, dev->dev_addr[3]);
+       WRITE_REG(NIC_PAR4, dev->dev_addr[4]);
+       WRITE_REG(NIC_PAR5, dev->dev_addr[5]);
 
-#ifdef HAVE_MULTICAST
-    /* clear multicast hash table */
-    for(i = 0; i < 8; i++)
-      WRITE_REG(NIC_MAR0 + 2*i, 0);
-#endif
+       /* clear multicast hash table */
+       for(i = 0; i < 8; i++)
+               WRITE_REG(NIC_MAR0 + 2*i, 0);
 
-    priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
-    WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
+       priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+       WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
 
-    /* goto page 0, start NIC */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+       /* goto page 0, start NIC */
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
 
-    /* take interface out of loopback */
-    WRITE_REG(NIC_TCR, 0);
+       /* take interface out of loopback */
+       WRITE_REG(NIC_TCR, 0);
 
-    dev->tbusy = 0;
-    dev->interrupt = 0;
-    dev->start = 1;
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
     
-    if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, 0, "Hydra Ethernet", dev))
-      return(-EAGAIN);
+       if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, 0, "Hydra Ethernet", dev))
+               return(-EAGAIN);
 
-    MOD_INC_USE_COUNT;
+       MOD_INC_USE_COUNT;
 
-    return(0);
-  }
+       return(0);
+}
 
 
 static int hydra_close(struct device *dev)
 {
-  struct hydra_private *priv = (struct hydra_private *)dev->priv;
-  volatile u_char *nicbase = priv->hydra_nic_base;
-  int n = 5000;
+       struct hydra_private *priv = (struct hydra_private *)dev->priv;
+       volatile u8 *nicbase = priv->hydra_nic_base;
+       int n = 5000;
 
-  dev->start = 0;
-  dev->tbusy = 1;
+       dev->start = 0;
+       dev->tbusy = 1;
 
 #ifdef HYDRA_DEBUG
-  printk("%s: Shutting down ethercard\n", dev->name);
-  printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);
+       printk("%s: Shutting down ethercard\n", dev->name);
+       printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);
 #endif
 
-  WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
 
-  /* wait for NIC to stop (what a nice timeout..) */
-  while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n);
+       /* wait for NIC to stop (what a nice timeout..) */
+       while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n);
     
-  free_irq(IRQ_AMIGA_PORTS, dev);
+       free_irq(IRQ_AMIGA_PORTS, dev);
 
-  MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
 
-  return(0);
+       return(0);
 }
 
 
 static void hydra_interrupt(int irq, void *data, struct pt_regs *fp)
-    {
-    volatile u_char *nicbase;
+{
+       volatile u8 *nicbase;
   
-    struct device *dev = (struct device *) data;
-    struct hydra_private *priv;
-    u_short intbits;
+       struct device *dev = (struct device *) data;
+       struct hydra_private *priv;
+       u16 intbits;
 
-    if(dev == NULL)
-        {
-        printk("hydra_interrupt(): irq for unknown device\n");
-        return;
-        }
+       if(dev == NULL)
+       {
+               printk("hydra_interrupt(): irq for unknown device\n");
+               return;
+       }
 
-/* this is not likely a problem - i think */
-    if(dev->interrupt)
-        printk("%s: re-entering the interrupt handler\n", dev->name);
+       /* this is not likely a problem - i think */
+       if(dev->interrupt)
+               printk("%s: re-entering the interrupt handler\n", dev->name);
 
-    dev->interrupt = 1;
+       dev->interrupt = 1;
 
-    priv = (struct hydra_private *) dev->priv;
-    nicbase = (u_char *) priv->hydra_nic_base;
+       priv = (struct hydra_private *) dev->priv;
+       nicbase = (u8 *) priv->hydra_nic_base;
 
-    /* select page 0 */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+       /* select page 0 */
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
 
-    intbits = READ_REG(NIC_ISR) & NIC_INTS;
-    if(intbits == 0)
+       intbits = READ_REG(NIC_ISR) & NIC_INTS;
+       if(intbits == 0)
         {
-        dev->interrupt = 0;
-        return;
-        }
+               dev->interrupt = 0;
+               return;
+       }
 
        /* acknowledge all interrupts, by clearing the interrupt flag */
        WRITE_REG(NIC_ISR, intbits);
 
        if((intbits & ISR_PTX) && !(intbits & ISR_TXE))
-           {
-           dev->tbusy = 0;
-           mark_bh(NET_BH);
-           }
+       {
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }
        
        if((intbits & ISR_PRX) && !(intbits & ISR_RXE))/* packet received OK */
-             hydra_rx(dev, priv, nicbase);
+               hydra_rx(dev, priv, nicbase);
 
         if(intbits & ISR_TXE)
-           priv->stats.tx_errors++;
+               priv->stats.tx_errors++;
 
         if(intbits & ISR_RXE)
-           priv->stats.rx_errors++;
+               priv->stats.rx_errors++;
 
-       if(intbits & ISR_CNT) {
-         /*
-          * read the tally counters and (currently) ignore the values
-          * might be useful because of bugs of some versions of the 8390 NIC
-          */
+       if(intbits & ISR_CNT) 
+       {
+               /*
+                * read the tally counters and (currently) ignore the values
+                * might be useful because of bugs of some versions of the 8390 NIC
+                */
 #ifdef HYDRA_DEBUG
-         printk("hydra_interrupt(): ISR_CNT\n");
+               printk("hydra_interrupt(): ISR_CNT\n");
 #endif
-         (void)READ_REG(NIC_CNTR0);
-         (void)READ_REG(NIC_CNTR1);
-         (void)READ_REG(NIC_CNTR2);
+               (void)READ_REG(NIC_CNTR0);
+               (void)READ_REG(NIC_CNTR1);
+               (void)READ_REG(NIC_CNTR2);
        }
        
        if(intbits & ISR_OVW)
-           {
-            #ifdef HYDRA_DEBUG
-           WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+       {
+#ifdef HYDRA_DEBUG
+               WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
 /* another one just too much for me to comprehend - basically this could  */
 /* only occur because of invalid access to hydra ram, thus invalidating  */
 /* the interrupt bits read - in average usage these do not occur at all */
-           printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n",
-                intbits, READ_REG(NIC_CURR));
-           WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
-            #endif
+               printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n",
+                       intbits, READ_REG(NIC_CURR));
+               WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+#endif
            
 
-           /* overwrite warning occurred, stop NIC & check the BOUNDARY pointer */
-           /* FIXME - real overwrite handling needed !! */
-
-           printk("hydra_interrupt(): overwrite warning, resetting NIC\n");
-           WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
-           while(!(READ_REG(NIC_ISR) & ISR_RST));
-           /* wait for NIC to reset */
-           WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
-           WRITE_REG(NIC_RBCR0, 0);
-           WRITE_REG(NIC_RBCR1, 0);
-           WRITE_REG(NIC_RCR, NIC_RCRBITS);
-           WRITE_REG(NIC_TCR, TCR_LB1);
-           WRITE_REG(NIC_PSTART, priv->rx_page_start);
-           WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
-           WRITE_REG(NIC_BNDRY, priv->rx_page_start);
-           WRITE_REG(NIC_ISR, 0xff);
-           WRITE_REG(NIC_IMR, NIC_INTS);
-/* currently this _won't_ reset my hydra, even though it is */
-/* basically the same code as in the board init - any ideas? */
-
-           priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
-           WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
+               /* overwrite warning occurred, stop NIC & check the BOUNDARY pointer */
+               /* FIXME - real overwrite handling needed !! */
+
+               printk("hydra_interrupt(): overwrite warning, resetting NIC\n");
+               WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+               while(!(READ_REG(NIC_ISR) & ISR_RST));
+               /* wait for NIC to reset */
+               WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+               WRITE_REG(NIC_RBCR0, 0);
+               WRITE_REG(NIC_RBCR1, 0);
+               WRITE_REG(NIC_RCR, NIC_RCRBITS);
+               WRITE_REG(NIC_TCR, TCR_LB1);
+               WRITE_REG(NIC_PSTART, priv->rx_page_start);
+               WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+               WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+               WRITE_REG(NIC_ISR, 0xff);
+               WRITE_REG(NIC_IMR, NIC_INTS);
+               /* currently this _won't_ reset my hydra, even though it is */
+               /* basically the same code as in the board init - any ideas? */
+
+               priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+               WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
            
-           WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
-           
-           WRITE_REG(NIC_TCR, 0);
-           }
+               WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
 
-    dev->interrupt = 0;
-    return;
+               WRITE_REG(NIC_TCR, 0);
+       }
+
+       dev->interrupt = 0;
+       return;
     }
 
 
 /*
  * packet transmit routine
  */
+
 static int hydra_start_xmit(struct sk_buff *skb, struct device *dev)
-    {
-    struct hydra_private *priv = (struct hydra_private *)dev->priv;
-    volatile u_char *nicbase = priv->hydra_nic_base;
-    int len, len1;
+{
+       struct hydra_private *priv = (struct hydra_private *)dev->priv;
+       volatile u8 *nicbase = priv->hydra_nic_base;
+       int len, len1;
 
        /* Transmitter timeout, serious problems. */
 
-    if(dev->tbusy)
+       if(dev->tbusy)
        {
-        int tickssofar = jiffies - dev->trans_start;
-       if(tickssofar < 20)
-           return(1);
-       WRITE_REG(NIC_CR, CR_STOP);
-       printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0);
-       priv->stats.tx_errors++;
-
-
-       dev->tbusy = 0;
-       dev->trans_start = jiffies;
-
-       return(0);
-       }
-
-
-    if(skb == NULL)
-        {
-       dev_tint(dev);
-       return(0);
+               int tickssofar = jiffies - dev->trans_start;
+               if(tickssofar < 20)
+                       return(1);
+               WRITE_REG(NIC_CR, CR_STOP);
+               printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0);
+               priv->stats.tx_errors++;
+               dev->tbusy = 0;
+               dev->trans_start = jiffies;
+               return(0);
        }
 
-    if((len = skb->len) <= 0)
-       return(0);
+       len=skb->len;
 
-    /* fill in a tx ring entry */
+       /* fill in a tx ring entry */
     
 #ifdef HYDRA_DEBUG
printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
      printk("TX pkt type 0x%04x from ", ((u16 *)skb->data)[6]);
        {
                int i;
-               u_char *ptr = &((u_char *)skb->data)[6];
+               u8 *ptr = &((u8 *)skb->data)[6];
                for (i = 0; i < 6; i++)
                        printk("%02x", ptr[i]);
        }
        printk(" to ");
        {
                int i;
-               u_char *ptr = (u_char *)skb->data;
+               u8 *ptr = (u8 *)skb->data;
                for (i = 0; i < 6; i++)
                        printk("%02x", ptr[i]);
        }
        printk(" data 0x%08x len %d\n", (int)skb->data, len);
 #endif
 
-    /*
-     * make sure that the packet size is at least the minimum
-     * allowed ethernet packet length.
-     * (possibly should also clear the unused space...)
-     * note: minimum packet length is 64, including CRC
-     */
-    len1 = len;
-    if(len < (ETHER_MIN_LEN-4))
-       len = (ETHER_MIN_LEN-1);
-
-    /* make sure we've got an even number of bytes to copy to hydra's mem */
-    if(len & 1) len++;
-
-    if((u_long)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000)
-      printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = 0x%x\n", (u_int)(priv->hydra_base+(priv->tx_page_start<<8)));
-
-    /* copy the packet data to the transmit buffer
-       in the ethernet card RAM */
-    memcpyw((u_short *)(priv->hydra_base + (priv->tx_page_start << 8)),
-           (u_short *)skb->data, len);
-    /* clear the unused space */
-/*    for(; len1<len; len1++)
-      (u_short)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
-*/
-    dev_kfree_skb(skb, FREE_WRITE);
+       /*
+        * make sure that the packet size is at least the minimum
+        * allowed ethernet packet length.
+        * (FIXME: Should also clear the unused space...)
+        * note: minimum packet length is 64, including CRC
+        */
+       len1 = len;
 
-    priv->stats.tx_packets++;
+       if(len < (ETHER_MIN_LEN-4))
+               len = (ETHER_MIN_LEN-1);
 
-    cli();
-    /* make sure we are on the correct page */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+       /* make sure we've got an even number of bytes to copy to hydra's mem */
+       if(len & 1) len++;
 
-    /* here we configure the transmit page start register etc */
-    /* notice that this code is hardwired to one transmit buffer */
-    WRITE_REG(NIC_TPSR, priv->tx_page_start);
-    WRITE_REG(NIC_TBCR0, len & 0xff);
-    WRITE_REG(NIC_TBCR1, len >> 8);
+       if((u32)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000)
+               printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = 0x%x\n", (u_int)(priv->hydra_base+(priv->tx_page_start<<8)));
 
-    /* commit the packet to the wire */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP);
-    sti();
+       /* copy the packet data to the transmit buffer 
+          in the ethernet card RAM */
+       memcpyw((u16 *)(priv->hydra_base + (priv->tx_page_start << 8)),
+               (u16 *)skb->data, len);
+       /* clear the unused space */
+       for(; len1<len; len1++)
+               (u16)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
+       dev_kfree_skb(skb, FREE_WRITE);
 
-    dev->trans_start = jiffies;
+       priv->stats.tx_packets++;
 
-    return(0);
-    }
+       cli();
+       /* make sure we are on the correct page */
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+       /* here we configure the transmit page start register etc */
+       /* notice that this code is hardwired to one transmit buffer */
+       WRITE_REG(NIC_TPSR, priv->tx_page_start);
+       WRITE_REG(NIC_TBCR0, len & 0xff);
+       WRITE_REG(NIC_TBCR1, len >> 8);
+
+       /* commit the packet to the wire */
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP);
+       sti();
 
+        dev->trans_start = jiffies;
 
-static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u_char *nicbase)
-    {
-    volatile u_short *board_ram_ptr;
-    struct sk_buff *skb;
-    int hdr_next_pkt, pkt_len, len1, boundary;
+       return(0);
+}
 
 
-    /* remove packet(s) from the ring and commit them to TCP layer */
-    WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */
-    while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */
-      {
-       board_ram_ptr = (u_short *)(priv->hydra_base + (priv->next_pkt << 8));
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u8 *nicbase)
+{
+       volatile u16 *board_ram_ptr;
+       struct sk_buff *skb;
+       int hdr_next_pkt, pkt_len, len1, boundary;
+
+
+       /* remove packet(s) from the ring and commit them to TCP layer */
+       WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */
+       while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */
+       {
+               board_ram_ptr = (u16 *)(priv->hydra_base + (priv->next_pkt << 8));
        
 #ifdef HYDRA_DEBUG
-       printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr);
+               printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr);
 #endif
        
-       /* the following must be done with two steps, or
-          GCC optimizes it to a byte access to Hydra memory,
-          which doesn't work... */
-       hdr_next_pkt = board_ram_ptr[0];
-       hdr_next_pkt >>= 8;
+               /* the following must be done with two steps, or
+                  GCC optimizes it to a byte access to Hydra memory,
+                  which doesn't work... */
+               hdr_next_pkt = board_ram_ptr[0];
+               hdr_next_pkt >>= 8;
        
-       pkt_len = board_ram_ptr[1];
-       pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8));
+               pkt_len = board_ram_ptr[1];
+               pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8));
        
 #ifdef HYDRA_DEBUG
-       printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len);
+               printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len);
 #endif
        
-       if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN)
-         {
-           /* note that board_ram_ptr is u_short */
-           /* CRC is not included in the packet length */
-           
-           pkt_len -= 4;
-           skb = dev_alloc_skb(pkt_len+2);
-           if(skb == NULL)
-             {
-               printk("%s: memory squeeze, dropping packet.\n", dev->name);
-               priv->stats.rx_dropped++;
-             }
-           else
-             {
-               skb->dev = dev;
-               skb_reserve(skb, 2);
+               if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN)
+               {
+                       /* note that board_ram_ptr is u16 */
+                       /* CRC is not included in the packet length */
                
-               if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start)
-                 {
-                   /* here, the packet is wrapped */
-                   len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4;
-                   
-                   memcpyw((u_short *)skb_put(skb, len1), (u_short *)(board_ram_ptr+2), len1);
-                   memcpyw((u_short *)skb_put(skb, pkt_len-len1),  (u_short *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1);
-                   
+                       pkt_len -= 4;
+                       skb = dev_alloc_skb(pkt_len+2);
+                       if(skb == NULL)
+                       {
+                               printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", dev->name);
+                               priv->stats.rx_dropped++;
+                       }
+                       else
+                       {
+                               skb->dev = dev;
+                               skb_reserve(skb, 2);
+                               if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start)
+                               {
+                                       /* here, the packet is wrapped */
+                                       len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4;
+                       
+                                       memcpyw((u16 *)skb_put(skb, len1), (u16 *)(board_ram_ptr+2), len1);
+                                       memcpyw((u16 *)skb_put(skb, pkt_len-len1),  (u16 *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1);
+                       
 #ifdef HYDRA_DEBUG
-                   printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1);
+                                       printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1);
 #endif
-                 }  /* ... here, packet is not wrapped */
-               else memcpyw((u_short *) skb_put(skb, pkt_len), (u_short *)(board_ram_ptr+2), pkt_len);
-             }
-           /* if(skb == NULL) ... */
-         }
-       else
-         {
-           WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
-           printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR));
+                               }  /* ... here, packet is not wrapped */
+                               else
+                                       memcpyw((u16 *) skb_put(skb, pkt_len), (u16 *)(board_ram_ptr+2), pkt_len);
+                       }
+               }
+               else
+               {
+                       WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+                       printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR));
 /*
 this is the error i kept getting until i switched to 0.9.10. it still doesn't
 mean that the bug would have gone away - so be alarmed. the packet is likely
@@ -596,45 +594,47 @@ being fetched from a wrong memory location - but why - dunno
    
 note-for-v2.1: not really problem anymore. hasn't been for a long time.
 */
-           
-           WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
-           /* should probably reset the NIC here ?? */
-           
-           hydra_open(dev);  /* FIXME - i shouldn't really be doing this. */
-           return;
-         }
+               
+                       WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+                       /* should probably reset the NIC here ?? */
+               
+                       hydra_open(dev);  /* FIXME - i shouldn't really be doing this. */
+                       return;
+               }
        
-       /* now, update the next_pkt pointer */
-       if(hdr_next_pkt < priv->rx_page_stop) priv->next_pkt = hdr_next_pkt;
-       else printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt);
+               /* now, update the next_pkt pointer */
+               if(hdr_next_pkt < priv->rx_page_stop)
+                       priv->next_pkt = hdr_next_pkt;
+               else
+                       printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt);
        
-       /* update the boundary pointer */
-       boundary = priv->next_pkt - 1;
-       if(boundary < priv->rx_page_start)
-         boundary = priv->rx_page_stop - 1;
+               /* update the boundary pointer */
+               boundary = priv->next_pkt - 1;
+               if(boundary < priv->rx_page_start)
+                       boundary = priv->rx_page_stop - 1;
        
-       /* set NIC to page 0 to update the NIC_BNDRY register */
-       WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
-       WRITE_REG(NIC_BNDRY, boundary);
+               /* set NIC to page 0 to update the NIC_BNDRY register */
+               WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+               WRITE_REG(NIC_BNDRY, boundary);
        
-       /* select page1 to access the NIC_CURR register */
-       WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+               /* select page1 to access the NIC_CURR register */
+               WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
        
        
-       skb->protocol = eth_type_trans(skb, dev);
-       netif_rx(skb);
-       priv->stats.rx_packets++;
+               skb->protocol = eth_type_trans(skb, dev);
+               netif_rx(skb);
+               priv->stats.rx_packets++;
        
-      }
-    return;
-    }
+       }
+       return;
+}
     
 
-static struct enet_statistics *hydra_get_stats(struct device *dev)
+static struct net_device_stats *hydra_get_stats(struct device *dev)
 {
        struct hydra_private *priv = (struct hydra_private *)dev->priv;
 #if 0
-       u_char *board = priv->hydra_base; 
+       u8 *board = priv->hydra_base; 
 
        short saved_addr;
 #endif
@@ -643,17 +643,15 @@ static struct enet_statistics *hydra_get_stats(struct device *dev)
        return(&priv->stats);
 }
 
-#ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
-    {
-    struct hydra_private *priv = (struct hydra_private *)dev->priv;
-    u_char *board = priv->hydra_base;
+{
+       struct hydra_private *priv = (struct hydra_private *)dev->priv;
+       u8 *board = priv->hydra_base;
 
-    /* yes, this code is also waiting for someone to complete.. :) */
-    /* (personally i don't care about multicasts at all :) */
-    return;
-    }
-#endif
+       /* yes, this code is also waiting for someone to complete.. :) */
+       /* (personally i don't care about multicasts at all :) */
+       return;
+}
 
 
 #ifdef MODULE
index 97fc35e3ee677420ab10ee95f2bab1f69306643e..24041c8a27bfb1f9537a461325247af12e99c103 100644 (file)
@@ -174,7 +174,7 @@ static              void tr_tx(struct device *dev);
 static int     tok_open(struct device *dev);
 static int     tok_close(struct device *dev);
 static int     tok_send_packet(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics * tok_get_stats(struct device *dev);
+static struct net_device_stats * tok_get_stats(struct device *dev);
 void           tr_readlog(struct device *dev);
 
 /* FIXME: Should use init_timer and friends not assume the structure
@@ -1561,11 +1561,11 @@ void tr_readlog(struct device *dev) {
    this device -- the tr.... structure is an ethnet look-alike
    so at least for this iteration may suffice.   */
 
-static struct enet_statistics * tok_get_stats(struct device *dev) {
+static struct net_device_stats * tok_get_stats(struct device *dev) {
 
        struct tok_info *toki;
        toki=(struct tok_info *) dev->priv;
-       return (struct enet_statistics *) &toki->tr_stats;
+       return (struct net_device_stats *) &toki->tr_stats;
 }
 
 #ifdef MODULE
index 3104e1de966051781fdd81ea574cfde911c42099..caeaa30131f03e24f5d3aa0667fa756a583b3afc 100644 (file)
@@ -234,7 +234,7 @@ struct lance_private {
        int cur_rx, cur_tx;                     /* The next free ring entry */
        int dirty_rx, dirty_tx;         /* The ring entries to be free()ed. */
        int dma;
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        unsigned char chip_version;     /* See lance_chip_type. */
        char tx_full;
        unsigned long lock;
@@ -294,7 +294,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
 static int lance_rx(struct device *dev);
 static void lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int lance_close(struct device *dev);
-static struct enet_statistics *lance_get_stats(struct device *dev);
+static struct net_device_stats *lance_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 \f
@@ -777,8 +777,7 @@ lance_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
        outw(csr0_bits, dev->base_addr + LANCE_DATA);
 }
 
-static int
-lance_start_xmit(struct sk_buff *skb, struct device *dev)
+static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct lance_private *lp = (struct lance_private *)dev->priv;
        int ioaddr = dev->base_addr;
@@ -820,14 +819,6 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
                return 0;
        }
 
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
-       if (skb->len <= 0)
-               return 0;
-
        if (lance_debug > 3) {
                outw(0x0000, ioaddr+LANCE_ADDR);
                printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
@@ -881,7 +872,8 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
                lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
        }
        lp->cur_tx++;
-
+       lp->stats.tx_bytes+=skb->len;
+       
        /* Trigger an immediate send poll. */
        outw(0x0000, ioaddr+LANCE_ADDR);
        outw(0x0048, ioaddr+LANCE_DATA);
@@ -1088,9 +1080,10 @@ lance_rx(struct device *dev)
                                eth_copy_and_sum(skb,
                                        (unsigned char *)bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),
                                        pkt_len,0);
+                               lp->stats.rx_bytes+=skb->len;
                                skb->protocol=eth_type_trans(skb,dev);
-                               netif_rx(skb);
                                lp->stats.rx_packets++;
+                               netif_rx(skb);
                        }
                }
                /* The docs say that the buffer length isn't touched, but Andrew Boyd
@@ -1139,8 +1132,7 @@ lance_close(struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *
-lance_get_stats(struct device *dev)
+static struct net_device_stats *lance_get_stats(struct device *dev)
 {
        struct lance_private *lp = (struct lance_private *)dev->priv;
        short ioaddr = dev->base_addr;
index 82e3ec09fb7a1db75164d928a2c6c499535163db..6d58d9282b10db31043d7d85ba023307fd85ac02 100644 (file)
@@ -132,7 +132,7 @@ struct lance32_private {
        int cur_rx, cur_tx;                     /* The next free ring entry */
        int dirty_rx, dirty_tx;                 /* The ring entries to be free()ed. */
        int dma;
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        char tx_full;
        unsigned long lock;
 };
@@ -143,7 +143,7 @@ static int lance32_start_xmit(struct sk_buff *skb, struct device *dev);
 static int lance32_rx(struct device *dev);
 static void lance32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int lance32_close(struct device *dev);
-static struct enet_statistics *lance32_get_stats(struct device *dev);
+static struct net_device_stats *lance32_get_stats(struct device *dev);
 static void lance32_set_multicast_list(struct device *dev);
 
 \f
@@ -785,8 +785,7 @@ lance32_close(struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *
-lance32_get_stats(struct device *dev)
+static struct net_device_stats *lance32_get_stats(struct device *dev)
 {
        struct lance32_private *lp = (struct lance32_private *)dev->priv;
        int ioaddr = dev->base_addr;
index 40e1c44a5786eb7b0cb7b576de02335cebadf448..f35cf2c460ea2149e89bca350a0e0081126438eb 100644 (file)
@@ -74,7 +74,7 @@ static struct lapbethdev {
        char   ethname[14];             /* ether device name */
        struct device *ethdev;          /* link to ethernet device */
        struct device axdev;            /* lapbeth device (lapb#) */
-       struct enet_statistics stats;   /* some statistics */
+       struct net_device_stats stats;  /* some statistics */
 } *lapbeth_devices = NULL;
 
 
@@ -330,7 +330,7 @@ static void lapbeth_disconnected(void *token, int reason)
 /*
  *     Statistics
  */
-static struct enet_statistics *lapbeth_get_stats(struct device *dev)
+static struct net_device_stats *lapbeth_get_stats(struct device *dev)
 {
        struct lapbethdev *lapbeth;
 
index 0f6c8c0f63aadd35d8a0fde1047a69a38562d911..84232fcfea6ca4fa2aeee87c2f6454031a81aacb 100644 (file)
  */
 static int loopback_xmit(struct sk_buff *skb, struct device *dev)
 {
-       struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
-  
+       struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
+
+       /*
+        *      Take this out if the debug says its ok
+        */
+          
        if (skb == NULL || dev == NULL) 
-               return(0);
+               printk(KERN_DEBUG "loopback fed NULL data - splat\n");
 
        /*
         *      Optimise so buffers with skb->free=1 are not copied but
@@ -96,9 +100,9 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
        return(0);
 }
 
-static struct enet_statistics *get_stats(struct device *dev)
+static struct net_device_stats *get_stats(struct device *dev)
 {
-       return (struct enet_statistics *)dev->priv;
+       return (struct net_device_stats *)dev->priv;
 }
 
 static int loopback_open(struct device *dev)
@@ -130,10 +134,10 @@ int loopback_init(struct device *dev)
        dev->pa_mask            = in_aton("255.0.0.0");
        dev->pa_alen            = 4;
 #endif  
-       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+       dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
        if (dev->priv == NULL)
                        return -ENOMEM;
-       memset(dev->priv, 0, sizeof(struct enet_statistics));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
        dev->get_stats = get_stats;
 
        /*
diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c
new file mode 100644 (file)
index 0000000..a0854f6
--- /dev/null
@@ -0,0 +1,1281 @@
+/***    ltpc.c -- a driver for the LocalTalk PC card.
+ *
+ *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *      This is ALPHA code at best.  It may not work for you.  It may
+ *      damage your equipment.  It may damage your relations with other
+ *      users of your network.  Use it at your own risk!
+ *
+ *      Based in part on:
+ *      skeleton.c      by Donald Becker
+ *      dummy.c         by Nick Holloway and Alan Cox
+ *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
+ *      the netatalk source code (UMICH)
+ *      lots of work on the card...
+ *
+ *      I do not have access to the (proprietary) SDK that goes with the card.
+ *      If you do, I don't want to know about it, and you can probably write
+ *      a better driver yourself anyway.  This does mean that the pieces that
+ *      talk to the card are guesswork on my part, so use at your own risk!
+ *
+ *      This is my first try at writing Linux networking code, and is also
+ *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
+ *      welcome suggestions)
+ *
+ *      This is a loadable kernel module which seems to work at my site
+ *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
+ *      the kernel support from 1.3.3b2 including patches routing.patch
+ *      and ddp.disappears.from.chooser.  In order to run it, you will need
+ *      to patch ddp.c and aarp.c in the kernel, but only a little...
+ *
+ *      I'm fairly confident that while this is arguably badly written, the
+ *      problems that people experience will be "higher level", that is, with
+ *      complications in the netatalk code.  The driver itself doesn't do
+ *      anything terribly complicated -- it pretends to be an ether device
+ *      as far as netatalk is concerned, strips the DDP data out of the ether
+ *      frame and builds a LLAP packet to send out the card.  In the other
+ *      direction, it receives LLAP frames from the card and builds a fake
+ *      ether packet that it then tosses up to the networking code.  You can
+ *      argue (correctly) that this is an ugly way to do things, but it
+ *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
+ *
+ *      The card will do a lot more than is used here -- I *think* it has the
+ *      layers up through ATP.  Even if you knew how that part works (which I
+ *      don't) it would be a big job to carve up the kernel ddp code to insert
+ *      things at a higher level, and probably a bad idea...
+ *
+ *      There are a number of other cards that do LocalTalk on the PC.  If
+ *      nobody finds any insurmountable (at the netatalk level) problems
+ *      here, this driver should encourage people to put some work into the
+ *      other cards (some of which I gather are still commercially available)
+ *      and also to put hooks for LocalTalk into the official ddp code.
+ *
+ *      I welcome comments and suggestions.  This is my first try at Linux
+ *      networking stuff, and there are probably lots of things that I did
+ *      suboptimally.  
+ *
+ ***/
+
+/***
+ *
+ * $Log: ltpc.c,v $
+ * Revision 1.8  1997/01/28 05:44:54  bradford
+ * Clean up for non-module a little.
+ * Hacked about a bit to clean things up - Alan Cox 
+ * Probably broken it from the origina 1.8
+ *
+ * Revision 1.7  1996/12/12 03:42:33  bradford
+ * DMA alloc cribbed from 3c505.c.
+ *
+ * Revision 1.6  1996/12/12 03:18:58  bradford
+ * Added virt_to_bus; works in 2.1.13.
+ *
+ * Revision 1.5  1996/12/12 03:13:22  root
+ * xmitQel initialization -- think through better though.
+ *
+ * Revision 1.4  1996/06/18 14:55:55  root
+ * Change names to ltpc. Tabs. Took a shot at dma alloc,
+ * although more needs to be done eventually.
+ *
+ * Revision 1.3  1996/05/22 14:59:39  root
+ * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
+ *
+ * Revision 1.2  1996/05/22 14:58:24  root
+ * Change tabs mostly.
+ *
+ * Revision 1.1  1996/04/23 04:45:09  root
+ * Initial revision
+ *
+ * Revision 0.16  1996/03/05 15:59:56  root
+ * Change ARPHRD_LOCALTLK definition to the "real" one.
+ *
+ * Revision 0.15  1996/03/05 06:28:30  root
+ * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
+ * it's getting closer.
+ *
+ * Revision 0.14  1996/02/25 17:38:32  root
+ * More cleanups.  Removed query to card on get_stats.
+ *
+ * Revision 0.13  1996/02/21  16:27:40  root
+ * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
+ * Clean up receive code a little.
+ *
+ * Revision 0.12  1996/02/19  16:34:53  root
+ * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
+ * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
+ * including packet printing, 4 for lower level (card i/o) stuff.
+ *
+ * Revision 0.11  1996/02/12  15:53:38  root
+ * Added router sends (requires new aarp.c patch)
+ *
+ * Revision 0.10  1996/02/11  00:19:35  root
+ * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
+ *
+ * Revision 0.9  1996/02/10  23:59:35  root
+ * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
+ * has a *different* definition of struct sockaddr_at than the Linux kernel
+ * does.  This is an "insidious and invidious" bug...
+ * (Actually the preceding comment is false -- it's the atalk.h in the
+ * ancient atalk-0.06 that's the problem)
+ *
+ * Revision 0.8  1996/02/10 19:09:00  root
+ * Merge 1.3 changes.  Tested OK under 1.3.60.
+ *
+ * Revision 0.7  1996/02/10 17:56:56  root
+ * Added debug=1 parameter on insmod for debugging prints.  Tried
+ * to fix timer unload on rmmod, but I don't think that's the problem.
+ *
+ * Revision 0.6  1995/12/31  19:01:09  root
+ * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
+ * Clean up initial probing -- sometimes the card wakes up latched in reset.
+ *
+ * Revision 0.5  1995/12/22  06:03:44  root
+ * Added comments in front and cleaned up a bit.
+ * This version sent out to people.
+ *
+ * Revision 0.4  1995/12/18  03:46:44  root
+ * Return shortDDP to longDDP fake to 0/0.  Added command structs.
+ *
+ ***/
+
+/* ltpc jumpers are:
+*
+*      Interrupts -- set at most one.  If none are set, the driver uses
+*      polled mode.  Because the card was developed in the XT era, the
+*      original documentation refers to IRQ2.  Since you'll be running
+*      this on an AT (or later) class machine, that really means IRQ9.
+*
+*      SW1     IRQ 4
+*      SW2     IRQ 3
+*      SW3     IRQ 9 (2 in original card documentation only applies to XT)
+*
+*
+*      DMA -- choose DMA 1 or 3, and set both corresponding switches.
+*
+*      SW4     DMA 3
+*      SW5     DMA 1
+*      SW6     DMA 3
+*      SW7     DMA 1
+*
+*
+*      I/O address -- choose one.  
+*
+*      SW8     220 / 240
+*/
+
+/*     To have some stuff logged, do 
+*      insmod ltpc.o debug=1
+*
+*      For a whole bunch of stuff, use higher numbers.
+*
+*      The default is 0, i.e. no messages except for the probe results.
+*/
+
+/* insmod-tweakable variables */
+static int debug=0;
+#define DEBUG_VERBOSE 1
+#define DEBUG_UPPER 2
+#define DEBUG_LOWER 4
+
+#include <linux/config.h> /* for CONFIG_MAX_16M */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include <linux/atalk.h>
+
+/* our stuff */
+#include "ltpc.h"
+
+/* function prototypes */
+static int do_read(struct device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen);
+static int sendup_buffer (struct device *dev);
+
+/* Dma Memory related stuff, cribbed directly from 3c505.c */
+
+/* Pure 2^n version of get_order */
+static inline int __get_order(unsigned long size)
+{
+        int order;
+
+        size = (size - 1) >> (PAGE_SHIFT - 1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
+static unsigned long dma_mem_alloc(int size)
+{
+        int order = __get_order(size);
+
+        return __get_dma_pages(GFP_KERNEL, order);
+}
+
+static unsigned char *ltdmabuf;
+static unsigned char *ltdmacbuf;
+
+struct xmitQel {
+       struct xmitQel *next;
+       unsigned char *cbuf;
+       short cbuflen;
+       unsigned char *dbuf;
+       short dbuflen;
+       unsigned char QWrite;   /* read or write data */
+       unsigned char mailbox;
+};
+
+static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
+
+static void enQ(struct xmitQel *qel)
+{
+       unsigned long flags;
+       qel->next = NULL;
+       save_flags(flags);
+       cli();
+       if (xmQtl) {
+               xmQtl->next = qel;
+       } else {
+               xmQhd = qel;
+       }
+       xmQtl = qel;
+       restore_flags(flags);
+
+       if (debug&DEBUG_LOWER)
+               printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
+}
+
+static struct xmitQel *deQ(void)
+{
+       unsigned long flags;
+       int i;
+       struct xmitQel *qel=NULL;
+       save_flags(flags);
+       cli();
+       if (xmQhd) {
+               qel = xmQhd;
+               xmQhd = qel->next;
+               if(!xmQhd) xmQtl = NULL;
+       }
+       restore_flags(flags);
+
+       if ((debug&DEBUG_LOWER) && qel) {
+               int n;
+               printk("ltpc: dequeued command ");
+               n = qel->cbuflen;
+               if (n>100) n=100;
+               for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
+               printk("\n");
+       }
+
+       return qel;
+}
+
+static struct xmitQel qels[16];
+
+static unsigned char mailbox[16];
+static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static int wait_timeout(struct device *dev, int c)
+{
+       /* returns true if it stayed c */
+       /* this uses base+6, but it's ok */
+       int i;
+       int timeout;
+
+       /* ten second or so total */
+
+       for(i=0;i<10000;i++) {
+               if ( c != inb_p(dev->base_addr+6) ) return 0;
+               for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
+       }
+       return 1; /* timed out */
+}
+
+static int getmbox(void)
+{
+       unsigned long flags;
+       int i;
+
+       save_flags(flags);
+       cli();
+       for(i=1;i<16;i++) if(!mboxinuse[i]) {
+               mboxinuse[i]=1;
+               restore_flags(flags);
+               return i;
+       }
+       restore_flags(flags);
+       return 0;
+}
+
+static void handlefc(struct device *dev)
+{
+       /* called *only* from idle, non-reentrant */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+       set_dma_count(dma,50);
+       enable_dma(dma);
+
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
+}
+
+static void handlefd(struct device *dev)
+{
+       int dma = dev->dma;
+       int base = dev->base_addr;
+
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,800);
+       enable_dma(dma);
+
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
+       sendup_buffer(dev);
+} 
+
+static void handlewrite(struct device *dev)
+{
+       /* called *only* from idle, non-reentrant */
+       /* on entry, 0xfb and ltdmabuf holds data */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+
+
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_WRITE);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,800);
+       enable_dma(dma);
+
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfb) ) {
+               printk("timed out in handlewrite, dma res %d\n",
+                       get_dma_residue(dev->dma) );
+       }
+}
+
+static void handleread(struct device *dev)
+{
+       /* on entry, 0xfb */
+       /* on exit, ltdmabuf holds data */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+
+
+
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,800);
+       enable_dma(dma);
+
+       inb_p(base+3);
+       inb_p(base+2);
+       if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
+}
+
+static void handlecommand(struct device *dev)
+{
+       /* on entry, 0xfa and ltdmacbuf holds command */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_WRITE);
+       set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+       set_dma_count(dma,50);
+       enable_dma(dma);
+
+       inb_p(base+3);
+       inb_p(base+2);
+       if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
+} 
+
+static unsigned char rescbuf[2] = {0,0};
+static unsigned char resdbuf[2];
+
+static int QInIdle=0;
+
+/* idle expects to be called with the IRQ line high -- either because of
+ * an interrupt, or because the line is tri-stated
+ */
+
+static void idle(struct device *dev)
+{
+       unsigned long flags;
+       int state;
+       /* FIXME This is initialized to shut the warning up, but I need to
+        * think this through again.
+        */
+       struct xmitQel *q=0;
+       int oops;
+       int i;
+       int statusPort = dev->base_addr+6;
+
+       save_flags(flags);
+       cli();
+       if(QInIdle) {
+               restore_flags(flags);
+               return;
+       }
+       QInIdle = 1;
+
+
+       restore_flags(flags);
+
+
+       (void) inb_p(statusPort); /* this tri-states the IRQ line */
+
+       oops = 100;
+
+loop:
+       if (0>oops--) { 
+               printk("idle: looped too many times\n");
+               goto done;
+       }
+
+       state = inb_p(statusPort);
+       if (state != inb_p(statusPort)) goto loop;
+
+       switch(state) {
+               case 0xfc: 
+                       if (debug&DEBUG_LOWER) printk("idle: fc\n");
+                       handlefc(dev); 
+                       break;
+               case 0xfd: 
+                       if(debug&DEBUG_LOWER) printk("idle: fd\n");
+                       handlefd(dev); 
+                       break;
+               case 0xf9: 
+                       if (debug&DEBUG_LOWER) printk("idle: f9\n");
+                       if(!mboxinuse[0]) {
+                               mboxinuse[0] = 1;
+                               qels[0].cbuf = rescbuf;
+                               qels[0].cbuflen = 2;
+                               qels[0].dbuf = resdbuf;
+                               qels[0].dbuflen = 2;
+                               qels[0].QWrite = 0;
+                               qels[0].mailbox = 0;
+                               enQ(&qels[0]);
+                       }
+                       inb_p(dev->base_addr+1);
+                       inb_p(dev->base_addr+0);
+                       if( wait_timeout(dev,0xf9) )
+                               printk("timed out idle f9\n");
+                       break;
+               case 0xf8:
+                       if (xmQhd) {
+                               inb_p(dev->base_addr+1);
+                               inb_p(dev->base_addr+0);
+                               if(wait_timeout(dev,0xf8) )
+                                       printk("timed out idle f8\n");
+                       } else {
+                               goto done;
+                       }
+                       break;
+               case 0xfa: 
+                       if(debug&DEBUG_LOWER) printk("idle: fa\n");
+                       if (xmQhd) {
+                               q=deQ();
+                               memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
+                               ltdmacbuf[1] = q->mailbox;
+                               if (debug>1) { 
+                                       int n;
+                                       printk("ltpc: sent command     ");
+                                       n = q->cbuflen;
+                                       if (n>100) n=100;
+                                       for(i=0;i<n;i++)
+                                               printk("%02x ",ltdmacbuf[i]);
+                                       printk("\n");
+                               }
+                               handlecommand(dev);
+                                       if(0xfa==inb_p(statusPort)) {
+                                               /* we timed out, so return */
+                                               goto done;
+                                       } 
+                       } else {
+                               /* we don't seem to have a command */
+                               if (!mboxinuse[0]) {
+                                       mboxinuse[0] = 1;
+                                       qels[0].cbuf = rescbuf;
+                                       qels[0].cbuflen = 2;
+                                       qels[0].dbuf = resdbuf;
+                                       qels[0].dbuflen = 2;
+                                       qels[0].QWrite = 0;
+                                       qels[0].mailbox = 0;
+                                       enQ(&qels[0]);
+                               } else {
+                                       printk("trouble: response command already queued\n");
+                                       goto done;
+                               }
+                       } 
+                       break;
+               case 0xfb:
+                       if(debug&DEBUG_LOWER) printk("idle: fb\n");
+                       if(q->QWrite) {
+                               memcpy(ltdmabuf,q->dbuf,q->dbuflen);
+                               handlewrite(dev);
+                       } else {
+                               handleread(dev);
+                               if(q->mailbox) {
+                                       memcpy(q->dbuf,ltdmabuf,q->dbuflen);
+                               } else { 
+                                       /* this was a result */
+                                       mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
+                                       mboxinuse[0]=0;
+                               }
+                       }
+                       break;
+       }
+       goto loop;
+
+done:
+       QInIdle=0;
+
+       /* now set the interrupts back as appropriate */
+       /* the first 7 takes it out of tri-state (but still high) */
+       /* the second resets it */
+       /* note that after this point, any read of 6 will trigger an interrupt */
+
+       if (dev->irq) {
+               inb_p(dev->base_addr+7);
+               inb_p(dev->base_addr+7);
+       }
+       return;
+}
+
+
+static int do_write(struct device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen)
+{
+
+       int i = getmbox();
+       int ret;
+
+       if(i) {
+               qels[i].cbuf = (unsigned char *) cbuf;
+               qels[i].cbuflen = cbuflen;
+               qels[i].dbuf = (unsigned char *) dbuf;
+               qels[i].dbuflen = dbuflen;
+               qels[i].QWrite = 1;
+               qels[i].mailbox = i;  /* this should be initted rather */
+               enQ(&qels[i]);
+               idle(dev);
+               ret = mailbox[i];
+               mboxinuse[i]=0;
+               return ret;
+       }
+       printk("ltpc: could not allocate mbox\n");
+       return -1;
+}
+
+static int do_read(struct device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen)
+{
+
+       int i = getmbox();
+       int ret;
+
+       if(i) {
+               qels[i].cbuf = (unsigned char *) cbuf;
+               qels[i].cbuflen = cbuflen;
+               qels[i].dbuf = (unsigned char *) dbuf;
+               qels[i].dbuflen = dbuflen;
+               qels[i].QWrite = 0;
+               qels[i].mailbox = i;  /* this should be initted rather */
+               enQ(&qels[i]);
+               idle(dev);
+               ret = mailbox[i];
+               mboxinuse[i]=0;
+               return ret;
+       }
+       printk("ltpc: could not allocate mbox\n");
+       return -1;
+}
+
+/* end of idle handlers -- what should be seen is do_read, do_write */
+
+static struct timer_list ltpc_timer;
+
+static int ltpc_xmit(struct sk_buff *skb, struct device *dev);
+static struct enet_statistics *ltpc_get_stats(struct device *dev);
+
+static int ltpc_open(struct device *dev)
+{
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+       return 0;
+}
+
+static int ltpc_close(struct device *dev)
+{
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+       return 0;
+}
+
+static int read_30 ( struct device *dev)
+{
+       lt_command c;
+       c.getflags.command = LT_GETFLAGS;
+       return do_read(dev, &c, sizeof(c.getflags),&c,0);
+}
+
+static int set_30 (struct device *dev,int x)
+{
+       lt_command c;
+       c.setflags.command = LT_SETFLAGS;
+       c.setflags.flags = x;
+       return do_write(dev, &c, sizeof(c.setflags),&c,0);
+}
+
+static int sendup_buffer (struct device *dev)
+{
+       /* on entry, command is in ltdmacbuf, data in ltdmabuf */
+       /* called from idle, non-reentrant */
+
+       int dnode, snode, llaptype, len; 
+       int sklen;
+       struct sk_buff *skb;
+       struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+       struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
+
+       if (ltc->command != LT_RCVLAP) {
+               printk("unknown command 0x%02x from ltpc card\n",ltc->command);
+               return(-1);
+       }
+       dnode = ltc->dnode;
+       snode = ltc->snode;
+       llaptype = ltc->laptype;
+       len = ltc->length; 
+
+       sklen = len;
+       if (llaptype == 1) 
+               sklen += 8;  /* correct for short ddp */
+       if(sklen > 800) {
+               printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
+                       dev->name,sklen);
+               return -1;
+       }
+
+       if ( (llaptype==0) || (llaptype>2) ) {
+               printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
+               return -1;
+       }
+
+
+       skb = dev_alloc_skb(3+sklen);
+       if (skb == NULL) 
+       {
+               printk("%s: dropping packet due to memory squeeze.\n",
+                       dev->name);
+               return -1;
+       }
+       skb->dev = dev;
+
+       if (sklen > len)
+               skb_reserve(skb,8);
+       skb_put(skb,len+3);
+       skb->protocol = htons(ETH_P_LOCALTALK);
+       /* add LLAP header */
+       skb->data[0] = dnode;
+       skb->data[1] = snode;
+       skb->data[2] = llaptype;
+       skb->mac.raw = skb->data;       /* save pointer to llap header */
+       skb_pull(skb,3);
+
+       /* copy ddp(s,e)hdr + contents */
+       memcpy(skb->data,(void*)ltdmabuf,len);
+
+       skb->h.raw = skb->data;
+
+       /* toss it onwards */
+       netif_rx(skb);
+       stats->rx_packets++;
+       return 0;
+}
+
+/* the handler for the board interrupt */
+static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+{
+       struct device *dev = (struct device *) irq2dev_map[irq];
+
+       if (dev==NULL) {
+               printk("ltpc_interrupt: unknown device.\n");
+               return;
+       }
+
+       inb_p(dev->base_addr+6);  /* disable further interrupts from board */
+
+       idle(dev); /* handle whatever is coming in */
+       /* idle re-enables interrupts from board */ 
+
+       return;
+}
+
+/***
+ *
+ *    The ioctls that the driver responds to are:
+ *
+ *    SIOCSIFADDR -- do probe using the passed node hint.
+ *    SIOCGIFADDR -- return net, node.
+ *
+ *    some of this stuff should be done elsewhere.
+ *
+ ***/
+
+static int ltpc_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+       struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
+       /* we'll keep the localtalk node address in dev->pa_addr */
+       struct at_addr *aa = (struct at_addr *) &dev->pa_addr;
+       struct lt_init c;
+       int ltflags;
+
+       if(debug&DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
+
+       switch(cmd) {
+               case SIOCSIFADDR:
+
+                       aa->s_net  = sa->sat_addr.s_net;
+      
+                       /* this does the probe and returns the node addr */
+                       c.command = LT_INIT;
+                       c.hint = sa->sat_addr.s_node;
+
+                       aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
+
+                       /* get all llap frames raw */
+                       ltflags = read_30(dev);
+                       ltflags |= LT_FLAG_ALLLAP;
+                       set_30 (dev,ltflags);  
+
+                       dev->broadcast[0] = 0xFF;
+                       dev->dev_addr[0] = aa->s_node;
+
+                       dev->addr_len=1;
+   
+                       return 0;
+
+               case SIOCGIFADDR:
+
+                       sa->sat_addr.s_net = aa->s_net;
+                       sa->sat_addr.s_node = aa->s_node;
+
+                       return 0;
+
+               default: 
+                       return -EINVAL;
+       }
+}
+
+static void set_multicast_list(struct device *dev)
+{
+       /* This needs to be present to keep netatalk happy. */
+       /* Actually netatalk needs fixing! */
+}
+
+static int ltpc_init(struct device *dev)
+{
+       /* Initialize the device structure. */
+  
+       /* Fill in the fields of the device structure with ethernet-generic values. */
+       ltalk_setup(dev);
+       dev->hard_start_xmit = ltpc_xmit;
+
+       dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+       if(!dev->priv)
+       {
+               printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name);
+               return -ENOMEM;
+       }
+
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
+       dev->get_stats = ltpc_get_stats;
+
+       dev->open = ltpc_open;
+       dev->stop = ltpc_close;
+
+       /* add the ltpc-specific things */
+       dev->do_ioctl = &ltpc_ioctl;
+
+       dev->set_multicast_list = &set_multicast_list;
+       return 0;
+}
+
+static int ltpc_poll_counter = 0;
+
+static void ltpc_poll(unsigned long l)
+{
+       struct device *dev = (struct device *) l;
+
+       del_timer(&ltpc_timer);
+
+       if(debug&DEBUG_VERBOSE) {
+               if (!ltpc_poll_counter) {
+                       ltpc_poll_counter = 50;
+                       printk("ltpc poll is alive\n");
+               }
+               ltpc_poll_counter--;
+       }
+  
+       if (!dev) return;  /* we've been downed */
+
+       if (dev->irq) {
+               /* we're set up for interrupts */
+               if (0xf8 != inb_p(dev->base_addr+7)) {
+                       /* trigger an interrupt */
+                       (void) inb_p(dev->base_addr+6);
+               }
+               ltpc_timer.expires = 100;
+       } else {
+               /* we're strictly polling mode */
+               idle(dev);
+               ltpc_timer.expires = 5;
+       }
+
+       ltpc_timer.expires += jiffies;  /* 1.2 to 1.3 change... */
+
+       add_timer(&ltpc_timer);
+}
+
+static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
+{
+       /* in kernel 1.3.xx, on entry skb->data points to ddp header,
+        * and skb->len is the length of the ddp data + ddp header
+        */
+
+       struct net_device_stats *stats = (struct enet_statistics *)dev->priv;
+
+       int i;
+       struct lt_sendlap cbuf;
+
+       cbuf.command = LT_SENDLAP;
+       cbuf.dnode = skb->data[0];
+       cbuf.laptype = skb->data[2];
+       skb_pull(skb,3);        /* skip past LLAP header */
+       cbuf.length = skb->len; /* this is host order */
+       skb->h.raw=skb->data;
+
+       if(debug&DEBUG_UPPER) {
+               printk("command ");
+               for(i=0;i<6;i++)
+                       printk("%02x ",((unsigned char *)&cbuf)[i]);
+               printk("\n");
+       }
+
+       do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
+
+       if(debug&DEBUG_UPPER) {
+               printk("sent %d ddp bytes\n",skb->len);
+               for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
+               printk("\n");
+       }
+
+       dev_kfree_skb(skb, FREE_WRITE);
+
+       stats->tx_packets++;
+
+       return 0;
+}
+
+static struct net_device_stats *ltpc_get_stats(struct device *dev)
+{
+       struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
+       return stats;
+}
+
+static unsigned short irqhitmask;
+
+static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr)
+{
+       irqhitmask |= 1<<irq;
+}
+
+int ltpc_probe(struct device *dev)
+{
+       int err;
+       unsigned char dma=0;
+       short base=0;
+       unsigned char irq=0;
+       int x=0,y=0;
+       int timeout;
+       int probe3, probe4, probe9;
+       unsigned short straymask;
+       unsigned long flags;
+
+       err = ltpc_init(dev);
+       if (err) return err;
+
+       /* occasionally the card comes up with reset latched, so we need
+        * to "reset the reset" first of all -- check the irq first also
+        */
+
+       save_flags(flags);
+       cli();
+
+       probe3 = request_irq( 3, &lt_probe_handler, 0, "ltpc_probe",NULL);
+       probe4 = request_irq( 4, &lt_probe_handler, 0, "ltpc_probe",NULL);
+       probe9 = request_irq( 9, &lt_probe_handler, 0, "ltpc_probe",NULL);
+
+       irqhitmask = 0;
+
+       sti();
+
+       timeout = jiffies+2;
+       while(timeout>jiffies) ;  /* wait for strays */
+
+       straymask = irqhitmask;  /* pick up any strays */
+       /* if someone already owns this address, don't probe */ 
+       if (!check_region(0x220,8)) {
+               inb_p(0x227);
+               inb_p(0x227);
+               x=inb_p(0x226);
+               timeout = jiffies+2;
+               while(timeout>jiffies) ;
+               if(straymask != irqhitmask) base = 0x220;
+       }
+       if (!check_region(0x240,8)) {
+               inb_p(0x247);
+               inb_p(0x247);
+               y=inb_p(0x246);
+               timeout = jiffies+2;
+               while(timeout>jiffies) ;
+               if(straymask != irqhitmask) base = 0x240;
+       }
+
+       /* at this point, either we have an irq and the base addr, or
+        * there isn't any irq and we don't know the base address, but
+        * in either event the card is no longer latched in reset and
+        * the irq request line is tri-stated.
+        */
+
+       cli();
+       if (!probe3) free_irq(3,NULL);
+       if (!probe4) free_irq(4,NULL);
+       if (!probe9) free_irq(9,NULL);
+
+       sti();
+       irqhitmask &= ~straymask;
+
+       irq = ffz(~irqhitmask);
+       if (irqhitmask != 1<<irq)
+               printk("ltpc card raised more than one interrupt!\n");
+
+       if (!base) {
+               if (!check_region(0x220,8)) {
+                       x = inb_p(0x220+6);
+                       if ( (x!=0xff) && (x>=0xf0) ) base = 0x220;
+               }
+               if (!check_region(0x240,8)) {
+                       y = inb_p(0x240+6);
+                       if ( (y!=0xff) && (y>=0xf0) ) base = 0x240;
+               } 
+       }
+
+       if(base) {
+               request_region(base,8,"ltpc");
+       } else {
+               printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y);
+               restore_flags(flags);
+               return -1;
+       }
+
+       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+       if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
+
+       if (!ltdmabuf) {
+               printk("ltpc: mem alloc failed\n");
+               restore_flags(flags);
+               return(-1);
+       }
+
+       if(debug&DEBUG_VERBOSE) {
+               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+       }
+
+       /* reset the card */
+
+       inb_p(base+1);
+       inb_p(base+3);
+       timeout = jiffies+2;
+       while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
+       inb_p(base+0);
+       inb_p(base+2);
+       inb_p(base+7); /* clear reset */
+       inb_p(base+4); 
+       inb_p(base+5);
+       inb_p(base+5); /* enable dma */
+       inb_p(base+6); /* tri-state interrupt line */
+
+       timeout = jiffies+100;
+       while(timeout>jiffies) {
+               /* wait for the card to complete initialization */
+       }
+       /* now, figure out which dma channel we're using */
+
+       /* set up both dma 1 and 3 for read call */
+
+       if (!request_dma(1,"ltpc")) {
+               disable_dma(1);
+               clear_dma_ff(1);
+               set_dma_mode(1,DMA_MODE_WRITE);
+               set_dma_addr(1,virt_to_bus(ltdmabuf));
+               set_dma_count(1,sizeof(struct lt_mem));
+               enable_dma(1);
+               dma|=1;
+       }
+       if (!request_dma(3,"ltpc")) {
+               disable_dma(3);
+               clear_dma_ff(3);
+               set_dma_mode(3,DMA_MODE_WRITE);
+               set_dma_addr(3,virt_to_bus(ltdmabuf));
+               set_dma_count(3,sizeof(struct lt_mem));
+               enable_dma(3);
+               dma|=2;
+       }
+
+       /* set up request */
+
+       /* FIXME -- do timings better! */
+
+       ltdmabuf[0] = 2; /* read request */
+       ltdmabuf[1] = 1;  /* mailbox */
+       ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
+       ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
+       ltdmabuf[6] = 0; /* dunno if this is necessary */
+
+       inb_p(base+1);
+       inb_p(base+0);
+       timeout = jiffies+100;
+       while(timeout>jiffies) {
+               if ( 0xfa == inb_p(base+6) ) break;
+       }
+
+       inb_p(base+3);
+       inb_p(base+2);
+       while(timeout>jiffies) {
+               if ( 0xfb == inb_p(base+6) ) break;
+       }
+
+       /* release the other dma channel */
+
+       if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
+               dma&=1;
+               free_dma(3);
+       }
+  
+       if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){
+               dma&=0x2;
+               free_dma(1);
+       }
+       if (!dma) {  /* no dma channel */
+               printk("No DMA channel found on ltpc card.\n");
+               restore_flags(flags);
+               return -1;
+       } 
+  
+       /* fix up dma number */
+       dma|=1;
+
+       /* set up read */
+
+       if(irq)
+               printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma);
+       else
+               printk("LocalTalk card found at %03x, DMA%d.  Using polled mode.\n",base,dma);
+    
+       dev->base_addr = base;
+       dev->irq = irq;
+       dev->dma = dma;
+
+       if(debug&DEBUG_VERBOSE) {
+               printk("finishing up transfer\n");
+       }
+
+       disable_dma(dma);
+       clear_dma_ff(dma);
+       set_dma_mode(dma,DMA_MODE_READ);
+       set_dma_addr(dma,virt_to_bus(ltdmabuf));
+       set_dma_count(dma,0x100);
+       enable_dma(dma);
+
+       (void) inb_p(base+3);
+       (void) inb_p(base+2);
+       timeout = jiffies+100;
+       while(timeout>jiffies) {
+               if( 0xf9 == inb_p(base+6)) break;
+       }
+
+       if(debug&DEBUG_VERBOSE) {
+               printk("setting up timer and irq\n");
+       }
+
+       init_timer(&ltpc_timer);
+       ltpc_timer.function=ltpc_poll;
+       ltpc_timer.data = (unsigned long) dev;
+
+       if (irq) {
+               irq2dev_map[irq] = dev;
+               (void) request_irq( irq, &ltpc_interrupt, 0, "ltpc",NULL);
+               (void) inb_p(base+7);  /* enable interrupts from board */
+               (void) inb_p(base+7);  /* and reset irq line */
+               ltpc_timer.expires = 100;
+                 /* poll it once per second just in case */
+       } else {
+               ltpc_timer.expires = 5;
+                 /* polled mode -- 20 times per second */
+       }
+
+       add_timer(&ltpc_timer);
+
+       restore_flags(flags); 
+
+       return 0;
+}
+
+#ifdef MODULE
+static struct device dev_ltpc = {
+       "ltalk0\0   ", 
+               0, 0, 0, 0,
+               0x0, 0,
+               0, 0, 0, NULL, ltpc_probe };
+
+int init_module(void)
+{
+       /* Find a name for this unit */
+       int ct= 1;
+       
+       while(dev_get(dev_ltpc.name)!=NULL && ct<100)
+       {
+               sprintf(dev_ltpc.name,"ltpc%d",ct);
+               ct++;
+       }
+       if(ct==100)
+               return -ENFILE;
+       
+       if (register_netdev(&dev_ltpc) != 0) {
+               if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n");
+               return -EIO;
+       } else {
+               if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
+               return 0;
+       }
+}
+
+void cleanup_module(void)
+{
+       long timeout;
+
+       ltpc_timer.data = 0;  /* signal the poll routine that we're done */
+
+       if(debug&DEBUG_VERBOSE) printk("freeing irq\n");
+
+       if(dev_ltpc.irq) {
+               free_irq(dev_ltpc.irq,NULL);
+               dev_ltpc.irq = 0;
+       }
+
+       if(del_timer(&ltpc_timer)) 
+       {
+               /* either the poll was never started, or a poll is in process */
+               if(debug&DEBUG_VERBOSE) printk("waiting\n");
+               /* if it's in process, wait a bit for it to finish */
+               timeout = jiffies+HZ; 
+               add_timer(&ltpc_timer)
+               while(del_timer(&ltpc_timer) && (timeout > jiffies))
+               {
+                       add_timer(&ltpc_timer);
+                       schedule();
+               }
+       }
+
+       if(debug&DEBUG_VERBOSE) printk("freeing dma\n");
+
+       if(dev_ltpc.dma) {
+               free_dma(dev_ltpc.dma);
+               dev_ltpc.dma = 0;
+       }
+
+       if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n");
+
+       if(dev_ltpc.base_addr) {
+               release_region(dev_ltpc.base_addr,8);
+               dev_ltpc.base_addr = 0;
+       }
+
+       if(debug&DEBUG_VERBOSE) printk("free_pages\n");
+
+       free_pages( (unsigned long) ltdmabuf, __get_order(1000));
+       ltdmabuf=NULL;
+       ltdmacbuf=NULL;
+
+       if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n");
+
+       unregister_netdev(&dev_ltpc);
+
+       if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
+}
+#endif /* MODULE */
diff --git a/drivers/net/ltpc.h b/drivers/net/ltpc.h
new file mode 100644 (file)
index 0000000..cd30544
--- /dev/null
@@ -0,0 +1,73 @@
+/***   ltpc.h
+ *
+ *
+ ***/
+
+#define LT_GETRESULT  0x00
+#define LT_WRITEMEM   0x01
+#define LT_READMEM    0x02
+#define LT_GETFLAGS   0x04
+#define LT_SETFLAGS   0x05
+#define LT_INIT       0x10
+#define LT_SENDLAP    0x13
+#define LT_RCVLAP     0x14
+
+/* the flag that we care about */
+#define LT_FLAG_ALLLAP 0x04
+
+struct lt_getresult {
+       unsigned char command;
+       unsigned char mailbox;
+};
+
+struct lt_mem {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned short addr;    /* host order */
+       unsigned short length;  /* host order */
+};
+
+struct lt_setflags {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char flags;
+};
+
+struct lt_getflags {
+       unsigned char command;
+       unsigned char mailbox;
+};
+
+struct lt_init {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char hint;
+};
+
+struct lt_sendlap {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char dnode;
+       unsigned char laptype;
+       unsigned short length;  /* host order */
+};
+
+struct lt_rcvlap {
+       unsigned char command;
+       unsigned char dnode;
+       unsigned char snode;
+       unsigned char laptype;
+       unsigned short length;  /* host order */
+};
+
+union lt_command {
+       struct lt_getresult getresult;
+       struct lt_mem mem;
+       struct lt_setflags setflags;
+       struct lt_getflags getflags;
+       struct lt_init init;
+       struct lt_sendlap sendlap;
+       struct lt_rcvlap rcvlap;
+};
+typedef union lt_command lt_command;
+
index dfe8695fdc5bcae2e68a01b487c2f33bffc62097..2b14474066805a2ab4754ccfc789c8d7d2ec77b0 100644 (file)
@@ -643,12 +643,12 @@ static void ax25_close(struct tty_struct *tty)
 }
 
 
-static struct enet_statistics *ax_get_stats(struct device *dev)
+static struct net_device_stats *ax_get_stats(struct device *dev)
 {
-       static struct enet_statistics stats;
+       static struct net_device_stats stats;
        struct ax_disp *ax = (struct ax_disp*)dev->priv;
 
-       memset(&stats, 0, sizeof(struct enet_statistics));
+       memset(&stats, 0, sizeof(struct net_device_stats));
 
        stats.rx_packets     = ax->rx_packets;
        stats.tx_packets     = ax->tx_packets;
@@ -839,7 +839,7 @@ int mkiss_init_ctrl_dev(void)
        ax_ldisc.read   = NULL;
        ax_ldisc.write  = NULL;
        ax_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long))ax25_disp_ioctl;
-       ax_ldisc.select = NULL;
+       ax_ldisc.poll   = NULL;
 
        ax_ldisc.receive_buf  = ax25_receive_buf;
        ax_ldisc.receive_room = ax25_receive_room;
index 18bb98423f81c848ed80613b79fa193bc9dfe518..31474ce332cabe0303a6b8493ab62aaa9d938e90 100644 (file)
@@ -819,7 +819,7 @@ static int myri_change_mtu(struct device *dev, int new_mtu)
        return 0;
 }
 
-static struct enet_statistics *myri_get_stats(struct device *dev)
+static struct net_device_stats *myri_get_stats(struct device *dev)
 { return &(((struct myri_eth *)dev->priv)->enet_stats); }
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
index 97e61dad301e9e9704640e3f6a78ae74917c98b8..2de6a46fa83a62d5b4a3c28d262b7b659a5333ba 100644 (file)
@@ -278,7 +278,7 @@ struct myri_eth {
        struct lanai_regs               *lregs;         /* Quick ptr to LANAI regs.   */
        struct sk_buff         *rx_skbs[RX_RING_SIZE+1];/* RX skb's                   */
        struct sk_buff         *tx_skbs[TX_RING_SIZE];  /* TX skb's                   */
-       struct enet_statistics          enet_stats;     /* Interface stats.           */
+       struct net_device_stats         enet_stats;     /* Interface stats.           */
 
        /* These are less frequently accessed. */
        struct myri_regs                *regs;          /* MyriCOM register space.    */
index 37987960b00be79b2a31708628703f05b37210df..aebbca8a4015363e4ea1c00a540fb37dcb2c2cb2 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/if_arp.h>
 #include <linux/fddidevice.h>
 #include <linux/net_alias.h>
+#include <linux/if_ltalk.h>
 
 /* The network devices currently exist only in the socket namespace, so these
    entries are unused.  The only ones that make sense are
@@ -247,6 +248,50 @@ void fddi_setup(struct device *dev)
 
 #endif
 
+#ifdef CONFIG_ATALK
+
+static int ltalk_change_mtu(struct device *dev, int mtu)
+{
+       return -EINVAL;
+}
+
+static int ltalk_mac_addr(struct device *dev, void *addr)
+{      
+       return -EINVAL;
+}
+
+
+void ltalk_setup(struct device *dev)
+{
+       /* Fill in the fields of the device structure with localtalk-generic values. */
+
+       dev_init_buffers(dev);
+       
+       dev->change_mtu         = ltalk_change_mtu;
+       dev->hard_header        = NULL;
+       dev->rebuild_header     = NULL;
+       dev->set_mac_address    = ltalk_mac_addr;
+       dev->hard_header_cache  = NULL;
+       dev->header_cache_update= NULL;
+
+       dev->type               = ARPHRD_LOCALTLK;
+       dev->hard_header_len    = LTALK_HLEN;
+       dev->mtu                = LTALK_MTU;
+       dev->addr_len           = LTALK_ALEN;
+       dev->tx_queue_len       = 10;   
+       
+       dev->broadcast[0]       = 0xFF;
+
+       dev->flags              = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
+       dev->family             = AF_APPLETALK;
+       dev->pa_addr            = 0;
+       dev->pa_brdaddr         = 0;
+       dev->pa_mask            = 0;
+       dev->pa_alen            = 1;
+}
+
+#endif
+
 int ether_config(struct device *dev, struct ifmap *map)
 {
        if (map->mem_start != (u_long)(-1))
index 8f4cd4e288a8c9744426d406a411544574676ac0..03adb84c154a3dc5b4eb8ca4c93834c490621127 100644 (file)
@@ -164,7 +164,8 @@ sizeof(nop_cmd) = 8;
 #define DELAY_18(); { __delay( (loops_per_sec>>18)+1 ); }
 
 /* wait for command with timeout: */
-#define WAIT_4_SCB_CMD() { int i; \
+#define WAIT_4_SCB_CMD() 
+{ int i; \
   for(i=0;i<16384;i++) { \
     if(!p->scb->cmd_cuc) break; \
     DELAY_18(); \
@@ -195,7 +196,7 @@ static void    ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
 static int     ni52_open(struct device *dev);
 static int     ni52_close(struct device *dev);
 static int     ni52_send_packet(struct sk_buff *,struct device *);
-static struct  enet_statistics *ni52_get_stats(struct device *dev);
+static struct  net_device_stats *ni52_get_stats(struct device *dev);
 static void    set_multicast_list(struct device *dev);
 #if 0
 static void    ni52_dump(struct device *,void *);
@@ -213,24 +214,24 @@ static void    ni52_rnr_int(struct device *dev);
 
 struct priv
 {
-  struct enet_statistics stats;
-  unsigned long base;
-  char *memtop;
-  int lock,reseted;
-  volatile struct rfd_struct  *rfd_last,*rfd_top,*rfd_first;
-  volatile struct scp_struct  *scp;  /* volatile is important */
-  volatile struct iscp_struct *iscp; /* volatile is important */
-  volatile struct scb_struct  *scb;  /* volatile is important */
-  volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
-  volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+       struct net_device_stats stats;
+       unsigned long base;
+       char *memtop;
+       int lock,reseted;
+       volatile struct rfd_struct      *rfd_last,*rfd_top,*rfd_first;
+       volatile struct scp_struct      *scp;   /* volatile is important */
+       volatile struct iscp_struct     *iscp;  /* volatile is important */
+       volatile struct scb_struct      *scb;   /* volatile is important */
+       volatile struct tbd_struct      *xmit_buffs[NUM_XMIT_BUFFS];
+       volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
-  volatile struct nop_cmd_struct *nop_cmds[2];
+       volatile struct nop_cmd_struct *nop_cmds[2];
 #else
-  volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+       volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
-  volatile int    nop_point,num_recv_buffs;
-  volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
-  volatile int    xmit_count,xmit_last;
+       volatile int            nop_point,num_recv_buffs;
+       volatile char           *xmit_cbuffs[NUM_XMIT_BUFFS];
+       volatile int            xmit_count,xmit_last;
 };
 
 /**********************************************
@@ -238,17 +239,17 @@ struct priv
  */
 static int ni52_close(struct device *dev)
 {
-  free_irq(dev->irq, NULL);
-  irq2dev_map[dev->irq] = NULL;
+       free_irq(dev->irq, NULL);
+       irq2dev_map[dev->irq] = NULL;
 
-  ni_reset586(); /* the hard way to stop the receiver */
+       ni_reset586(); /* the hard way to stop the receiver */
 
-  dev->start = 0;
-  dev->tbusy = 0;
+       dev->start = 0;
+       dev->tbusy = 0;
 
-  MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
 
-  return 0;
+       return 0;
 }
 
 /**********************************************
@@ -256,26 +257,26 @@ static int ni52_close(struct device *dev)
  */
 static int ni52_open(struct device *dev)
 {
-  ni_disint();
-  alloc586(dev);
-  init586(dev);
-  startrecv586(dev);
-  ni_enaint();
-
-  if(request_irq(dev->irq, &ni52_interrupt,0,"ni5210",NULL))
-  {
-    ni_reset586();
-    return -EAGAIN;
-  }
-  irq2dev_map[dev->irq] = dev;
-
-  dev->interrupt = 0;
-  dev->tbusy = 0;
-  dev->start = 1;
-
-  MOD_INC_USE_COUNT;
-
-  return 0; /* most done by init */
+       ni_disint();
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       ni_enaint();
+
+       if(request_irq(dev->irq, &ni52_interrupt,0,"ni5210",NULL))
+       {
+               ni_reset586();
+               return -EAGAIN;
+       }
+       irq2dev_map[dev->irq] = dev;
+
+       dev->interrupt = 0;
+       dev->tbusy = 0;
+       dev->start = 1;
+
+       MOD_INC_USE_COUNT;
+
+       return 0; /* most done by init */
 }
 
 /**********************************************
@@ -283,41 +284,41 @@ static int ni52_open(struct device *dev)
  */
 static int check586(struct device *dev,char *where,unsigned size)
 {
-  struct priv pb;
-  struct priv *p = /* (struct priv *) dev->priv*/ &pb;
-  char *iscp_addrs[2];
-  int i;
-
-  p->base = (unsigned long) bus_to_virt((unsigned long)where) + size - 0x01000000;
-  p->memtop = bus_to_virt((unsigned long)where) + size;
-  p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
-  memset((char *)p->scp,0, sizeof(struct scp_struct));
-  for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
-    if(((char *)p->scp)[i])
-      return 0;
-  p->scp->sysbus = SYSBUSVAL;        /* 1 = 8Bit-Bus, 0 = 16 Bit */
-  if(p->scp->sysbus != SYSBUSVAL)
-    return 0;
-
-  iscp_addrs[0] = bus_to_virt((unsigned long)where);
-  iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct);
-
-  for(i=0;i<2;i++)
-  {
-    p->iscp = (struct iscp_struct *) iscp_addrs[i];
-    memset((char *)p->iscp,0, sizeof(struct iscp_struct));
-
-    p->scp->iscp = make24(p->iscp);
-    p->iscp->busy = 1;
-
-    ni_reset586();
-    ni_attn586();
-    DELAY(1);  /* wait a while... */
-
-    if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
-      return 0;
-  }
-  return 1;
+       struct priv pb;
+       struct priv *p = /* (struct priv *) dev->priv*/ &pb;
+       char *iscp_addrs[2];
+       int i;
+
+       p->base = (unsigned long) bus_to_virt((unsigned long)where) + size - 0x01000000;
+       p->memtop = bus_to_virt((unsigned long)where) + size;
+       p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+       memset((char *)p->scp,0, sizeof(struct scp_struct));
+       for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+               if(((char *)p->scp)[i])
+                       return 0;
+       p->scp->sysbus = SYSBUSVAL;                             /* 1 = 8Bit-Bus, 0 = 16 Bit */
+       if(p->scp->sysbus != SYSBUSVAL)
+               return 0;
+
+       iscp_addrs[0] = bus_to_virt((unsigned long)where);
+       iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct);
+
+       for(i=0;i<2;i++)
+       {
+               p->iscp = (struct iscp_struct *) iscp_addrs[i];
+               memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+               p->scp->iscp = make24(p->iscp);
+               p->iscp->busy = 1;
+
+               ni_reset586();
+               ni_attn586();
+               DELAY(1);       /* wait a while... */
+
+               if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+                       return 0;
+       }
+       return 1;
 }
 
 /******************************************************************
@@ -325,34 +326,34 @@ static int check586(struct device *dev,char *where,unsigned size)
  */
 void alloc586(struct device *dev)
 {
-  struct priv *p =  (struct priv *) dev->priv;
+       struct priv *p =        (struct priv *) dev->priv;
 
-  ni_reset586();
-  DELAY(1);
+       ni_reset586();
+       DELAY(1);
 
-  p->scp  = (struct scp_struct *)  (p->base + SCP_DEFAULT_ADDRESS);
-  p->scb  = (struct scb_struct *)  bus_to_virt(dev->mem_start);
-  p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct));
+       p->scp  = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+       p->scb  = (struct scb_struct *) bus_to_virt(dev->mem_start);
+       p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct));
 
-  memset((char *) p->iscp,0,sizeof(struct iscp_struct));
-  memset((char *) p->scp ,0,sizeof(struct scp_struct));
+       memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+       memset((char *) p->scp ,0,sizeof(struct scp_struct));
 
-  p->scp->iscp = make24(p->iscp);
-  p->scp->sysbus = SYSBUSVAL;
-  p->iscp->scb_offset = make16(p->scb);
+       p->scp->iscp = make24(p->iscp);
+       p->scp->sysbus = SYSBUSVAL;
+       p->iscp->scb_offset = make16(p->scb);
 
-  p->iscp->busy = 1;
-  ni_reset586();
-  ni_attn586();
+       p->iscp->busy = 1;
+       ni_reset586();
+       ni_attn586();
 
-  DELAY(1);
+       DELAY(1);
 
-  if(p->iscp->busy)
-    printk("%s: Init-Problems (alloc).\n",dev->name);
+       if(p->iscp->busy)
+               printk("%s: Init-Problems (alloc).\n",dev->name);
 
-  p->reseted = 0;
+       p->reseted = 0;
 
-  memset((char *)p->scb,0,sizeof(struct scb_struct));
+       memset((char *)p->scb,0,sizeof(struct scb_struct));
 }
 
 /**********************************************
@@ -361,172 +362,172 @@ void alloc586(struct device *dev)
 int ni52_probe(struct device *dev)
 {
 #ifndef MODULE
-  int *port;
-  static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0};
+       int *port;
+       static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0};
 #endif
-  int base_addr = dev->base_addr;
+       int base_addr = dev->base_addr;
 
-  if (base_addr > 0x1ff)               /* Check a single specified location. */
-    if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
-        (inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
-      return ni52_probe1(dev, base_addr);
-  else if (base_addr > 0)              /* Don't probe at all. */
-    return ENXIO;
+       if (base_addr > 0x1ff)          /* Check a single specified location. */
+               if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
+                               (inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
+                       return ni52_probe1(dev, base_addr);
+       else if (base_addr > 0)         /* Don't probe at all. */
+               return ENXIO;
 
 #ifdef MODULE
-  printk("%s: no autoprobing allowed for modules.\n",dev->name);
+       printk("%s: no autoprobing allowed for modules.\n",dev->name);
 #else
-  for (port = ports; *port; port++) {
-    int ioaddr = *port;
-    if (check_region(ioaddr, NI52_TOTAL_SIZE))
-      continue;
-    if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-        !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
-      continue;
-
-    dev->base_addr = ioaddr;
-    if (ni52_probe1(dev, ioaddr) == 0)
-      return 0;
-  }
+       for (port = ports; *port; port++) {
+               int ioaddr = *port;
+               if (check_region(ioaddr, NI52_TOTAL_SIZE))
+                       continue;
+               if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
+                               !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
+                       continue;
+
+               dev->base_addr = ioaddr;
+               if (ni52_probe1(dev, ioaddr) == 0)
+                       return 0;
+       }
 
 #ifdef FULL_IO_PROBE
-  for(dev->base_addr=0x200;dev->base_addr<0x400;dev->base_addr+=8)
-  {
-    int ioaddr = dev->base_addr;
-    if (check_region(ioaddr, NI52_TOTAL_SIZE))
-      continue;
-    if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-        !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
-      continue;
-    if (ni52_probe1(dev, ioaddr) == 0)
-      return 0;
-  }
+       for(dev->base_addr=0x200;dev->base_addr<0x400;dev->base_addr+=8)
+       {
+               int ioaddr = dev->base_addr;
+               if (check_region(ioaddr, NI52_TOTAL_SIZE))
+                       continue;
+               if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
+                               !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
+                       continue;
+               if (ni52_probe1(dev, ioaddr) == 0)
+                       return 0;
+       }
 #endif
 
 #endif
 
-  dev->base_addr = base_addr;
-  return ENODEV;
+       dev->base_addr = base_addr;
+       return ENODEV;
 }
 
 static int ni52_probe1(struct device *dev,int ioaddr)
 {
-  int i,size;
+       int i,size;
 
-  for(i=0;i<ETH_ALEN;i++)
-    dev->dev_addr[i] = inb(dev->base_addr+i);
+       for(i=0;i<ETH_ALEN;i++)
+               dev->dev_addr[i] = inb(dev->base_addr+i);
 
-  if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1
-     || dev->dev_addr[2] != NI52_ADDR2)
-    return ENODEV;
+       if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1
+                || dev->dev_addr[2] != NI52_ADDR2)
+               return ENODEV;
 
-  printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr);
+       printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr);
 
-  request_region(ioaddr,NI52_TOTAL_SIZE,"ni5210");
+       request_region(ioaddr,NI52_TOTAL_SIZE,"ni5210");
 
-  /*
-   * check (or search) IO-Memory, 8K and 16K
-   */
+       /*
+        * check (or search) IO-Memory, 8K and 16K
+        */
 #ifdef MODULE
-  size = dev->mem_end - dev->mem_start;
-  if(size != 0x2000 && size != 0x4000)
-  {
-    printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n",dev->name,size);
-    return ENODEV;
-  }
-  if(!check586(dev,(char *) dev->mem_start,size))
-  {
-    printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
-    return ENODEV;
-  }
+       size = dev->mem_end - dev->mem_start;
+       if(size != 0x2000 && size != 0x4000)
+       {
+               printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n",dev->name,size);
+               return ENODEV;
+       }
+       if(!check586(dev,(char *) dev->mem_start,size))
+       {
+               printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+               return ENODEV;
+       }
 #else
-  if(dev->mem_start != 0) /* no auto-mem-probe */
-  {
-    size = 0x4000; /* check for 16K mem */
-    if(!check586(dev,(char *) dev->mem_start,size)) {
-      size = 0x2000; /* check for 8K mem */
-      if(!check586(dev,(char *) dev->mem_start,size)) {
-        printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start);
-        return ENODEV;
-      }
-    }
-  }
-  else
-  {
-   static long memaddrs[] = { 0xc8000,0xca000,0xcc000,0xce000,0xd0000,0xd2000,
-                              0xd4000,0xd6000,0xd8000,0xda000,0xdc000, 0 };
-   for(i=0;;i++)
-    {
-      if(!memaddrs[i]) {
-        printk("?memprobe, Can't find io-memory!\n");
-        return ENODEV;
-      }
-      dev->mem_start = memaddrs[i];
-      size = 0x2000; /* check for 8K mem */
-      if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */
-        break;
-      size = 0x4000; /* check for 16K mem */
-      if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */
-        break;
-    }
-  }
-  dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
+       if(dev->mem_start != 0) /* no auto-mem-probe */
+       {
+               size = 0x4000; /* check for 16K mem */
+               if(!check586(dev,(char *) dev->mem_start,size)) {
+                       size = 0x2000; /* check for 8K mem */
+                       if(!check586(dev,(char *) dev->mem_start,size)) {
+                               printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start);
+                               return ENODEV;
+                       }
+               }
+       }
+       else
+       {
+               static long memaddrs[] = { 0xc8000,0xca000,0xcc000,0xce000,0xd0000,0xd2000,
+                                                                                                                       0xd4000,0xd6000,0xd8000,0xda000,0xdc000, 0 };
+               for(i=0;;i++)
+               {
+                       if(!memaddrs[i]) {
+                               printk("?memprobe, Can't find io-memory!\n");
+                               return ENODEV;
+                       }
+                       dev->mem_start = memaddrs[i];
+                       size = 0x2000; /* check for 8K mem */
+                       if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */
+                               break;
+                       size = 0x4000; /* check for 16K mem */
+                       if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */
+                               break;
+               }
+       }
+       dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
 #endif
 
-  dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
-  if(dev->priv == NULL)
-  {
-    printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
-    return -ENOMEM;
-  }
-                                  /* warning: we don't free it on errors */
-  memset((char *) dev->priv,0,sizeof(struct priv));
-
-  ((struct priv *) (dev->priv))->memtop = bus_to_virt(dev->mem_start) + size;
-  ((struct priv *) (dev->priv))->base =  (unsigned long) bus_to_virt(dev->mem_start) + size - 0x01000000;
-  alloc586(dev);
-
-  /* set number of receive-buffs according to memsize */
-  if(size == 0x2000)
-    ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
-  else
-    ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
-
-  printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size);
-
-  if(dev->irq < 2)
-  {
-    autoirq_setup(0);
-    ni_reset586();
-    ni_attn586();
-    if(!(dev->irq = autoirq_report(2)))
-    {
-      printk("?autoirq, Failed to detect IRQ line!\n");
-      return 1;
-    }
-    printk("IRQ %d (autodetected).\n",dev->irq);
-  }
-  else  {
-    if(dev->irq == 2)
-      dev->irq = 9;
-    printk("IRQ %d (assigned and not checked!).\n",dev->irq);
-  }
-
-  dev->open            = &ni52_open;
-  dev->stop            = &ni52_close;
-  dev->get_stats       = &ni52_get_stats;
-  dev->hard_start_xmit = &ni52_send_packet;
-  dev->set_multicast_list = &set_multicast_list;
-
-  dev->if_port                = 0;
-
-  ether_setup(dev);
-
-  dev->tbusy = 0;
-  dev->interrupt = 0;
-  dev->start = 0;
-
-  return 0;
+       dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
+       if(dev->priv == NULL)
+       {
+               printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
+               return -ENOMEM;
+       }
+                                                                                                                                       /* warning: we don't free it on errors */
+       memset((char *) dev->priv,0,sizeof(struct priv));
+
+       ((struct priv *) (dev->priv))->memtop = bus_to_virt(dev->mem_start) + size;
+       ((struct priv *) (dev->priv))->base =   (unsigned long) bus_to_virt(dev->mem_start) + size - 0x01000000;
+       alloc586(dev);
+
+       /* set number of receive-buffs according to memsize */
+       if(size == 0x2000)
+               ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+       else
+               ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+
+       printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size);
+
+       if(dev->irq < 2)
+       {
+               autoirq_setup(0);
+               ni_reset586();
+               ni_attn586();
+               if(!(dev->irq = autoirq_report(2)))
+               {
+                       printk("?autoirq, Failed to detect IRQ line!\n");
+                       return 1;
+               }
+               printk("IRQ %d (autodetected).\n",dev->irq);
+       }
+       else    {
+               if(dev->irq == 2)
+                       dev->irq = 9;
+               printk("IRQ %d (assigned and not checked!).\n",dev->irq);
+       }
+
+       dev->open               = &ni52_open;
+       dev->stop               = &ni52_close;
+       dev->get_stats          = &ni52_get_stats;
+       dev->hard_start_xmit    = &ni52_send_packet;
+       dev->set_multicast_list = &set_multicast_list;
+
+       dev->if_port            = 0;
+
+       ether_setup(dev);
+
+       dev->tbusy              = 0;
+       dev->interrupt          = 0;
+       dev->start              = 0;
+
+       return 0;
 }
 
 /**********************************************
@@ -536,230 +537,232 @@ static int ni52_probe1(struct device *dev,int ioaddr)
 
 static int init586(struct device *dev)
 {
-  void *ptr;
-  int i,result=0;
-  struct priv *p = (struct priv *) dev->priv;
-  volatile struct configure_cmd_struct  *cfg_cmd;
-  volatile struct iasetup_cmd_struct *ias_cmd;
-  volatile struct tdr_cmd_struct *tdr_cmd;
-  volatile struct mcsetup_cmd_struct *mc_cmd;
-  struct dev_mc_list *dmi=dev->mc_list;
-  int num_addrs=dev->mc_count;
-
-  ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
-
-  cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
-  cfg_cmd->cmd_status = 0;
-  cfg_cmd->cmd_cmd    = CMD_CONFIGURE | CMD_LAST;
-  cfg_cmd->cmd_link   = 0xffff;
-
-  cfg_cmd->byte_cnt   = 0x0a; /* number of cfg bytes */
-  cfg_cmd->fifo       = fifo; /* fifo-limit (8=tx:32/rx:64) */
-  cfg_cmd->sav_bf     = 0x40; /* hold or discard bad recv frames (bit 7) */
-  cfg_cmd->adr_len    = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
-  cfg_cmd->priority   = 0x00;
-  cfg_cmd->ifs        = 0x60;
-  cfg_cmd->time_low   = 0x00;
-  cfg_cmd->time_high  = 0xf2;
-  cfg_cmd->promisc    = 0;
-  if(dev->flags & IFF_ALLMULTI) {
-    int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
-    if(num_addrs > len)  {
-      printk("%s: switching to promisc. mode\n",dev->name);
-      dev->flags|=IFF_PROMISC;
-    }
-  }
-  if(dev->flags&IFF_PROMISC)
-  {
-       cfg_cmd->promisc=1;
-       dev->flags|=IFF_PROMISC;
-  }
-  cfg_cmd->carr_coll  = 0x00;
-
-  p->scb->cbl_offset = make16(cfg_cmd);
-  p->scb->cmd_ruc = 0;
-
-  p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-
-  WAIT_4_STAT_COMPL(cfg_cmd);
-
-  if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
-  {
-    printk("%s: configure command failed: %x\n",dev->name,cfg_cmd->cmd_status);
-    return 1;
-  }
-
-    /*
-     * individual address setup
-     */
-  ias_cmd = (struct iasetup_cmd_struct *)ptr;
-
-  ias_cmd->cmd_status = 0;
-  ias_cmd->cmd_cmd    = CMD_IASETUP | CMD_LAST;
-  ias_cmd->cmd_link   = 0xffff;
-
-  memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
-
-  p->scb->cbl_offset = make16(ias_cmd);
-
-  p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-
-  WAIT_4_STAT_COMPL(ias_cmd);
-
-  if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
-    printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status);
-    return 1;
-  }
-
-   /*
-    * TDR, wire check .. e.g. no resistor e.t.c
-    */
-  tdr_cmd = (struct tdr_cmd_struct *)ptr;
-
-  tdr_cmd->cmd_status  = 0;
-  tdr_cmd->cmd_cmd     = CMD_TDR | CMD_LAST;
-  tdr_cmd->cmd_link    = 0xffff;
-  tdr_cmd->status      = 0;
-
-  p->scb->cbl_offset = make16(tdr_cmd);
-  p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-
-  WAIT_4_STAT_COMPL(tdr_cmd);
-
-  if(!(tdr_cmd->cmd_status & STAT_COMPL))
-  {
-    printk("%s: Problems while running the TDR.\n",dev->name);
-  }
-  else
-  {
-    DELAY_16(); /* wait for result */
-    result = tdr_cmd->status;
-
-    p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
-    ni_attn586(); /* ack the interrupts */
-
-    if(result & TDR_LNK_OK)
-      ;
-    else if(result & TDR_XCVR_PRB)
-      printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
-    else if(result & TDR_ET_OPN)
-      printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
-    else if(result & TDR_ET_SRT)
-    {
-      if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
-        printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
-    }
-    else
-      printk("%s: TDR: Unknown status %04x\n",dev->name,result);
-  }
-
-  /*
-   * Multicast setup
-   */
-  if(num_addrs && !(dev->flags & IFF_PROMISC) )
-  {
-    mc_cmd = (struct mcsetup_cmd_struct *) ptr;
-    mc_cmd->cmd_status = 0;
-    mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
-    mc_cmd->cmd_link = 0xffff;
-    mc_cmd->mc_cnt = num_addrs * 6;
-
-    for(i=0;i<num_addrs;i++,dmi=dmi->next)
-      memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
-
-    p->scb->cbl_offset = make16(mc_cmd);
-    p->scb->cmd_cuc = CUC_START;
-    ni_attn586();
-
-    WAIT_4_STAT_COMPL(mc_cmd);
-
-    if( (mc_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
-      printk("%s: Can't apply multicast-address-list.\n",dev->name);
-  }
-
-   /*
-    * alloc nop/xmit-cmds
-    */
+       void *ptr;
+       int i,result=0;
+       struct priv *p = (struct priv *) dev->priv;
+       volatile struct configure_cmd_struct    *cfg_cmd;
+       volatile struct iasetup_cmd_struct *ias_cmd;
+       volatile struct tdr_cmd_struct *tdr_cmd;
+       volatile struct mcsetup_cmd_struct *mc_cmd;
+       struct dev_mc_list *dmi=dev->mc_list;
+       int num_addrs=dev->mc_count;
+
+       ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+       cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+       cfg_cmd->cmd_status     = 0;
+       cfg_cmd->cmd_cmd        = CMD_CONFIGURE | CMD_LAST;
+       cfg_cmd->cmd_link       = 0xffff;
+
+       cfg_cmd->byte_cnt       = 0x0a; /* number of cfg bytes */
+       cfg_cmd->fifo           = fifo; /* fifo-limit (8=tx:32/rx:64) */
+       cfg_cmd->sav_bf         = 0x40; /* hold or discard bad recv frames (bit 7) */
+       cfg_cmd->adr_len        = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+       cfg_cmd->priority       = 0x00;
+       cfg_cmd->ifs            = 0x60;
+       cfg_cmd->time_low       = 0x00;
+       cfg_cmd->time_high      = 0xf2;
+       cfg_cmd->promisc        = 0;
+       if(dev->flags & IFF_ALLMULTI) {
+               int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+               if(num_addrs > len)     {
+                       printk("%s: switching to promisc. mode\n",dev->name);
+                       dev->flags|=IFF_PROMISC;
+               }
+       }
+       if(dev->flags&IFF_PROMISC)
+       {
+                        cfg_cmd->promisc=1;
+                        dev->flags|=IFF_PROMISC;
+       }
+       cfg_cmd->carr_coll      = 0x00;
+
+       p->scb->cbl_offset      = make16(cfg_cmd);
+       p->scb->cmd_ruc         = 0;
+
+       p->scb->cmd_cuc         = CUC_START; /* cmd.-unit start */
+       ni_attn586();
+
+       WAIT_4_STAT_COMPL(cfg_cmd);
+
+       if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+       {
+               printk("%s: configure command failed: %x\n",dev->name,cfg_cmd->cmd_status);
+               return 1;
+       }
+
+       /*
+        * individual address setup
+        */
+
+       ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+       ias_cmd->cmd_status     = 0;
+       ias_cmd->cmd_cmd        = CMD_IASETUP | CMD_LAST;
+       ias_cmd->cmd_link       = 0xffff;
+
+       memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+       p->scb->cbl_offset = make16(ias_cmd);
+
+       p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+       ni_attn586();
+
+       WAIT_4_STAT_COMPL(ias_cmd);
+
+       if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+               printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status);
+               return 1;
+       }
+
+       /*
+        * TDR, wire check .. e.g. no resistor e.t.c
+        */
+        
+       tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+       tdr_cmd->cmd_status     = 0;
+       tdr_cmd->cmd_cmd        = CMD_TDR | CMD_LAST;
+       tdr_cmd->cmd_link       = 0xffff;
+       tdr_cmd->status         = 0;
+
+       p->scb->cbl_offset = make16(tdr_cmd);
+       p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+       ni_attn586();
+
+       WAIT_4_STAT_COMPL(tdr_cmd);
+
+       if(!(tdr_cmd->cmd_status & STAT_COMPL))
+       {
+               printk("%s: Problems while running the TDR.\n",dev->name);
+       }
+       else
+       {
+               DELAY_16(); /* wait for result */
+               result = tdr_cmd->status;
+
+               p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+               ni_attn586(); /* ack the interrupts */
+
+               if(result & TDR_LNK_OK)
+                       ;
+               else if(result & TDR_XCVR_PRB)
+                       printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+               else if(result & TDR_ET_OPN)
+                       printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+               else if(result & TDR_ET_SRT)
+               {
+                       if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+                               printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+               }
+               else
+                       printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+       }
+
+       /*
+        * Multicast setup
+        */
+       if(num_addrs && !(dev->flags & IFF_PROMISC) )
+       {
+               mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+               mc_cmd->cmd_status = 0;
+               mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
+               mc_cmd->cmd_link = 0xffff;
+               mc_cmd->mc_cnt = num_addrs * 6;
+
+               for(i=0;i<num_addrs;i++,dmi=dmi->next)
+                       memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
+
+               p->scb->cbl_offset = make16(mc_cmd);
+               p->scb->cmd_cuc = CUC_START;
+               ni_attn586();
+
+               WAIT_4_STAT_COMPL(mc_cmd);
+
+               if( (mc_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+                       printk("%s: Can't apply multicast-address-list.\n",dev->name);
+       }
+
+       /*
+        * alloc nop/xmit-cmds
+        */
 #if (NUM_XMIT_BUFFS == 1)
-  for(i=0;i<2;i++)
-  {
-    p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
-    p->nop_cmds[i]->cmd_cmd    = CMD_NOP;
-    p->nop_cmds[i]->cmd_status = 0;
-    p->nop_cmds[i]->cmd_link   = make16((p->nop_cmds[i]));
-    ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-  }
+       for(i=0;i<2;i++)
+       {
+               p->nop_cmds[i]                  = (struct nop_cmd_struct *)ptr;
+               p->nop_cmds[i]->cmd_cmd         = CMD_NOP;
+               p->nop_cmds[i]->cmd_status      = 0;
+               p->nop_cmds[i]->cmd_link        = make16((p->nop_cmds[i]));
+               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+       }
 #else
-  for(i=0;i<NUM_XMIT_BUFFS;i++)
-  {
-    p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
-    p->nop_cmds[i]->cmd_cmd    = CMD_NOP;
-    p->nop_cmds[i]->cmd_status = 0;
-    p->nop_cmds[i]->cmd_link   = make16((p->nop_cmds[i]));
-    ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-  }
+       for(i=0;i<NUM_XMIT_BUFFS;i++)
+       {
+               p->nop_cmds[i]                  = (struct nop_cmd_struct *)ptr;
+               p->nop_cmds[i]->cmd_cmd         = CMD_NOP;
+               p->nop_cmds[i]->cmd_status      = 0;
+               p->nop_cmds[i]->cmd_link        = make16((p->nop_cmds[i]));
+               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+       }
 #endif
 
-  ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
-
-  /*
-   * alloc xmit-buffs / init xmit_cmds
-   */
-  for(i=0;i<NUM_XMIT_BUFFS;i++)
-  {
-    p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
-    ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
-    p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
-    ptr = (char *) ptr + XMIT_BUFF_SIZE;
-    p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
-    ptr = (char *) ptr + sizeof(struct tbd_struct);
-    if((void *)ptr > (void *)p->iscp)
-    {
-      printk("%s: not enough shared-mem for your configuration!\n",dev->name);
-      return 1;
-    }
-    memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
-    memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
-    p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
-    p->xmit_cmds[i]->cmd_status = STAT_COMPL;
-    p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
-    p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
-    p->xmit_buffs[i]->next = 0xffff;
-    p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
-  }
-
-  p->xmit_count = 0;
-  p->xmit_last  = 0;
+       ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+
+       /*
+        * alloc xmit-buffs / init xmit_cmds
+        */
+       for(i=0;i<NUM_XMIT_BUFFS;i++)
+       {
+               p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+               ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+               p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+               ptr = (char *) ptr + XMIT_BUFF_SIZE;
+               p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+               ptr = (char *) ptr + sizeof(struct tbd_struct);
+               if((void *)ptr > (void *)p->iscp)
+               {
+                       printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+                       return 1;
+               }
+               memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+               memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+               p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+               p->xmit_cmds[i]->cmd_status = STAT_COMPL;
+               p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
+               p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+               p->xmit_buffs[i]->next = 0xffff;
+               p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+       }
+
+       p->xmit_count = 0;
+       p->xmit_last    = 0;
 #ifndef NO_NOPCOMMANDS
-  p->nop_point  = 0;
+       p->nop_point    = 0;
 #endif
 
-   /*
-    * 'start transmitter'
-    */
+        /*
+               * 'start transmitter'
+               */
 #ifndef NO_NOPCOMMANDS
-  p->scb->cbl_offset = make16(p->nop_cmds[0]);
-  p->scb->cmd_cuc = CUC_START;
-  ni_attn586();
-  WAIT_4_SCB_CMD();
+       p->scb->cbl_offset = make16(p->nop_cmds[0]);
+       p->scb->cmd_cuc = CUC_START;
+       ni_attn586();
+       WAIT_4_SCB_CMD();
 #else
-  p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
-  p->xmit_cmds[0]->cmd_cmd  = CMD_XMIT | CMD_SUSPEND | CMD_INT;
+       p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+       p->xmit_cmds[0]->cmd_cmd        = CMD_XMIT | CMD_SUSPEND | CMD_INT;
 #endif
 
-  /*
-   * ack. interrupts
-   */
-  p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
-  ni_attn586();
-  DELAY_16();
+       /*
+        * ack. interrupts
+        */
+       p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+       ni_attn586();
+       DELAY_16();
 
-  ni_enaint();
+       ni_enaint();
 
-  return 0;
+       return 0;
 }
 
 /******************************************************
@@ -769,43 +772,43 @@ static int init586(struct device *dev)
 
 static void *alloc_rfa(struct device *dev,void *ptr)
 {
-  volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
-  volatile struct rbd_struct *rbd;
-  int i;
-  struct priv *p = (struct priv *) dev->priv;
+       volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+       volatile struct rbd_struct *rbd;
+       int i;
+       struct priv *p = (struct priv *) dev->priv;
 
-  memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
-  p->rfd_first = rfd;
+       memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+       p->rfd_first = rfd;
 
-  for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
-    rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
-    rfd[i].rbd_offset = 0xffff;
-  }
-  rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;   /* RU suspend */
+       for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+               rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+               rfd[i].rbd_offset = 0xffff;
+       }
+       rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;         /* RU suspend */
 
-  ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+       ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
 
-  rbd = (struct rbd_struct *) ptr;
-  ptr = (void *) (rbd + p->num_recv_buffs);
+       rbd = (struct rbd_struct *) ptr;
+       ptr = (void *) (rbd + p->num_recv_buffs);
 
-   /* clr descriptors */
-  memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+        /* clr descriptors */
+       memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
 
-  for(i=0;i<p->num_recv_buffs;i++)
-  {
-    rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
-    rbd[i].size = RECV_BUFF_SIZE;
-    rbd[i].buffer = make24(ptr);
-    ptr = (char *) ptr + RECV_BUFF_SIZE;
-  }
+       for(i=0;i<p->num_recv_buffs;i++)
+       {
+               rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+               rbd[i].size = RECV_BUFF_SIZE;
+               rbd[i].buffer = make24(ptr);
+               ptr = (char *) ptr + RECV_BUFF_SIZE;
+       }
 
-  p->rfd_top  = p->rfd_first;
-  p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+       p->rfd_top      = p->rfd_first;
+       p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
 
-  p->scb->rfa_offset           = make16(p->rfd_first);
-  p->rfd_first->rbd_offset     = make16(rbd);
+       p->scb->rfa_offset              = make16(p->rfd_first);
+       p->rfd_first->rbd_offset        = make16(rbd);
 
-  return ptr;
+       return ptr;
 }
 
 
@@ -815,76 +818,76 @@ static void *alloc_rfa(struct device *dev,void *ptr)
 
 static void ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
 {
-  struct device *dev = (struct device *) irq2dev_map[irq];
-  unsigned short stat;
-  int cnt=0;
-  struct priv *p;
-
-  if (!dev) {
-    printk ("ni5210-interrupt: irq %d for unknown device.\n",irq);
-    return;
-  }
-  p = (struct priv *) dev->priv;
-
-  if(debuglevel > 1)
-    printk("I");
-
-  dev->interrupt = 1;
-
-  WAIT_4_SCB_CMD(); /* wait for last command  */
-
-  while((stat=p->scb->cus & STAT_MASK))
-  {
-    p->scb->cmd_cuc = stat;
-    ni_attn586();
-
-    if(stat & STAT_FR)   /* received a frame */
-      ni52_rcv_int(dev);
-
-    if(stat & STAT_RNR) /* RU went 'not ready' */
-    {
-      printk("(R)");
-      if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
-      {
-        WAIT_4_SCB_CMD();
-        p->scb->cmd_ruc = RUC_RESUME;
-        ni_attn586();
-        WAIT_4_SCB_CMD_RUC();
-      }
-      else
-      {
-        printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
-        ni52_rnr_int(dev);
-      }
-    }
-
-    if(stat & STAT_CX)    /* command with I-bit set complete */
-       ni52_xmt_int(dev);
+       struct device *dev = (struct device *) irq2dev_map[irq];
+       unsigned short stat;
+       int cnt=0;
+       struct priv *p;
+
+       if (!dev) {
+               printk ("ni5210-interrupt: irq %d for unknown device.\n",irq);
+               return;
+       }
+       p = (struct priv *) dev->priv;
+
+       if(debuglevel > 1)
+               printk("I");
+
+       dev->interrupt = 1;
+
+       WAIT_4_SCB_CMD(); /* wait for last command      */
+
+       while((stat=p->scb->cus & STAT_MASK))
+       {
+               p->scb->cmd_cuc = stat;
+               ni_attn586();
+
+               if(stat & STAT_FR)       /* received a frame */
+                       ni52_rcv_int(dev);
+
+               if(stat & STAT_RNR) /* RU went 'not ready' */
+               {
+                       printk("(R)");
+                       if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+                       {
+                               WAIT_4_SCB_CMD();
+                               p->scb->cmd_ruc = RUC_RESUME;
+                               ni_attn586();
+                               WAIT_4_SCB_CMD_RUC();
+                       }
+                       else
+                       {
+                               printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+                               ni52_rnr_int(dev);
+                       }
+               }
+
+               if(stat & STAT_CX)              /* command with I-bit set complete */
+                        ni52_xmt_int(dev);
 
 #ifndef NO_NOPCOMMANDS
-    if(stat & STAT_CNA)  /* CU went 'not ready' */
-    {
-      if(dev->start)
-        printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
-    }
+               if(stat & STAT_CNA)     /* CU went 'not ready' */
+               {
+                       if(dev->start)
+                               printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+               }
 #endif
 
-    if(debuglevel > 1)
-      printk("%d",cnt++);
+               if(debuglevel > 1)
+                       printk("%d",cnt++);
 
-    WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
-    if(p->scb->cmd_cuc)   /* timed out? */
-    {
-      printk("%s: Acknowledge timed out.\n",dev->name);
-      ni_disint();
-      break;
-    }
-  }
+               WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
+               if(p->scb->cmd_cuc)      /* timed out? */
+               {
+                       printk("%s: Acknowledge timed out.\n",dev->name);
+                       ni_disint();
+                       break;
+               }
+       }
 
-  if(debuglevel > 1)
-    printk("i");
+       if(debuglevel > 1)
+               printk("i");
 
-  dev->interrupt = 0;
+       dev->interrupt = 0;
 }
 
 /*******************************************************
@@ -893,121 +896,121 @@ static void ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
 
 static void ni52_rcv_int(struct device *dev)
 {
-  int status,cnt=0;
-  unsigned short totlen;
-  struct sk_buff *skb;
-  struct rbd_struct *rbd;
-  struct priv *p = (struct priv *) dev->priv;
-
-  if(debuglevel > 0)
-    printk("R");
-
-  for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
-  {
-      rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
-
-      if(status & RFD_OK) /* frame received without error? */
-      {
-        if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */
-        {
-          totlen &= RBD_MASK; /* length of this frame */
-          rbd->status = 0;
-          skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
-          if(skb != NULL)
-          {
-            skb->dev = dev;
-            skb_reserve(skb,2);
-            skb_put(skb,totlen);
-            eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0);
-            skb->protocol=eth_type_trans(skb,dev);
-            netif_rx(skb);
-            p->stats.rx_packets++;
-          }
-          else
-            p->stats.rx_dropped++;
-        }
-        else
-        {
-          int rstat;
-             /* free all RBD's until RBD_LAST is set */
-          totlen = 0;
-          while(!((rstat=rbd->status) & RBD_LAST))
-          {
-            totlen += rstat & RBD_MASK;
-            if(!rstat)
-            {
-              printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
-              break;
-            }
-            rbd->status = 0;
-            rbd = (struct rbd_struct *) make32(rbd->next);
-          }
-          totlen += rstat & RBD_MASK;
-          rbd->status = 0;
-          printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
-          p->stats.rx_dropped++;
-       }
-      }
-      else /* frame !(ok), only with 'save-bad-frames' */
-      {
-        printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
-        p->stats.rx_errors++;
-      }
-      p->rfd_top->stat_high = 0;
-      p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
-      p->rfd_top->rbd_offset = 0xffff;
-      p->rfd_last->last = 0;        /* delete RFD_SUSP  */
-      p->rfd_last = p->rfd_top;
-      p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
-      p->scb->rfa_offset = make16(p->rfd_top);
-
-      if(debuglevel > 0)
-        printk("%d",cnt++);
-  }
-
-  if(automatic_resume)
-  {
-    WAIT_4_SCB_CMD();
-    p->scb->cmd_ruc = RUC_RESUME;
-    ni_attn586();
-    WAIT_4_SCB_CMD_RUC();
-  }
+       int status,cnt=0;
+       unsigned short totlen;
+       struct sk_buff *skb;
+       struct rbd_struct *rbd;
+       struct priv *p = (struct priv *) dev->priv;
+
+       if(debuglevel > 0)
+               printk("R");
+
+       for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+       {
+                       rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+                       if(status & RFD_OK) /* frame received without error? */
+                       {
+                               if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */
+                               {
+                                       totlen &= RBD_MASK; /* length of this frame */
+                                       rbd->status = 0;
+                                       skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+                                       if(skb != NULL)
+                                       {
+                                               skb->dev = dev;
+                                               skb_reserve(skb,2);
+                                               skb_put(skb,totlen);
+                                               eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0);
+                                               skb->protocol=eth_type_trans(skb,dev);
+                                               netif_rx(skb);
+                                               p->stats.rx_packets++;
+                                       }
+                                       else
+                                               p->stats.rx_dropped++;
+                               }
+                               else
+                               {
+                                       int rstat;
+                                                /* free all RBD's until RBD_LAST is set */
+                                       totlen = 0;
+                                       while(!((rstat=rbd->status) & RBD_LAST))
+                                       {
+                                               totlen += rstat & RBD_MASK;
+                                               if(!rstat)
+                                               {
+                                                       printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+                                                       break;
+                                               }
+                                               rbd->status = 0;
+                                               rbd = (struct rbd_struct *) make32(rbd->next);
+                                       }
+                                       totlen += rstat & RBD_MASK;
+                                       rbd->status = 0;
+                                       printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+                                       p->stats.rx_dropped++;
+                        }
+               }
+               else /* frame !(ok), only with 'save-bad-frames' */
+               {
+                       printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+                       p->stats.rx_errors++;
+               }
+               p->rfd_top->stat_high = 0;
+               p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+               p->rfd_top->rbd_offset = 0xffff;
+               p->rfd_last->last = 0;                          /* delete RFD_SUSP      */
+               p->rfd_last = p->rfd_top;
+               p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+               p->scb->rfa_offset = make16(p->rfd_top);
+
+               if(debuglevel > 0)
+                       printk("%d",cnt++);
+       }
+
+       if(automatic_resume)
+       {
+               WAIT_4_SCB_CMD();
+               p->scb->cmd_ruc = RUC_RESUME;
+               ni_attn586();
+               WAIT_4_SCB_CMD_RUC();
+       }
 
 #ifdef WAIT_4_BUSY
-  {
-    int i;
-    for(i=0;i<1024;i++)
-    {
-      if(p->rfd_top->status)
-        break;
-      DELAY_16();
-      if(i == 1023)
-        printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
-    }
-  }
+       {
+               int i;
+               for(i=0;i<1024;i++)
+               {
+                       if(p->rfd_top->status)
+                               break;
+                       DELAY_16();
+                       if(i == 1023)
+                               printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+               }
+       }
 #endif
 
 #ifdef 0
-  if(!at_least_one)
-  {
-    int i;
-    volatile struct rfd_struct *rfds=p->rfd_top;
-    volatile struct rbd_struct *rbds;
-    printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
-    for(i=0;i< (p->num_recv_buffs+4);i++)
-    {
-      rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
-      printk("%04x:%04x ",rfds->status,rbds->status);
-      rfds = (struct rfd_struct *) make32(rfds->next);
-    }
-    printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
-    printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
-  }
-  old_at_least = at_least_one;
+       if(!at_least_one)
+       {
+               int i;
+               volatile struct rfd_struct *rfds=p->rfd_top;
+               volatile struct rbd_struct *rbds;
+               printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+               for(i=0;i< (p->num_recv_buffs+4);i++)
+               {
+                       rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+                       printk("%04x:%04x ",rfds->status,rbds->status);
+                       rfds = (struct rfd_struct *) make32(rfds->next);
+               }
+               printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+               printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+       }
+       old_at_least = at_least_one;
 #endif
 
-  if(debuglevel > 0)
-    printk("r");
+       if(debuglevel > 0)
+               printk("r");
 }
 
 /**********************************************************
@@ -1016,20 +1019,20 @@ static void ni52_rcv_int(struct device *dev)
 
 static void ni52_rnr_int(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
+       struct priv *p = (struct priv *) dev->priv;
 
-  p->stats.rx_errors++;
+       p->stats.rx_errors++;
 
-  WAIT_4_SCB_CMD();    /* wait for the last cmd, WAIT_4_FULLSTAT?? */
-  p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
-  ni_attn586();
-  WAIT_4_SCB_CMD_RUC();    /* wait for accept cmd. */
+       WAIT_4_SCB_CMD();               /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+       p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+       ni_attn586();
+       WAIT_4_SCB_CMD_RUC();           /* wait for accept cmd. */
 
-  alloc_rfa(dev,(char *)p->rfd_first);
+       alloc_rfa(dev,(char *)p->rfd_first);
 /* maybe add a check here, before restarting the RU */
-  startrecv586(dev); /* restart RU */
+       startrecv586(dev); /* restart RU */
 
-  printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+       printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
 
 }
 
@@ -1039,51 +1042,51 @@ static void ni52_rnr_int(struct device *dev)
 
 static void ni52_xmt_int(struct device *dev)
 {
-  int status;
-  struct priv *p = (struct priv *) dev->priv;
-
-  if(debuglevel > 0)
-    printk("X");
-
-  status = p->xmit_cmds[p->xmit_last]->cmd_status;
-  if(!(status & STAT_COMPL))
-    printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
-
-  if(status & STAT_OK)
-  {
-    p->stats.tx_packets++;
-    p->stats.collisions += (status & TCMD_MAXCOLLMASK);
-  }
-  else
-  {
-    p->stats.tx_errors++;
-    if(status & TCMD_LATECOLL) {
-      printk("%s: late collision detected.\n",dev->name);
-      p->stats.collisions++;
-    }
-    else if(status & TCMD_NOCARRIER) {
-      p->stats.tx_carrier_errors++;
-      printk("%s: no carrier detected.\n",dev->name);
-    }
-    else if(status & TCMD_LOSTCTS)
-      printk("%s: loss of CTS detected.\n",dev->name);
-    else if(status & TCMD_UNDERRUN) {
-      p->stats.tx_fifo_errors++;
-      printk("%s: DMA underrun detected.\n",dev->name);
-    }
-    else if(status & TCMD_MAXCOLL) {
-      printk("%s: Max. collisions exceeded.\n",dev->name);
-      p->stats.collisions += 16;
-    }
-  }
+       int status;
+       struct priv *p = (struct priv *) dev->priv;
+
+       if(debuglevel > 0)
+               printk("X");
+
+       status = p->xmit_cmds[p->xmit_last]->cmd_status;
+       if(!(status & STAT_COMPL))
+               printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+       if(status & STAT_OK)
+       {
+               p->stats.tx_packets++;
+               p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+       }
+       else
+       {
+               p->stats.tx_errors++;
+               if(status & TCMD_LATECOLL) {
+                       printk("%s: late collision detected.\n",dev->name);
+                       p->stats.collisions++;
+               }
+               else if(status & TCMD_NOCARRIER) {
+                       p->stats.tx_carrier_errors++;
+                       printk("%s: no carrier detected.\n",dev->name);
+               }
+               else if(status & TCMD_LOSTCTS)
+                       printk("%s: loss of CTS detected.\n",dev->name);
+               else if(status & TCMD_UNDERRUN) {
+                       p->stats.tx_fifo_errors++;
+                       printk("%s: DMA underrun detected.\n",dev->name);
+               }
+               else if(status & TCMD_MAXCOLL) {
+                       printk("%s: Max. collisions exceeded.\n",dev->name);
+                       p->stats.collisions += 16;
+               }
+       }
 
 #if (NUM_XMIT_BUFFS > 1)
-  if( (++p->xmit_last) == NUM_XMIT_BUFFS)
-    p->xmit_last = 0;
+       if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+               p->xmit_last = 0;
 #endif
 
-  dev->tbusy = 0;
-  mark_bh(NET_BH);
+       dev->tbusy = 0;
+       mark_bh(NET_BH);
 }
 
 /***********************************************************
@@ -1092,14 +1095,14 @@ static void ni52_xmt_int(struct device *dev)
 
 static void startrecv586(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
-
-  WAIT_4_SCB_CMD();
-  WAIT_4_SCB_CMD_RUC();
-  p->scb->rfa_offset = make16(p->rfd_first);
-  p->scb->cmd_ruc = RUC_START;
-  ni_attn586();                /* start cmd. */
-  WAIT_4_SCB_CMD_RUC();        /* wait for accept cmd. (no timeout!!) */
+       struct priv *p = (struct priv *) dev->priv;
+
+       WAIT_4_SCB_CMD();
+       WAIT_4_SCB_CMD_RUC();
+       p->scb->rfa_offset = make16(p->rfd_first);
+       p->scb->cmd_ruc = RUC_START;
+       ni_attn586();           /* start cmd. */
+       WAIT_4_SCB_CMD_RUC();   /* wait for accept cmd. (no timeout!!) */
 }
 
 /******************************************************
@@ -1108,182 +1111,182 @@ static void startrecv586(struct device *dev)
 
 static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
 {
-  int len,i;
+       int len,i;
 #ifndef NO_NOPCOMMANDS
-  int next_nop;
+       int next_nop;
 #endif
-  struct priv *p = (struct priv *) dev->priv;
+       struct priv *p = (struct priv *) dev->priv;
 
-  if(dev->tbusy)
-  {
-    int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 5)
-      return 1;
+       if(dev->tbusy)
+       {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 5)
+                       return 1;
 
 #ifndef NO_NOPCOMMANDS
-    if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
-    {
-      dev->tbusy = 0;
+               if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+               {
+                       dev->tbusy = 0;
 #ifdef DEBUG
-      printk("%s: strange ... timeout with CU active?!?\n",dev->name);
-      printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
+                       printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+                       printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
 #endif
-      p->scb->cmd_cuc = CUC_ABORT;
-      ni_attn586();
-      WAIT_4_SCB_CMD();
-      p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
-      p->scb->cmd_cuc = CUC_START;
-      ni_attn586();
-      WAIT_4_SCB_CMD();
-      dev->trans_start = jiffies;
-      return 0;
-    }
-    else
+                       p->scb->cmd_cuc = CUC_ABORT;
+                       ni_attn586();
+                       WAIT_4_SCB_CMD();
+                       p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+                       p->scb->cmd_cuc = CUC_START;
+                       ni_attn586();
+                       WAIT_4_SCB_CMD();
+                       dev->trans_start = jiffies;
+                       return 0;
+               }
+               else
 #endif
-    {
+               {
 #ifdef DEBUG
-      printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
-      printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
-      printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+                       printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+                       printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
+                       printk("%s: check, whether you set the right interrupt number!\n",dev->name);
 #endif
-      ni52_close(dev);
-      ni52_open(dev);
-    }
-    dev->trans_start = jiffies;
-    return 0;
-  }
-
-  if(skb == NULL)
-  {
-    dev_tint(dev);
-    return 0;
-  }
-
-  if (skb->len <= 0)
-    return 0;
-  if(skb->len > XMIT_BUFF_SIZE)
-  {
-    printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
-    return 0;
-  }
-
-  if (set_bit(0, (void*)&dev->tbusy)) {
-    printk("%s: Transmitter access conflict.\n", dev->name);
-    return 1;
-  }
+                       ni52_close(dev);
+                       ni52_open(dev);
+               }
+               dev->trans_start = jiffies;
+               return 0;
+       }
+
+       if(skb == NULL)
+       {
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (skb->len <= 0)
+               return 0;
+       if(skb->len > XMIT_BUFF_SIZE)
+       {
+               printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+               return 0;
+       }
+
+       if (set_bit(0, (void*)&dev->tbusy)) {
+               printk("%s: Transmitter access conflict.\n", dev->name);
+               return 1;
+       }
 #if(NUM_XMIT_BUFFS > 1)
-  else if(set_bit(0,(void *) &p->lock)) {
-    printk("%s: Queue was locked\n",dev->name);
-    return 1;
-  }
+       else if(set_bit(0,(void *) &p->lock)) {
+               printk("%s: Queue was locked\n",dev->name);
+               return 1;
+       }
 #endif
-  else
-  {
-    memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
-    len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+       else
+       {
+               memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+               len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
 #if (NUM_XMIT_BUFFS == 1)
-#  ifdef NO_NOPCOMMANDS
+#      ifdef NO_NOPCOMMANDS
 
 #ifdef DEBUG
-    if(p->scb->cus & CU_ACTIVE)
-    {
-      printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
-      printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,p->xmit_cmds[0]->cmd_status);
-    }
+               if(p->scb->cus & CU_ACTIVE)
+               {
+                       printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+                       printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,p->xmit_cmds[0]->cmd_status);
+               }
 #endif
 
-    p->xmit_buffs[0]->size = TBD_LAST | len;
-    for(i=0;i<16;i++)
-    {
-      p->xmit_cmds[0]->cmd_status = 0;
-      WAIT_4_SCB_CMD();
-      if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
-        p->scb->cmd_cuc = CUC_RESUME;
-      else
-      {
-        p->scb->cbl_offset = make16(p->xmit_cmds[0]);
-        p->scb->cmd_cuc = CUC_START;
-      }
-
-      ni_attn586();
-      dev->trans_start = jiffies;
-      if(!i)
-        dev_kfree_skb(skb,FREE_WRITE);
-      WAIT_4_SCB_CMD();
-      if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
-        break;
-      if(p->xmit_cmds[0]->cmd_status)
-        break;
-      if(i==15)
-        printk("%s: Can't start transmit-command.\n",dev->name);
-    }
-#  else
-    next_nop = (p->nop_point + 1) & 0x1;
-    p->xmit_buffs[0]->size = TBD_LAST | len;
-
-    p->xmit_cmds[0]->cmd_link   = p->nop_cmds[next_nop]->cmd_link
-                                = make16((p->nop_cmds[next_nop]));
-    p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
-
-    p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
-    dev->trans_start = jiffies;
-    p->nop_point = next_nop;
-    dev_kfree_skb(skb,FREE_WRITE);
-#  endif
+               p->xmit_buffs[0]->size = TBD_LAST | len;
+               for(i=0;i<16;i++)
+               {
+                       p->xmit_cmds[0]->cmd_status = 0;
+                       WAIT_4_SCB_CMD();
+                       if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+                               p->scb->cmd_cuc = CUC_RESUME;
+                       else
+                       {
+                               p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+                               p->scb->cmd_cuc = CUC_START;
+                       }
+
+                       ni_attn586();
+                       dev->trans_start = jiffies;
+                       if(!i)
+                               dev_kfree_skb(skb,FREE_WRITE);
+                       WAIT_4_SCB_CMD();
+                       if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+                               break;
+                       if(p->xmit_cmds[0]->cmd_status)
+                               break;
+                       if(i==15)
+                               printk("%s: Can't start transmit-command.\n",dev->name);
+               }
+#      else
+               next_nop = (p->nop_point + 1) & 0x1;
+               p->xmit_buffs[0]->size = TBD_LAST | len;
+
+               p->xmit_cmds[0]->cmd_link        = p->nop_cmds[next_nop]->cmd_link
+                                                                                                                               = make16((p->nop_cmds[next_nop]));
+               p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+               p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+               dev->trans_start = jiffies;
+               p->nop_point = next_nop;
+               dev_kfree_skb(skb,FREE_WRITE);
+#      endif
 #else
-    p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
-    if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
-      next_nop = 0;
+               p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
+               if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+                       next_nop = 0;
 
-    p->xmit_cmds[p->xmit_count]->cmd_status  = 0;
+               p->xmit_cmds[p->xmit_count]->cmd_status = 0;
        /* linkpointer of xmit-command already points to next nop cmd */
-    p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
-    p->nop_cmds[next_nop]->cmd_status = 0;
-
-    p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
-    dev->trans_start = jiffies;
-    p->xmit_count = next_nop;
-
-    {
-      long flags;
-      save_flags(flags);
-      cli();
-      if(p->xmit_count != p->xmit_last)
-        dev->tbusy = 0;
-      p->lock = 0;
-      restore_flags(flags);
-    }
-    dev_kfree_skb(skb,FREE_WRITE);
+               p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+               p->nop_cmds[next_nop]->cmd_status = 0;
+
+               p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+               dev->trans_start = jiffies;
+               p->xmit_count = next_nop;
+
+               {
+                       long flags;
+                       save_flags(flags);
+                       cli();
+                       if(p->xmit_count != p->xmit_last)
+                               dev->tbusy = 0;
+                       p->lock = 0;
+                       restore_flags(flags);
+               }
+               dev_kfree_skb(skb,FREE_WRITE);
 #endif
-  }
-  return 0;
+       }
+       return 0;
 }
 
 /*******************************************
  * Someone wanna have the statistics
  */
 
-static struct enet_statistics *ni52_get_stats(struct device *dev)
+static struct net_device_stats *ni52_get_stats(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
-  unsigned short crc,aln,rsc,ovrn;
-
-  crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
-  p->scb->crc_errs = 0;
-  aln = p->scb->aln_errs;
-  p->scb->aln_errs = 0;
-  rsc = p->scb->rsc_errs;
-  p->scb->rsc_errs = 0;
-  ovrn = p->scb->ovrn_errs;
-  p->scb->ovrn_errs = 0;
-
-  p->stats.rx_crc_errors += crc;
-  p->stats.rx_fifo_errors += ovrn;
-  p->stats.rx_frame_errors += aln;
-  p->stats.rx_dropped += rsc;
-
-  return &p->stats;
+       struct priv *p = (struct priv *) dev->priv;
+       unsigned short crc,aln,rsc,ovrn;
+
+       crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
+       p->scb->crc_errs = 0;
+       aln = p->scb->aln_errs;
+       p->scb->aln_errs = 0;
+       rsc = p->scb->rsc_errs;
+       p->scb->rsc_errs = 0;
+       ovrn = p->scb->ovrn_errs;
+       p->scb->ovrn_errs = 0;
+
+       p->stats.rx_crc_errors += crc;
+       p->stats.rx_fifo_errors += ovrn;
+       p->stats.rx_frame_errors += aln;
+       p->stats.rx_dropped += rsc;
+
+       return &p->stats;
 }
 
 /********************************************************
@@ -1291,35 +1294,35 @@ static struct enet_statistics *ni52_get_stats(struct device *dev)
  */
 static void set_multicast_list(struct device *dev)
 {
-  if(!dev->start)
-  {
-    printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
-    return;
-  }
+       if(!dev->start)
+       {
+               printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
+               return;
+       }
 
-  dev->start = 0;
+       dev->start = 0;
 
-  ni_disint();
-  alloc586(dev);
-  init586(dev);
-  startrecv586(dev);
-  ni_enaint();
+       ni_disint();
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       ni_enaint();
 
-  dev->start = 1;
+       dev->start = 1;
 }
 
 #ifdef MODULE
 static struct device dev_ni52 = {
-  "        ",  /* "ni5210": device name inserted by net_init.c */
-  0, 0, 0, 0,
-  0x300, 9,   /* I/O address, IRQ */
-  0, 0, 0, NULL, ni52_probe };
+       "                               ",      /* "ni5210": device name inserted by net_init.c */
+       0, 0, 0, 0,
+       0x300, 9,        /* I/O address, IRQ */
+       0, 0, 0, NULL, ni52_probe };
 
 /* set: io,irq,memstart,memend or set it when calling insmod */
 int irq=9;
 int io=0x300;
 long memstart=0; /* e.g 0xd0000 */
-long memend=0;   /* e.g 0xd4000 */
+long memend=0;  /* e.g 0xd4000 */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -1328,25 +1331,25 @@ MODULE_PARM(memend, "l");
 
 int init_module(void)
 {
-  if(io <= 0x0 || !memend || !memstart || irq < 2) {
-    printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
-    return -ENODEV;
-  }
-  dev_ni52.irq = irq;
-  dev_ni52.base_addr = io;
-  dev_ni52.mem_end = memend;
-  dev_ni52.mem_start = memstart;
-  if (register_netdev(&dev_ni52) != 0)
-    return -EIO;
-  return 0;
+       if(io <= 0x0 || !memend || !memstart || irq < 2) {
+               printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
+               return -ENODEV;
+       }
+       dev_ni52.irq = irq;
+       dev_ni52.base_addr = io;
+       dev_ni52.mem_end = memend;
+       dev_ni52.mem_start = memstart;
+       if (register_netdev(&dev_ni52) != 0)
+               return -EIO;
+       return 0;
 }
 
 void cleanup_module(void)
 {
-  release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE);
-  kfree(dev_ni52.priv);
-  dev_ni52.priv = NULL;
-  unregister_netdev(&dev_ni52);
+       release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE);
+       kfree(dev_ni52.priv);
+       dev_ni52.priv = NULL;
+       unregister_netdev(&dev_ni52);
 }
 #endif /* MODULE */
 
@@ -1356,34 +1359,34 @@ void cleanup_module(void)
  */
 void ni52_dump(struct device *dev,void *ptr)
 {
-  struct priv *p = (struct priv *) dev->priv;
-  struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
-  int i;
-
-  p->scb->cmd_cuc = CUC_ABORT;
-  ni_attn586();
-  WAIT_4_SCB_CMD();
-  WAIT_4_SCB_CMD_RUC();
-
-  dump_cmd->cmd_status = 0;
-  dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
-  dump_cmd->dump_offset = make16((dump_cmd + 1));
-  dump_cmd->cmd_link = 0xffff;
-
-  p->scb->cbl_offset = make16(dump_cmd);
-  p->scb->cmd_cuc = CUC_START;
-  ni_attn586();
-  WAIT_4_STAT_COMPL(dump_cmd);
-
-  if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
-        printk("%s: Can't get dump information.\n",dev->name);
-
-  for(i=0;i<170;i++) {
-    printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
-    if(i % 24 == 23)
-      printk("\n");
-  }
-  printk("\n");
+       struct priv *p = (struct priv *) dev->priv;
+       struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+       int i;
+
+       p->scb->cmd_cuc = CUC_ABORT;
+       ni_attn586();
+       WAIT_4_SCB_CMD();
+       WAIT_4_SCB_CMD_RUC();
+
+       dump_cmd->cmd_status = 0;
+       dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+       dump_cmd->dump_offset = make16((dump_cmd + 1));
+       dump_cmd->cmd_link = 0xffff;
+
+       p->scb->cbl_offset = make16(dump_cmd);
+       p->scb->cmd_cuc = CUC_START;
+       ni_attn586();
+       WAIT_4_STAT_COMPL(dump_cmd);
+
+       if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+                               printk("%s: Can't get dump information.\n",dev->name);
+
+       for(i=0;i<170;i++) {
+               printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+               if(i % 24 == 23)
+                       printk("\n");
+       }
+       printk("\n");
 }
 #endif
 
index b2fc38b9ae8457dccae0eb5867ce5345ab16b45e..1cdd7b4cf6869a400bd3ad11611d5306ef6c7a0c 100644 (file)
@@ -195,27 +195,27 @@ static struct card {
 
 struct priv
 {
-  struct rmd rmdhead[RMDNUM];
-  struct tmd tmdhead[TMDNUM];
-  struct init_block ib;
-  int rmdnum;
-  int tmdnum,tmdlast;
+       struct rmd rmdhead[RMDNUM];
+       struct tmd tmdhead[TMDNUM];
+       struct init_block ib;
+       int rmdnum;
+       int tmdnum,tmdlast;
 #ifdef RCV_VIA_SKB
-  struct sk_buff *recv_skb[RMDNUM];
+       struct sk_buff *recv_skb[RMDNUM];
 #else
-  void *recvbounce[RMDNUM];
+       void *recvbounce[RMDNUM];
 #endif
 #ifdef XMT_VIA_SKB
-  struct sk_buff *tmd_skb[TMDNUM];
+       struct sk_buff *tmd_skb[TMDNUM];
 #endif
-  void *tmdbounce[TMDNUM];
-  int tmdbouncenum;
-  int lock,xmit_queued;
-  struct enet_statistics stats;
-  void *self;
-  int cmdr_addr;
-  int cardno;
-  int features;
+       void *tmdbounce[TMDNUM];
+       int tmdbouncenum;
+       int lock,xmit_queued;
+       struct net_device_stats stats;
+       void *self;
+       int cmdr_addr;
+       int cardno;
+       int features;
 };
 
 static int  ni65_probe1(struct device *dev,int);
@@ -229,7 +229,7 @@ static int  ni65_send_packet(struct sk_buff *skb, struct device *dev);
 static int  ni65_close(struct device *dev);
 static int  ni65_alloc_buffer(struct device *dev);
 static void ni65_free_buffer(struct priv *p);
-static struct enet_statistics *ni65_get_stats(struct device *);
+static struct net_device_stats *ni65_get_stats(struct device *);
 static void set_multicast_list(struct device *dev);
 
 static int irqtab[] = { 9,12,15,5 }; /* irq config-translate */
@@ -242,22 +242,22 @@ static int debuglevel = 1;
  */
 static void ni65_set_performance(struct priv *p)
 {
-  writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */
+       writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */
 
-  if( !(cards[p->cardno].config & 0x02) )
-    return;
+       if( !(cards[p->cardno].config & 0x02) )
+               return;
 
-  outw(80,PORT+L_ADDRREG);
-  if(inw(PORT+L_ADDRREG) != 80)
-    return;
+       outw(80,PORT+L_ADDRREG);
+       if(inw(PORT+L_ADDRREG) != 80)
+               return;
 
-  writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */
-  outw(0,PORT+L_ADDRREG);
-  outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */
-  outw(1,PORT+L_ADDRREG);
-  outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns  */
+       writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */
+       outw(0,PORT+L_ADDRREG);
+       outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */
+       outw(1,PORT+L_ADDRREG);
+       outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns     */
 
-  outw(CSR0,PORT+L_ADDRREG);   /* switch back to CSR0 */
+       outw(CSR0,PORT+L_ADDRREG);      /* switch back to CSR0 */
 }
 
 /*
@@ -265,31 +265,31 @@ static void ni65_set_performance(struct priv *p)
  */
 static int ni65_open(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
-  int irqval = request_irq(dev->irq, &ni65_interrupt,0,
+       struct priv *p = (struct priv *) dev->priv;
+       int irqval = request_irq(dev->irq, &ni65_interrupt,0,
                         cards[p->cardno].cardname,NULL);
-  if (irqval) {
-    printk ("%s: unable to get IRQ %d (irqval=%d).\n",
-              dev->name,dev->irq, irqval);
-    return -EAGAIN;
-  }
-  irq2dev_map[dev->irq] = dev;
-
-  if(ni65_lance_reinit(dev))
-  {
-    dev->tbusy     = 0;
-    dev->interrupt = 0;
-    dev->start     = 1;
-    MOD_INC_USE_COUNT;
-    return 0;
-  }
-  else
-  {
-    irq2dev_map[dev->irq] = NULL;
-    free_irq(dev->irq,NULL);
-    dev->start = 0;
-    return -EAGAIN;
-  }
+       if (irqval) {
+               printk ("%s: unable to get IRQ %d (irqval=%d).\n",
+                         dev->name,dev->irq, irqval);
+               return -EAGAIN;
+       }
+       irq2dev_map[dev->irq] = dev;
+
+       if(ni65_lance_reinit(dev))
+       {
+               dev->tbusy     = 0;
+               dev->interrupt = 0;
+               dev->start     = 1;
+               MOD_INC_USE_COUNT;
+               return 0;
+       }
+       else
+       {
+               irq2dev_map[dev->irq] = NULL;
+               free_irq(dev->irq,NULL);
+               dev->start = 0;
+               return -EAGAIN;
+       }
 }
 
 /*
@@ -297,28 +297,28 @@ static int ni65_open(struct device *dev)
  */
 static int ni65_close(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
+       struct priv *p = (struct priv *) dev->priv;
 
-  outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
+       outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
 
 #ifdef XMT_VIA_SKB
-  {
-    int i;
-    for(i=0;i<TMDNUM;i++)
-    {
-      if(p->tmd_skb[i]) {
-        dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
-        p->tmd_skb[i] = NULL;
-      }
-    }
-  }
+       {
+               int i;
+               for(i=0;i<TMDNUM;i++)
+               {
+                       if(p->tmd_skb[i]) {
+                               dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+                               p->tmd_skb[i] = NULL;
+                       }
+               }
+       }
 #endif
-  irq2dev_map[dev->irq] = NULL;
-  free_irq(dev->irq,NULL);
-  dev->tbusy = 1;
-  dev->start = 0;
-  MOD_DEC_USE_COUNT;
-  return 0;
+       irq2dev_map[dev->irq] = NULL;
+       free_irq(dev->irq,NULL);
+       dev->tbusy = 1;
+       dev->start = 0;
+       MOD_DEC_USE_COUNT;
+       return 0;
 }
 
 /*
@@ -329,21 +329,21 @@ static
 #endif
 int ni65_probe(struct device *dev)
 {
-  int *port;
-  static int ports[] = {0x360,0x300,0x320,0x340, 0};
+       int *port;
+       static int ports[] = {0x360,0x300,0x320,0x340, 0};
 
-  if (dev->base_addr > 0x1ff)          /* Check a single specified location. */
-     return ni65_probe1(dev, dev->base_addr);
-  else if (dev->base_addr > 0)         /* Don't probe at all. */
-     return -ENXIO;
+       if (dev->base_addr > 0x1ff)          /* Check a single specified location. */
+                return ni65_probe1(dev, dev->base_addr);
+       else if (dev->base_addr > 0)         /* Don't probe at all. */
+                return -ENXIO;
 
-  for (port = ports; *port; port++)
-  {
-    if (ni65_probe1(dev, *port) == 0)
-       return 0;
-  }
+       for (port = ports; *port; port++)
+       {
+               if (ni65_probe1(dev, *port) == 0)
+                        return 0;
+       }
 
-  return -ENODEV;
+       return -ENODEV;
 }
 
 /*
@@ -351,139 +351,139 @@ int ni65_probe(struct device *dev)
  */
 static int ni65_probe1(struct device *dev,int ioaddr)
 {
-  int i,j;
-  struct priv *p;
-
-  for(i=0;i<NUM_CARDS;i++) {
-    if(check_region(ioaddr, cards[i].total_size))
-      continue;
-    if(cards[i].id_offset >= 0) {
-      if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 ||
-         inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) {
-         continue;
-      }
-    }
-    if(cards[i].vendor_id) {
-      for(j=0;j<3;j++)
-        if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
-          continue;
-    }
-    break;
-  }
-  if(i == NUM_CARDS)
-    return -ENODEV;
-
-  for(j=0;j<6;j++)
-    dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j);
-
-  if( (j=ni65_alloc_buffer(dev)) < 0)
-    return j;
-  p = (struct priv *) dev->priv;
-  p->cmdr_addr = ioaddr + cards[i].cmd_offset;
-  p->cardno = i;
-
-  printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
-
-  outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
-  if( (j=readreg(CSR0)) != 0x4) {
-     printk(KERN_ERR "can't RESET card: %04x\n",j);
-     ni65_free_buffer(p);
-     return -EAGAIN;
-  }
-
-  outw(88,PORT+L_ADDRREG);
-  if(inw(PORT+L_ADDRREG) == 88) {
-    unsigned long v;
-    v = inw(PORT+L_DATAREG);
-    v <<= 16;
-    outw(89,PORT+L_ADDRREG);
-    v |= inw(PORT+L_DATAREG);
-    printk("Version %#08lx, ",v);
-    p->features = INIT_RING_BEFORE_START;
-  }
-  else {
-    printk("ancient LANCE, ");
-    p->features = 0x0;
-  }
-
-  if(test_bit(0,&cards[i].config)) {
-    dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3];
-    dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3];
-    printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma);
-  }
-  else {
-    if(dev->dma == 0) {
+       int i,j;
+       struct priv *p;
+
+       for(i=0;i<NUM_CARDS;i++) {
+               if(check_region(ioaddr, cards[i].total_size))
+                       continue;
+               if(cards[i].id_offset >= 0) {
+                       if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 ||
+                                inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) {
+                                continue;
+                       }
+               }
+               if(cards[i].vendor_id) {
+                       for(j=0;j<3;j++)
+                               if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
+                                       continue;
+               }
+               break;
+       }
+       if(i == NUM_CARDS)
+               return -ENODEV;
+
+       for(j=0;j<6;j++)
+               dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j);
+
+       if( (j=ni65_alloc_buffer(dev)) < 0)
+               return j;
+       p = (struct priv *) dev->priv;
+       p->cmdr_addr = ioaddr + cards[i].cmd_offset;
+       p->cardno = i;
+
+       printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
+
+       outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
+       if( (j=readreg(CSR0)) != 0x4) {
+                printk(KERN_ERR "can't RESET card: %04x\n",j);
+                ni65_free_buffer(p);
+                return -EAGAIN;
+       }
+
+       outw(88,PORT+L_ADDRREG);
+       if(inw(PORT+L_ADDRREG) == 88) {
+               unsigned long v;
+               v = inw(PORT+L_DATAREG);
+               v <<= 16;
+               outw(89,PORT+L_ADDRREG);
+               v |= inw(PORT+L_DATAREG);
+               printk("Version %#08lx, ",v);
+               p->features = INIT_RING_BEFORE_START;
+       }
+       else {
+               printk("ancient LANCE, ");
+               p->features = 0x0;
+       }
+
+       if(test_bit(0,&cards[i].config)) {
+               dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3];
+               dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3];
+               printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma);
+       }
+       else {
+               if(dev->dma == 0) {
                /* 'stuck test' from lance.c */
-      int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);
-      for(i=1;i<5;i++) {
-        int dma = dmatab[i];
-        if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
-          continue;
-        disable_dma(dma);
-        set_dma_mode(dma,DMA_MODE_CASCADE);
-        enable_dma(dma);
-        ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
-        disable_dma(dma);
-        free_dma(dma);
-        if(readreg(CSR0) & CSR0_IDON)
-          break;
-      }
-      if(i == 5) {
-        printk("Can't detect DMA channel!\n");
-        ni65_free_buffer(p);
-        return -EAGAIN;
-      }
-      dev->dma = dmatab[i];
-      printk("DMA %d (autodetected), ",dev->dma);
-    }
-    else
-      printk("DMA %d (assigned), ",dev->dma);
-
-    if(dev->irq < 2)
-    {
-      ni65_init_lance(p,dev->dev_addr,0,0);
-      autoirq_setup(0);
-      writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
-
-      if(!(dev->irq = autoirq_report(2)))
-      {
-        printk("Failed to detect IRQ line!\n");
-        ni65_free_buffer(p);
-        return -EAGAIN;
-      }
-      printk("IRQ %d (autodetected).\n",dev->irq);
-    }
-    else
-      printk("IRQ %d (assigned).\n",dev->irq);
-  }
-
-  if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)
-  {
-    printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
-    ni65_free_buffer(p);
-    return -EAGAIN;
-  }
-
-  /*
-   * Grab the region so we can find another board.
-   */
-  request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);
-
-  dev->base_addr = ioaddr;
-
-  dev->open               = ni65_open;
-  dev->stop               = ni65_close;
-  dev->hard_start_xmit    = ni65_send_packet;
-  dev->get_stats          = ni65_get_stats;
-  dev->set_multicast_list = set_multicast_list;
-
-  ether_setup(dev);
-
-  dev->interrupt      = 0;
-  dev->tbusy          = 0;
-  dev->start          = 0;
-
-  return 0; /* everything is OK */
+                       int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);
+                       for(i=1;i<5;i++) {
+                               int dma = dmatab[i];
+                               if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
+                                       continue;
+                               disable_dma(dma);
+                               set_dma_mode(dma,DMA_MODE_CASCADE);
+                               enable_dma(dma);
+                               ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
+                               disable_dma(dma);
+                               free_dma(dma);
+                               if(readreg(CSR0) & CSR0_IDON)
+                                       break;
+                       }
+                       if(i == 5) {
+                               printk("Can't detect DMA channel!\n");
+                               ni65_free_buffer(p);
+                               return -EAGAIN;
+                       }
+                       dev->dma = dmatab[i];
+                       printk("DMA %d (autodetected), ",dev->dma);
+               }
+               else
+                       printk("DMA %d (assigned), ",dev->dma);
+
+               if(dev->irq < 2)
+               {
+                       ni65_init_lance(p,dev->dev_addr,0,0);
+                       autoirq_setup(0);
+                       writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
+
+                       if(!(dev->irq = autoirq_report(2)))
+                       {
+                               printk("Failed to detect IRQ line!\n");
+                               ni65_free_buffer(p);
+                               return -EAGAIN;
+                       }
+                       printk("IRQ %d (autodetected).\n",dev->irq);
+               }
+               else
+                       printk("IRQ %d (assigned).\n",dev->irq);
+       }
+
+       if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)
+       {
+               printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
+               ni65_free_buffer(p);
+               return -EAGAIN;
+       }
+
+       /*
+        * Grab the region so we can find another board.
+        */
+       request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);
+
+       dev->base_addr = ioaddr;
+
+       dev->open               = ni65_open;
+       dev->stop               = ni65_close;
+       dev->hard_start_xmit    = ni65_send_packet;
+       dev->get_stats          = ni65_get_stats;
+       dev->set_multicast_list = set_multicast_list;
+
+       ether_setup(dev);
+
+       dev->interrupt          = 0;
+       dev->tbusy              = 0;
+       dev->start              = 0;
+
+       return 0; /* everything is OK */
 }
 
 /*
@@ -491,33 +491,33 @@ static int ni65_probe1(struct device *dev,int ioaddr)
  */
 static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int mode)
 {
-  int i;
-  u32 pib;
+       int i;
+       u32 pib;
 
-  writereg(CSR0_CLRALL|CSR0_STOP,CSR0);
+       writereg(CSR0_CLRALL|CSR0_STOP,CSR0);
 
-  for(i=0;i<6;i++)
-    p->ib.eaddr[i] = daddr[i];
+       for(i=0;i<6;i++)
+               p->ib.eaddr[i] = daddr[i];
 
-  for(i=0;i<8;i++)
-    p->ib.filter[i] = filter;
-  p->ib.mode = mode;
+       for(i=0;i<8;i++)
+               p->ib.filter[i] = filter;
+       p->ib.mode = mode;
 
-  p->ib.trp = (u32) virt_to_bus(p->tmdhead) | TMDNUMMASK;
-  p->ib.rrp = (u32) virt_to_bus(p->rmdhead) | RMDNUMMASK;
-  writereg(0,CSR3);  /* busmaster/no word-swap */
-  pib = (u32) virt_to_bus(&p->ib);
-  writereg(pib & 0xffff,CSR1);
-  writereg(pib >> 16,CSR2);
+       p->ib.trp = (u32) virt_to_bus(p->tmdhead) | TMDNUMMASK;
+       p->ib.rrp = (u32) virt_to_bus(p->rmdhead) | RMDNUMMASK;
+       writereg(0,CSR3);       /* busmaster/no word-swap */
+       pib = (u32) virt_to_bus(&p->ib);
+       writereg(pib & 0xffff,CSR1);
+       writereg(pib >> 16,CSR2);
 
-  writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
+       writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
 
-  for(i=0;i<32;i++)
-  {
-    udelay(4000);
-    if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )
-      break; /* init ok ? */
-  }
+       for(i=0;i<32;i++)
+       {
+               udelay(4000);
+               if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )
+                       break; /* init ok ? */
+       }
 }
 
 /*
@@ -525,37 +525,37 @@ static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int m
  */
 static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type)
 {
-  struct sk_buff *skb=NULL;
-  unsigned char *ptr;
-  void *ret;
-
-  if(type) {
-    ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);
-    if(!skb) {
-      printk("%s: unable to allocate %s memory.\n",dev->name,what);
-      return NULL;
-    }
-    skb->dev = dev;
-    skb_reserve(skb,2+16);
-    skb_put(skb,R_BUF_SIZE);   /* grab the whole space .. (not necessary) */
-    ptr = skb->data;
-  }
-  else {
-    ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);
-    if(!ret) {
-      printk("%s: unable to allocate %s memory.\n",dev->name,what);
-      return NULL;
-    }
-  }
-  if( (u32) virt_to_bus(ptr+size) > 0x1000000) {
-    printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
-    if(type)
-      kfree_skb(skb,FREE_WRITE);
-    else
-      kfree(ptr);
-    return NULL;
-  }
-  return ret;
+       struct sk_buff *skb=NULL;
+       unsigned char *ptr;
+       void *ret;
+
+       if(type) {
+               ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);
+               if(!skb) {
+                       printk("%s: unable to allocate %s memory.\n",dev->name,what);
+                       return NULL;
+               }
+               skb->dev = dev;
+               skb_reserve(skb,2+16);
+               skb_put(skb,R_BUF_SIZE);         /* grab the whole space .. (not necessary) */
+               ptr = skb->data;
+       }
+       else {
+               ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);
+               if(!ret) {
+                       printk("%s: unable to allocate %s memory.\n",dev->name,what);
+                       return NULL;
+               }
+       }
+       if( (u32) virt_to_bus(ptr+size) > 0x1000000) {
+               printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
+               if(type)
+                       kfree_skb(skb,FREE_WRITE);
+               else
+                       kfree(ptr);
+               return NULL;
+       }
+       return ret;
 }
 
 /*
@@ -563,51 +563,51 @@ static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type)
  */
 static int ni65_alloc_buffer(struct device *dev)
 {
-  unsigned char *ptr;
-  struct priv *p;
-  int i;
-
-  /*
-   * we need 8-aligned memory ..
-   */
-  ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0);
-  if(!ptr)
-    return -ENOMEM;
-
-  p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
-  memset((char *) dev->priv,0,sizeof(struct priv));
-  p->self = ptr;
-
-  for(i=0;i<TMDNUM;i++)
-  {
+       unsigned char *ptr;
+       struct priv *p;
+       int i;
+
+       /*
+        * we need 8-aligned memory ..
+        */
+       ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0);
+       if(!ptr)
+               return -ENOMEM;
+
+       p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
+       memset((char *) dev->priv,0,sizeof(struct priv));
+       p->self = ptr;
+
+       for(i=0;i<TMDNUM;i++)
+       {
 #ifdef XMT_VIA_SKB
-    p->tmd_skb[i] = NULL;
+               p->tmd_skb[i] = NULL;
 #endif
-    p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0);
-    if(!p->tmdbounce[i]) {
-      ni65_free_buffer(p);
-      return -ENOMEM;
-    }
-  }
-
-  for(i=0;i<RMDNUM;i++)
-  {
+               p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0);
+               if(!p->tmdbounce[i]) {
+                       ni65_free_buffer(p);
+                       return -ENOMEM;
+               }
+       }
+
+       for(i=0;i<RMDNUM;i++)
+       {
 #ifdef RCV_VIA_SKB
-    p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1);
-    if(!p->recv_skb[i]) {
-      ni65_free_buffer(p);
-      return -ENOMEM;
-    }
+               p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1);
+               if(!p->recv_skb[i]) {
+                       ni65_free_buffer(p);
+                       return -ENOMEM;
+               }
 #else
-    p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0);
-    if(!p->recvbounce[i]) {
-      ni65_free_buffer(p);
-      return -ENOMEM;
-    }
+               p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0);
+               if(!p->recvbounce[i]) {
+                       ni65_free_buffer(p);
+                       return -ENOMEM;
+               }
 #endif
-  }
+       }
 
-  return 0; /* everything is OK */
+       return 0; /* everything is OK */
 }
 
 /*
@@ -615,32 +615,32 @@ static int ni65_alloc_buffer(struct device *dev)
  */
 static void ni65_free_buffer(struct priv *p)
 {
-  int i;
+       int i;
 
-  if(!p)
-    return;
+       if(!p)
+               return;
 
-  for(i=0;i<TMDNUM;i++) {
-    if(p->tmdbounce[i])
-      kfree(p->tmdbounce[i]);
+       for(i=0;i<TMDNUM;i++) {
+               if(p->tmdbounce[i])
+                       kfree(p->tmdbounce[i]);
 #ifdef XMT_VIA_SKB
-    if(p->tmd_skb[i])
-      dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+               if(p->tmd_skb[i])
+                       dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
 #endif
-  }
+       }
 
-  for(i=0;i<RMDNUM;i++)
-  {
+       for(i=0;i<RMDNUM;i++)
+       {
 #ifdef RCV_VIA_SKB
-    if(p->recv_skb[i])
-      dev_kfree_skb(p->recv_skb[i],FREE_WRITE);
+               if(p->recv_skb[i])
+                       dev_kfree_skb(p->recv_skb[i],FREE_WRITE);
 #else
-    if(p->recvbounce[i])
-      kfree(p->recvbounce[i]);
+               if(p->recvbounce[i])
+                       kfree(p->recvbounce[i]);
 #endif
-  }
-  if(p->self)
-    kfree(p->self);
+       }
+       if(p->self)
+               kfree(p->self);
 }
 
 
@@ -649,68 +649,68 @@ static void ni65_free_buffer(struct priv *p)
  */
 static void ni65_stop_start(struct device *dev,struct priv *p)
 {
-  int csr0 = CSR0_INEA;
+       int csr0 = CSR0_INEA;
 
-  writedatareg(CSR0_STOP);
+       writedatareg(CSR0_STOP);
 
-  if(debuglevel > 1)
-    printk("ni65_stop_start\n");
+       if(debuglevel > 1)
+               printk("ni65_stop_start\n");
 
-  if(p->features & INIT_RING_BEFORE_START) {
-    int i;
+       if(p->features & INIT_RING_BEFORE_START) {
+               int i;
 #ifdef XMT_VIA_SKB
-    struct sk_buff *skb_save[TMDNUM];
+               struct sk_buff *skb_save[TMDNUM];
 #endif
-    unsigned long buffer[TMDNUM];
-    short blen[TMDNUM];
-
-    if(p->xmit_queued) {
-      while(1) {
-        if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN))
-          break;
-        p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
-        if(p->tmdlast == p->tmdnum)
-          break;
-      }
-    }
-
-    for(i=0;i<TMDNUM;i++) {
-      struct tmd *tmdp = p->tmdhead + i;
+               unsigned long buffer[TMDNUM];
+               short blen[TMDNUM];
+
+               if(p->xmit_queued) {
+                       while(1) {
+                               if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN))
+                                       break;
+                               p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
+                               if(p->tmdlast == p->tmdnum)
+                                       break;
+                       }
+               }
+
+               for(i=0;i<TMDNUM;i++) {
+                       struct tmd *tmdp = p->tmdhead + i;
 #ifdef XMT_VIA_SKB
-      skb_save[i] = p->tmd_skb[i];
+                       skb_save[i] = p->tmd_skb[i];
 #endif
-      buffer[i] = (u32) bus_to_virt(tmdp->u.buffer);
-      blen[i] = tmdp->blen;
-      tmdp->u.s.status = 0x0;
-    }
-
-    for(i=0;i<RMDNUM;i++) {
-      struct rmd *rmdp = p->rmdhead + i;
-      rmdp->u.s.status = RCV_OWN;
-    }
-    p->tmdnum = p->xmit_queued = 0;
-    writedatareg(CSR0_STRT | csr0);
-
-    for(i=0;i<TMDNUM;i++) {
-      int num = (i + p->tmdlast) & (TMDNUM-1);
-      p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */
-      p->tmdhead[i].blen = blen[num];
-      if(p->tmdhead[i].u.s.status & XMIT_OWN) {
-         p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
-         p->xmit_queued = 1;
+                       buffer[i] = (u32) bus_to_virt(tmdp->u.buffer);
+                       blen[i] = tmdp->blen;
+                       tmdp->u.s.status = 0x0;
+               }
+
+               for(i=0;i<RMDNUM;i++) {
+                       struct rmd *rmdp = p->rmdhead + i;
+                       rmdp->u.s.status = RCV_OWN;
+               }
+               p->tmdnum = p->xmit_queued = 0;
+               writedatareg(CSR0_STRT | csr0);
+
+               for(i=0;i<TMDNUM;i++) {
+                       int num = (i + p->tmdlast) & (TMDNUM-1);
+                       p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */
+                       p->tmdhead[i].blen = blen[num];
+                       if(p->tmdhead[i].u.s.status & XMIT_OWN) {
+                                p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
+                                p->xmit_queued = 1;
         writedatareg(CSR0_TDMD | CSR0_INEA | csr0);
-      }
+                       }
 #ifdef XMT_VIA_SKB
-      p->tmd_skb[i] = skb_save[num];
+                       p->tmd_skb[i] = skb_save[num];
 #endif
-    }
-    p->rmdnum = p->tmdlast = 0;
-    if(!p->lock)
-      dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
-    dev->trans_start = jiffies;
-  }
-  else
-    writedatareg(CSR0_STRT | csr0);
+               }
+               p->rmdnum = p->tmdlast = 0;
+               if(!p->lock)
+                       dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
+               dev->trans_start = jiffies;
+       }
+       else
+               writedatareg(CSR0_STRT | csr0);
 }
 
 /*
@@ -718,74 +718,74 @@ static void ni65_stop_start(struct device *dev,struct priv *p)
  */
 static int ni65_lance_reinit(struct device *dev)
 {
-   int i;
-   struct priv *p = (struct priv *) dev->priv;
-
-   p->lock = 0;
-   p->xmit_queued = 0;
-
-   disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */
-   set_dma_mode(dev->dma,DMA_MODE_CASCADE);
-   enable_dma(dev->dma);
-
-   outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
-   if( (i=readreg(CSR0) ) != 0x4)
-   {
-     printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,
-              cards[p->cardno].cardname,(int) i);
-     disable_dma(dev->dma);
-     return 0;
-   }
-
-   p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0;
-   for(i=0;i<TMDNUM;i++)
-   {
-     struct tmd *tmdp = p->tmdhead + i;
+        int i;
+        struct priv *p = (struct priv *) dev->priv;
+
+        p->lock = 0;
+        p->xmit_queued = 0;
+
+        disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */
+        set_dma_mode(dev->dma,DMA_MODE_CASCADE);
+        enable_dma(dev->dma);
+
+        outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
+        if( (i=readreg(CSR0) ) != 0x4)
+        {
+                printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,
+                                                       cards[p->cardno].cardname,(int) i);
+                disable_dma(dev->dma);
+                return 0;
+        }
+
+        p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0;
+        for(i=0;i<TMDNUM;i++)
+        {
+                struct tmd *tmdp = p->tmdhead + i;
 #ifdef XMT_VIA_SKB
-     if(p->tmd_skb[i]) {
-       dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
-       p->tmd_skb[i] = NULL;
-     }
+                if(p->tmd_skb[i]) {
+                        dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+                        p->tmd_skb[i] = NULL;
+                }
 #endif
-     tmdp->u.buffer = 0x0;
-     tmdp->u.s.status = XMIT_START | XMIT_END;
-     tmdp->blen = tmdp->status2 = 0;
-   }
-
-   for(i=0;i<RMDNUM;i++)
-   {
-     struct rmd *rmdp = p->rmdhead + i;
+                tmdp->u.buffer = 0x0;
+                tmdp->u.s.status = XMIT_START | XMIT_END;
+                tmdp->blen = tmdp->status2 = 0;
+        }
+
+        for(i=0;i<RMDNUM;i++)
+        {
+                struct rmd *rmdp = p->rmdhead + i;
 #ifdef RCV_VIA_SKB
-     rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data);
+                rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data);
 #else
-     rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]);
+                rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]);
 #endif
-     rmdp->blen = -(R_BUF_SIZE-8);
-     rmdp->mlen = 0;
-     rmdp->u.s.status = RCV_OWN;
-   }
-
-   if(dev->flags & IFF_PROMISC)
-     ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);
-   else if(dev->mc_count || dev->flags & IFF_ALLMULTI)
-     ni65_init_lance(p,dev->dev_addr,0xff,0x0);
-   else
-     ni65_init_lance(p,dev->dev_addr,0x00,0x00);
-
-  /*
-   * ni65_set_lance_mem() sets L_ADDRREG to CSR0
-   * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED
-   */
-
-   if(inw(PORT+L_DATAREG) & CSR0_IDON)  {
-     ni65_set_performance(p);
-           /* init OK: start lance , enable interrupts */
-     writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT);
-     return 1; /* ->OK */
-   }
-   printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
-   disable_dma(dev->dma);
-   return 0; /* ->Error */
+                rmdp->blen = -(R_BUF_SIZE-8);
+                rmdp->mlen = 0;
+                rmdp->u.s.status = RCV_OWN;
+        }
+
+        if(dev->flags & IFF_PROMISC)
+                ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);
+        else if(dev->mc_count || dev->flags & IFF_ALLMULTI)
+                ni65_init_lance(p,dev->dev_addr,0xff,0x0);
+        else
+                ni65_init_lance(p,dev->dev_addr,0x00,0x00);
+
+       /*
+        * ni65_set_lance_mem() sets L_ADDRREG to CSR0
+        * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED
+        */
+
+        if(inw(PORT+L_DATAREG) & CSR0_IDON)    {
+                ni65_set_performance(p);
+                                        /* init OK: start lance , enable interrupts */
+                writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT);
+                return 1; /* ->OK */
+        }
+        printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
+        disable_dma(dev->dma);
+        return 0; /* ->Error */
 }
 
 /*
@@ -793,117 +793,117 @@ static int ni65_lance_reinit(struct device *dev)
  */
 static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 {
-  int csr0;
-  struct device *dev = (struct device *) irq2dev_map[irq];
-  struct priv *p;
-  int bcnt = 32;
+       int csr0;
+       struct device *dev = (struct device *) irq2dev_map[irq];
+       struct priv *p;
+       int bcnt = 32;
 
-  if (dev == NULL) {
-    printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
-    return;
-  }
+       if (dev == NULL) {
+               printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
 
-  if(set_bit(0,(int *) &dev->interrupt)) {
-    printk("ni65: oops .. interrupt while proceeding interrupt\n");
-    return;
-  }
-  p = (struct priv *) dev->priv;
+       if(set_bit(0,(int *) &dev->interrupt)) {
+               printk("ni65: oops .. interrupt while proceeding interrupt\n");
+               return;
+       }
+       p = (struct priv *) dev->priv;
 
-  while(--bcnt) {
-    csr0 = inw(PORT+L_DATAREG);
+       while(--bcnt) {
+               csr0 = inw(PORT+L_DATAREG);
 
 #if 0
-    writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */
+               writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */
 #else
-    writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */
+               writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */
 #endif
 
-    if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT)))
-      break;
-
-    if(csr0 & CSR0_RINT) /* RECV-int? */
-      ni65_recv_intr(dev,csr0);
-    if(csr0 & CSR0_TINT) /* XMIT-int? */
-      ni65_xmit_intr(dev,csr0);
-
-    if(csr0 & CSR0_ERR)
-    {
-      struct priv *p = (struct priv *) dev->priv;
-      if(debuglevel > 1)
-        printk("%s: general error: %04x.\n",dev->name,csr0);
-      if(csr0 & CSR0_BABL)
-        p->stats.tx_errors++;
-      if(csr0 & CSR0_MISS) {
-        int i;
-        for(i=0;i<RMDNUM;i++)
-          printk("%02x ",p->rmdhead[i].u.s.status);
-        printk("\n");
-        p->stats.rx_errors++;
-      }
-      if(csr0 & CSR0_MERR) {
-        if(debuglevel > 1)
-          printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
-        ni65_stop_start(dev,p);
-      }
-    }
-  }
+               if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT)))
+                       break;
+
+               if(csr0 & CSR0_RINT) /* RECV-int? */
+                       ni65_recv_intr(dev,csr0);
+               if(csr0 & CSR0_TINT) /* XMIT-int? */
+                       ni65_xmit_intr(dev,csr0);
+
+               if(csr0 & CSR0_ERR)
+               {
+                       struct priv *p = (struct priv *) dev->priv;
+                       if(debuglevel > 1)
+                               printk("%s: general error: %04x.\n",dev->name,csr0);
+                       if(csr0 & CSR0_BABL)
+                               p->stats.tx_errors++;
+                       if(csr0 & CSR0_MISS) {
+                               int i;
+                               for(i=0;i<RMDNUM;i++)
+                                       printk("%02x ",p->rmdhead[i].u.s.status);
+                               printk("\n");
+                               p->stats.rx_errors++;
+                       }
+                       if(csr0 & CSR0_MERR) {
+                               if(debuglevel > 1)
+                                       printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
+                               ni65_stop_start(dev,p);
+                       }
+               }
+       }
 
 #ifdef RCV_PARANOIA_CHECK
 {
  int j;
  for(j=0;j<RMDNUM;j++)
  {
-  struct priv *p = (struct priv *) dev->priv;
-  int i,k,num1,num2;
-  for(i=RMDNUM-1;i>0;i--) {
-     num2 = (p->rmdnum + i) & (RMDNUM-1);
-     if(!(p->rmdhead[num2].u.s.status & RCV_OWN))
-        break;
-  }
-
-  if(i) {
-    for(k=0;k<RMDNUM;k++) {
-      num1 = (p->rmdnum + k) & (RMDNUM-1);
-      if(!(p->rmdhead[num1].u.s.status & RCV_OWN))
-        break;
-    }
-    if(!k)
-      break;
-
-    if(debuglevel > 0)
-    {
-      char buf[256],*buf1;
-      int k;
-      buf1 = buf;
-      for(k=0;k<RMDNUM;k++) {
-        sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */
-        buf1 += 3;
-      }
-      *buf1 = 0;
-      printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf);
-    }
-
-    p->rmdnum = num1;
-    ni65_recv_intr(dev,csr0);
-    if((p->rmdhead[num2].u.s.status & RCV_OWN))
-      break;   /* ok, we are 'in sync' again */
-  }
-  else
-    break;
+       struct priv *p = (struct priv *) dev->priv;
+       int i,k,num1,num2;
+       for(i=RMDNUM-1;i>0;i--) {
+                num2 = (p->rmdnum + i) & (RMDNUM-1);
+                if(!(p->rmdhead[num2].u.s.status & RCV_OWN))
+                               break;
+       }
+
+       if(i) {
+               for(k=0;k<RMDNUM;k++) {
+                       num1 = (p->rmdnum + k) & (RMDNUM-1);
+                       if(!(p->rmdhead[num1].u.s.status & RCV_OWN))
+                               break;
+               }
+               if(!k)
+                       break;
+
+               if(debuglevel > 0)
+               {
+                       char buf[256],*buf1;
+                       int k;
+                       buf1 = buf;
+                       for(k=0;k<RMDNUM;k++) {
+                               sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */
+                               buf1 += 3;
+                       }
+                       *buf1 = 0;
+                       printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf);
+               }
+
+               p->rmdnum = num1;
+               ni65_recv_intr(dev,csr0);
+               if((p->rmdhead[num2].u.s.status & RCV_OWN))
+                       break;  /* ok, we are 'in sync' again */
+       }
+       else
+               break;
  }
 }
 #endif
 
-  if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) {
-    printk("%s: RX or TX was offline -> restart\n",dev->name);
-    ni65_stop_start(dev,p);
-  }
-  else
-    writedatareg(CSR0_INEA);
+       if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) {
+               printk("%s: RX or TX was offline -> restart\n",dev->name);
+               ni65_stop_start(dev,p);
+       }
+       else
+               writedatareg(CSR0_INEA);
 
-  dev->interrupt = 0;
+       dev->interrupt = 0;
 
-  return;
+       return;
 }
 
 /*
@@ -912,62 +912,62 @@ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
  */
 static void ni65_xmit_intr(struct device *dev,int csr0)
 {
-  struct priv *p = (struct priv *) dev->priv;
+       struct priv *p = (struct priv *) dev->priv;
 
-  while(p->xmit_queued)
-  {
-    struct tmd *tmdp = p->tmdhead + p->tmdlast;
-    int tmdstat = tmdp->u.s.status;
+       while(p->xmit_queued)
+       {
+               struct tmd *tmdp = p->tmdhead + p->tmdlast;
+               int tmdstat = tmdp->u.s.status;
 
-    if(tmdstat & XMIT_OWN)
-      break;
+               if(tmdstat & XMIT_OWN)
+                       break;
 
-    if(tmdstat & XMIT_ERR)
-    {
+               if(tmdstat & XMIT_ERR)
+               {
 #if 0
-      if(tmdp->status2 & XMIT_TDRMASK && debuglevel > 3)
-        printk(KERN_ERR "%s: tdr-problems (e.g. no resistor)\n",dev->name);
+                       if(tmdp->status2 & XMIT_TDRMASK && debuglevel > 3)
+                               printk(KERN_ERR "%s: tdr-problems (e.g. no resistor)\n",dev->name);
 #endif
-     /* checking some errors */
-      if(tmdp->status2 & XMIT_RTRY)
-        p->stats.tx_aborted_errors++;
-      if(tmdp->status2 & XMIT_LCAR)
-        p->stats.tx_carrier_errors++;
-      if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) {
+                /* checking some errors */
+                       if(tmdp->status2 & XMIT_RTRY)
+                               p->stats.tx_aborted_errors++;
+                       if(tmdp->status2 & XMIT_LCAR)
+                               p->stats.tx_carrier_errors++;
+                       if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) {
                /* this stops the xmitter */
-        p->stats.tx_fifo_errors++;
-        if(debuglevel > 0)
-          printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name);
-        if(p->features & INIT_RING_BEFORE_START) {
-          tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; /* test: resend this frame */
-          ni65_stop_start(dev,p);
-          break;       /* no more Xmit processing .. */
-        }
-        else
-         ni65_stop_start(dev,p);
-      }
-      if(debuglevel > 2)
-        printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2);
-      if(!(csr0 & CSR0_BABL)) /* don't count errors twice */
-        p->stats.tx_errors++;
-      tmdp->status2 = 0;
-    }
-    else
-      p->stats.tx_packets++;
+                               p->stats.tx_fifo_errors++;
+                               if(debuglevel > 0)
+                                       printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name);
+                               if(p->features & INIT_RING_BEFORE_START) {
+                                       tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;    /* test: resend this frame */
+                                       ni65_stop_start(dev,p);
+                                       break;  /* no more Xmit processing .. */
+                               }
+                               else
+                                ni65_stop_start(dev,p);
+                       }
+                       if(debuglevel > 2)
+                               printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2);
+                       if(!(csr0 & CSR0_BABL)) /* don't count errors twice */
+                               p->stats.tx_errors++;
+                       tmdp->status2 = 0;
+               }
+               else
+                       p->stats.tx_packets++;
 
 #ifdef XMT_VIA_SKB
-    if(p->tmd_skb[p->tmdlast]) {
-       dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
-       p->tmd_skb[p->tmdlast] = NULL;
-    }
+               if(p->tmd_skb[p->tmdlast]) {
+                        dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
+                        p->tmd_skb[p->tmdlast] = NULL;
+               }
 #endif
 
-    p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
-    if(p->tmdlast == p->tmdnum)
-      p->xmit_queued = 0;
-  }
-  dev->tbusy = 0;
-  mark_bh(NET_BH);
+               p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
+               if(p->tmdlast == p->tmdnum)
+                       p->xmit_queued = 0;
+       }
+       dev->tbusy = 0;
+       mark_bh(NET_BH);
 }
 
 /*
@@ -975,90 +975,90 @@ static void ni65_xmit_intr(struct device *dev,int csr0)
  */
 static void ni65_recv_intr(struct device *dev,int csr0)
 {
-  struct rmd *rmdp;
-  int rmdstat,len;
-  int cnt=0;
-  struct priv *p = (struct priv *) dev->priv;
-
-  rmdp = p->rmdhead + p->rmdnum;
-  while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
-  {
-    cnt++;
-    if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */
-    {
-      if(!(rmdstat & RCV_ERR)) {
-        if(rmdstat & RCV_START)
-        {
-          p->stats.rx_length_errors++;
-          printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff);
-        }
-      }
-      else {
-        if(debuglevel > 2)
-          printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n",
-                  dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) );
-        if(rmdstat & RCV_FRAM)
-          p->stats.rx_frame_errors++;
-        if(rmdstat & RCV_OFLO)
-          p->stats.rx_over_errors++;
-        if(rmdstat & RCV_CRC)
-          p->stats.rx_crc_errors++;
-        if(rmdstat & RCV_BUF_ERR)
-          p->stats.rx_fifo_errors++;
-      }
-      if(!(csr0 & CSR0_MISS)) /* don't count errors twice */
-        p->stats.rx_errors++;
-    }
-    else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60)
-    {
+       struct rmd *rmdp;
+       int rmdstat,len;
+       int cnt=0;
+       struct priv *p = (struct priv *) dev->priv;
+
+       rmdp = p->rmdhead + p->rmdnum;
+       while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
+       {
+               cnt++;
+               if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */
+               {
+                       if(!(rmdstat & RCV_ERR)) {
+                               if(rmdstat & RCV_START)
+                               {
+                                       p->stats.rx_length_errors++;
+                                       printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff);
+                               }
+                       }
+                       else {
+                               if(debuglevel > 2)
+                                       printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n",
+                                                                       dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) );
+                               if(rmdstat & RCV_FRAM)
+                                       p->stats.rx_frame_errors++;
+                               if(rmdstat & RCV_OFLO)
+                                       p->stats.rx_over_errors++;
+                               if(rmdstat & RCV_CRC)
+                                       p->stats.rx_crc_errors++;
+                               if(rmdstat & RCV_BUF_ERR)
+                                       p->stats.rx_fifo_errors++;
+                       }
+                       if(!(csr0 & CSR0_MISS)) /* don't count errors twice */
+                               p->stats.rx_errors++;
+               }
+               else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60)
+               {
 #ifdef RCV_VIA_SKB
-      struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC);
-      if (skb)
-        skb_reserve(skb,16);
+                       struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC);
+                       if (skb)
+                               skb_reserve(skb,16);
 #else
-      struct sk_buff *skb = dev_alloc_skb(len+2);
+                       struct sk_buff *skb = dev_alloc_skb(len+2);
 #endif
-      if(skb)
-      {
-        skb_reserve(skb,2);
+                       if(skb)
+                       {
+                               skb_reserve(skb,2);
        skb->dev = dev;
 #ifdef RCV_VIA_SKB
-        if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) {
-          skb_put(skb,len);
-          eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0);
-        }
-        else {
-          struct sk_buff *skb1 = p->recv_skb[p->rmdnum];
-          skb_put(skb,R_BUF_SIZE);
-          p->recv_skb[p->rmdnum] = skb;
-          rmdp->u.buffer = (u32) virt_to_bus(skb->data);
-          skb = skb1;
-          skb_trim(skb,len);
-        }
+                               if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) {
+                                       skb_put(skb,len);
+                                       eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0);
+                               }
+                               else {
+                                       struct sk_buff *skb1 = p->recv_skb[p->rmdnum];
+                                       skb_put(skb,R_BUF_SIZE);
+                                       p->recv_skb[p->rmdnum] = skb;
+                                       rmdp->u.buffer = (u32) virt_to_bus(skb->data);
+                                       skb = skb1;
+                                       skb_trim(skb,len);
+                               }
 #else
-        skb_put(skb,len);
-        eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
+                               skb_put(skb,len);
+                               eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
 #endif
-        p->stats.rx_packets++;
-        skb->protocol=eth_type_trans(skb,dev);
-        netif_rx(skb);
-      }
-      else
-      {
-        printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name);
-        p->stats.rx_dropped++;
-      }
-    }
-    else {
-      printk(KERN_INFO "%s: received runt packet\n",dev->name);
-      p->stats.rx_errors++;
-    }
-    rmdp->blen = -(R_BUF_SIZE-8);
-    rmdp->mlen = 0;
-    rmdp->u.s.status = RCV_OWN; /* change owner */
-    p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1);
-    rmdp = p->rmdhead + p->rmdnum;
-  }
+                               p->stats.rx_packets++;
+                               skb->protocol=eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                       }
+                       else
+                       {
+                               printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name);
+                               p->stats.rx_dropped++;
+                       }
+               }
+               else {
+                       printk(KERN_INFO "%s: received runt packet\n",dev->name);
+                       p->stats.rx_errors++;
+               }
+               rmdp->blen = -(R_BUF_SIZE-8);
+               rmdp->mlen = 0;
+               rmdp->u.s.status = RCV_OWN; /* change owner */
+               p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1);
+               rmdp = p->rmdhead + p->rmdnum;
+       }
 }
 
 /*
@@ -1066,106 +1066,99 @@ static void ni65_recv_intr(struct device *dev,int csr0)
  */
 static int ni65_send_packet(struct sk_buff *skb, struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
-
-  if(dev->tbusy)
-  {
-    int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 50)
-      return 1;
-
-    printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
-{
-  int i;
-  for(i=0;i<TMDNUM;i++)
-    printk("%02x ",p->tmdhead[i].u.s.status);
-  printk("\n");
-}
-    ni65_lance_reinit(dev);
-    dev->tbusy=0;
-    dev->trans_start = jiffies;
-  }
-
-  if(skb == NULL) {
-    dev_tint(dev);
-    return 0;
-  }
-
-  if (skb->len <= 0)
-    return 0;
-
-  if (set_bit(0, (void*)&dev->tbusy) != 0) {
-     printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
-     return 1;
-  }
-  if (set_bit(0, (void*)&p->lock)) {
-       printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
-       return 1;
-  }
-
-  {
-    short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-    struct tmd *tmdp;
-    long flags;
+       struct priv *p = (struct priv *) dev->priv;
+
+       if(dev->tbusy)
+       {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 50)
+                       return 1;
+
+               printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
+               {
+                       int i;
+                       for(i=0;i<TMDNUM;i++)
+                               printk("%02x ",p->tmdhead[i].u.s.status);
+                       printk("\n");
+               }
+               ni65_lance_reinit(dev);
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+       }
+
+       if (set_bit(0, (void*)&dev->tbusy) != 0) {
+                printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
+                return 1;
+       }
+       if (set_bit(0, (void*)&p->lock)) {
+               printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
+               return 1;
+       }
+
+       {
+               short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+               struct tmd *tmdp;
+               long flags;
 
 #ifdef XMT_VIA_SKB
-    if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
+               if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
 #endif
 
-      memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
-               (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
-      dev_kfree_skb (skb, FREE_WRITE);
+                       memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
+                                                        (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
+                       dev_kfree_skb (skb, FREE_WRITE);
 
-      save_flags(flags);
-      cli();
+                       save_flags(flags);
+                       cli();
 
-      tmdp = p->tmdhead + p->tmdnum;
-      tmdp->u.buffer = (u32) virt_to_bus(p->tmdbounce[p->tmdbouncenum]);
-      p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);
+                       tmdp = p->tmdhead + p->tmdnum;
+                       tmdp->u.buffer = (u32) virt_to_bus(p->tmdbounce[p->tmdbouncenum]);
+                       p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);
 
 #ifdef XMT_VIA_SKB
-    }
-    else {
-      save_flags(flags);
-      cli();
-
-      tmdp = p->tmdhead + p->tmdnum;
-      tmdp->u.buffer = (u32) virt_to_bus(skb->data);
-      p->tmd_skb[p->tmdnum] = skb;
-    }
+               }
+               else {
+                       save_flags(flags);
+                       cli();
+
+                       tmdp = p->tmdhead + p->tmdnum;
+                       tmdp->u.buffer = (u32) virt_to_bus(skb->data);
+                       p->tmd_skb[p->tmdnum] = skb;
+               }
 #endif
-    tmdp->blen = -len;
+               tmdp->blen = -len;
 
-    tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;
-    writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */
+               tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;
+               writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */
 
-    p->xmit_queued = 1;
-    p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
+               p->xmit_queued = 1;
+               p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
 
-    dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
-    p->lock = 0;
-    dev->trans_start = jiffies;
+               dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
+               p->lock = 0;
+               dev->trans_start = jiffies;
 
-    restore_flags(flags);
-  }
+               restore_flags(flags);
+       }
 
-  return 0;
+       return 0;
 }
 
-static struct enet_statistics *ni65_get_stats(struct device *dev)
+static struct net_device_stats *ni65_get_stats(struct device *dev)
 {
 
 #if 0
- int i;
- struct priv *p = (struct priv *) dev->priv;
- for(i=0;i<RMDNUM;i++) {
-   struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1));
-   printk("%02x ",rmdp->u.s.status);
- }
- printk("\n");
+       int i;
+       struct priv *p = (struct priv *) dev->priv;
+       for(i=0;i<RMDNUM;i++)
+       {
+               struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1));
+               printk("%02x ",rmdp->u.s.status);
+       }
+       printk("\n");
 #endif
 
-  return &((struct priv *) dev->priv)->stats;
+       return &((struct priv *) dev->priv)->stats;
 }
 
 static void set_multicast_list(struct device *dev)
@@ -1177,10 +1170,10 @@ static void set_multicast_list(struct device *dev)
 
 #ifdef MODULE
 static struct device dev_ni65 = {
-  "        ",  /* "ni6510": device name inserted by net_init.c */
-  0, 0, 0, 0,
-  0x360, 9,   /* I/O address, IRQ */
-  0, 0, 0, NULL, ni65_probe };
+       "                               ",      /* "ni6510": device name inserted by net_init.c */
+       0, 0, 0, 0,
+       0x360, 9,        /* I/O address, IRQ */
+       0, 0, 0, NULL, ni65_probe };
 
 /* set: io,irq,dma or set it when calling insmod */
 static int irq=0;
@@ -1193,35 +1186,28 @@ MODULE_PARM(dma, "i");
 
 int init_module(void)
 {
-#if 0
-  if(io <= 0x0 || irq < 2) {
-    printk("ni65: Autoprobing not allowed for modules.\n");
-    printk("ni65: Set symbols 'io' 'irq' and 'dma'\n");
-    return -ENODEV;
-  }
-#endif
-  dev_ni65.irq = irq;
-  dev_ni65.dma = dma;
-  dev_ni65.base_addr = io;
-  if (register_netdev(&dev_ni65) != 0)
-    return -EIO;
-  return 0;
+       dev_ni65.irq = irq;
+       dev_ni65.dma = dma;
+       dev_ni65.base_addr = io;
+       if (register_netdev(&dev_ni65) != 0)
+               return -EIO;
+       return 0;
 }
 
 void cleanup_module(void)
 {
-  struct priv *p;
-  p = (struct priv *) dev_ni65.priv;
-  if(!p) {
-    printk("Ooops .. no privat struct\n");
-    return;
-  }
-  disable_dma(dev_ni65.dma);
-  free_dma(dev_ni65.dma);
-  release_region(dev_ni65.base_addr,cards[p->cardno].total_size);
-  ni65_free_buffer(p);
-  dev_ni65.priv = NULL;
-  unregister_netdev(&dev_ni65);
+       struct priv *p;
+       p = (struct priv *) dev_ni65.priv;
+       if(!p) {
+               printk("Ooops .. no private struct\n");
+               return;
+       }
+       disable_dma(dev_ni65.dma);
+       free_dma(dev_ni65.dma);
+       release_region(dev_ni65.base_addr,cards[p->cardno].total_size);
+       ni65_free_buffer(p);
+       dev_ni65.priv = NULL;
+       unregister_netdev(&dev_ni65);
 }
 #endif /* MODULE */
 
index 0dd7b5d46a43e98021debfb66eccc08812c4e323..b4e4e56a3f677b658b8a0a6a00218d690447814d 100644 (file)
@@ -146,7 +146,7 @@ static int pi_send_packet(struct sk_buff *skb, struct device *dev);
 static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs);
 static int pi_close(struct device *dev);
 static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static struct enet_statistics *pi_get_stats(struct device *dev);
+static struct net_device_stats *pi_get_stats(struct device *dev);
 static void rts(struct pi_local *lp, int x);
 static void b_rxint(struct device *dev, struct pi_local *lp);
 static void b_txint(struct pi_local *lp);
@@ -164,69 +164,71 @@ static char ax25_test[7] =
 
 static int ext2_secrm_seed = 152;      /* Random generator base */
 
-static inline unsigned char random(void)
+extern inline unsigned char random(void)
 {
-    return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed
+       return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed
                            * 69069l + 1);
 }
 
-static inline void wrtscc(int cbase, int ctl, int sccreg, int val)
+extern inline void wrtscc(int cbase, int ctl, int sccreg, int val)
 {
-    /* assume caller disables interrupts! */
-    outb_p(0, cbase + DMAEN);  /* Disable DMA while we touch the scc */
-    outb_p(sccreg, ctl);       /* Select register */
-    outb_p(val, ctl);          /* Output value */
-    outb_p(1, cbase + DMAEN);  /* Enable DMA */
+       /* assume caller disables interrupts! */
+       outb_p(0, cbase + DMAEN);       /* Disable DMA while we touch the scc */
+       outb_p(sccreg, ctl);            /* Select register */
+       outb_p(val, ctl);               /* Output value */
+       outb_p(1, cbase + DMAEN);       /* Enable DMA */
 }
 
-static inline int rdscc(int cbase, int ctl, int sccreg)
+extern inline int rdscc(int cbase, int ctl, int sccreg)
 {
-    int retval;
-
-    /* assume caller disables interrupts! */
-    outb_p(0, cbase + DMAEN);  /* Disable DMA while we touch the scc */
-    outb_p(sccreg, ctl);       /* Select register */
-    retval = inb_p(ctl);
-    outb_p(1, cbase + DMAEN);  /* Enable DMA */
-    return retval;
+       int retval;
+
+       /* assume caller disables interrupts! */
+       outb_p(0, cbase + DMAEN);       /* Disable DMA while we touch the scc */
+       outb_p(sccreg, ctl);    /* Select register */
+       retval = inb_p(ctl);
+       outb_p(1, cbase + DMAEN);       /* Enable DMA */
+       return retval;
 }
 
 static void switchbuffers(struct pi_local *lp)
 {
-    if (lp->rcvbuf == lp->rxdmabuf1)
-       lp->rcvbuf = lp->rxdmabuf2;
-    else
-       lp->rcvbuf = lp->rxdmabuf1;
+       if (lp->rcvbuf == lp->rxdmabuf1)
+               lp->rcvbuf = lp->rxdmabuf2;
+       else
+               lp->rcvbuf = lp->rxdmabuf1;
 }
 
 static void hardware_send_packet(struct pi_local *lp, struct sk_buff *skb)
 {
-    char kickflag;
-    unsigned long flags;
+       char kickflag;
+       unsigned long flags;
 
-    lp->stats.tx_packets++;
+       lp->stats.tx_packets++;
 
-    save_flags(flags);
-    cli();
-    kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
-    restore_flags(flags);
+       save_flags(flags);
+       cli();
+       kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
+       restore_flags(flags);
 
-    skb_queue_tail(&lp->sndq, skb);
-    if (kickflag) {
-       /* simulate interrupt to xmit */
-       switch (lp->base & 2) {
-       case 2:
-           a_txint(lp);        /* process interrupt */
-           break;
-       case 0:
-           save_flags(flags);
-           cli();
-           if (lp->tstate == IDLE)
-               b_txint(lp);
-           restore_flags(flags);
-           break;
+       skb_queue_tail(&lp->sndq, skb);
+       if (kickflag) 
+       {
+               /* simulate interrupt to xmit */
+               switch (lp->base & 2) 
+               {
+                       case 2:
+                               a_txint(lp);    /* process interrupt */
+                               break;
+                       case 0:
+                               save_flags(flags);
+                               cli();
+                               if (lp->tstate == IDLE)
+                                       b_txint(lp);
+                               restore_flags(flags);
+                               break;
+               }
        }
-    }
 }
 
 static void setup_rx_dma(struct pi_local *lp)
@@ -1662,12 +1664,11 @@ static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct netstats *
- pi_get_stats(struct device *dev)
+static struct net_device_stats *pi_get_stats(struct device *dev)
 {
-    struct pi_local *lp = (struct pi_local *) dev->priv;
+       struct pi_local *lp = (struct pi_local *) dev->priv;
 
-    return &lp->stats;
+       return &lp->stats;
 }
 
 #ifdef MODULE
index 8f45ea42091600335de1ab4ccba5a8de91047163..aca659f7a687e8ebbfbad317442447adcd73fed7 100644 (file)
@@ -1,9 +1,6 @@
 
 #define DMA_BUFF_SIZE 2200
 
-/* Network statistics, with the same names as 'struct enet_statistics'. */
-#define netstats enet_statistics
-
 #define ON 1
 #define OFF 0
 
index f2799b3dd74811d0bbdfd2e7688f1223233a69b0..f11b05476df484ab68d14ae2e968ea041ec77145 100644 (file)
@@ -147,7 +147,7 @@ static int plip_rebuild_header(struct sk_buff *skb);
 static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
 static int plip_open(struct device *dev);
 static int plip_close(struct device *dev);
-static struct enet_statistics *plip_get_stats(struct device *dev);
+static struct net_device_stats *plip_get_stats(struct device *dev);
 static int plip_config(struct device *dev, struct ifmap *map);
 static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 \f
@@ -198,7 +198,7 @@ struct plip_local {
 };
 
 struct net_local {
-       struct enet_statistics enet_stats;
+       struct net_device_stats enet_stats;
        struct tq_struct immediate;
        struct tq_struct deferred;
        struct plip_local snd_data;
@@ -213,8 +213,8 @@ struct net_local {
 \f
 /* Entry point of PLIP driver.
    Probe the hardware, and register/initialize the driver. */
-int
-plip_init(struct device *dev)
+
+int plip_init(struct device *dev)
 {
        struct net_local *nl;
        int iosize = (PAR_DATA(dev) == 0x3bc) ? 3 : 8;
@@ -306,8 +306,8 @@ plip_init(struct device *dev)
 /* Bottom half handler for the delayed request.
    This routine is kicked by do_timer().
    Request `plip_bh' to be invoked. */
-static void
-plip_kick_bh(struct device *dev)
+   
+static void plip_kick_bh(struct device *dev)
 {
        struct net_local *nl = (struct net_local *)dev->priv;
 
@@ -350,8 +350,7 @@ static plip_func connection_state_table[] =
 };
 
 /* Bottom half handler of PLIP. */
-static void
-plip_bh(struct device *dev)
+static void plip_bh(struct device *dev)
 {
        struct net_local *nl = (struct net_local *)dev->priv;
        struct plip_local *snd = &nl->snd_data;
@@ -368,8 +367,7 @@ plip_bh(struct device *dev)
        }
 }
 
-static int
-plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
                      struct plip_local *snd, struct plip_local *rcv,
                      int error)
 {
@@ -431,8 +429,7 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
        return TIMEOUT;
 }
 \f
-static int
-plip_none(struct device *dev, struct net_local *nl,
+static int plip_none(struct device *dev, struct net_local *nl,
          struct plip_local *snd, struct plip_local *rcv)
 {
        return OK;
@@ -440,8 +437,7 @@ plip_none(struct device *dev, struct net_local *nl,
 
 /* PLIP_RECEIVE --- receive a byte(two nibbles)
    Returns OK on success, TIMEOUT on timeout */
-inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
+extern inline int plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
             enum plip_nibble_state *ns_p, unsigned char *data_p)
 {
        unsigned char c0, c1;
@@ -490,8 +486,7 @@ plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
 }
 
 /* PLIP_RECEIVE_PACKET --- receive a packet */
-static int
-plip_receive_packet(struct device *dev, struct net_local *nl,
+static int plip_receive_packet(struct device *dev, struct net_local *nl,
                    struct plip_local *snd, struct plip_local *rcv)
 {
        unsigned short status_addr = PAR_STATUS(dev);
@@ -607,8 +602,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
 
 /* PLIP_SEND --- send a byte (two nibbles)
    Returns OK on success, TIMEOUT when timeout    */
-inline static int
-plip_send(unsigned short nibble_timeout, unsigned short data_addr,
+extern inline int plip_send(unsigned short nibble_timeout, unsigned short data_addr,
          enum plip_nibble_state *ns_p, unsigned char data)
 {
        unsigned char c0;
@@ -654,8 +648,7 @@ plip_send(unsigned short nibble_timeout, unsigned short data_addr,
 }
 
 /* PLIP_SEND_PACKET --- send a packet */
-static int
-plip_send_packet(struct device *dev, struct net_local *nl,
+static int plip_send_packet(struct device *dev, struct net_local *nl,
                 struct plip_local *snd, struct plip_local *rcv)
 {
        unsigned short data_addr = PAR_DATA(dev);
@@ -759,8 +752,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
        return OK;
 }
 
-static int
-plip_connection_close(struct device *dev, struct net_local *nl,
+static int plip_connection_close(struct device *dev, struct net_local *nl,
                      struct plip_local *snd, struct plip_local *rcv)
 {
        cli();
@@ -774,8 +766,7 @@ plip_connection_close(struct device *dev, struct net_local *nl,
 }
 
 /* PLIP_ERROR --- wait till other end settled */
-static int
-plip_error(struct device *dev, struct net_local *nl,
+static int plip_error(struct device *dev, struct net_local *nl,
           struct plip_local *snd, struct plip_local *rcv)
 {
        unsigned char status;
@@ -799,8 +790,7 @@ plip_error(struct device *dev, struct net_local *nl,
 }
 \f
 /* Handle the parallel port interrupts. */
-static void
-plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        struct device *dev = (struct device *) irq2dev_map[irq];
        struct net_local *nl = (struct net_local *)dev->priv;
@@ -853,8 +843,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 }
 \f
 /* We don't need to send arp, for plip is point-to-point. */
-static int
-plip_rebuild_header(struct sk_buff *skb)
+static int plip_rebuild_header(struct sk_buff *skb)
 {
        struct device *dev = skb->dev;
        struct net_local *nl = (struct net_local *)dev->priv;
@@ -888,8 +877,7 @@ plip_rebuild_header(struct sk_buff *skb)
        return 0;
 }
 
-static int
-plip_tx_packet(struct sk_buff *skb, struct device *dev)
+static int plip_tx_packet(struct sk_buff *skb, struct device *dev)
 {
        struct net_local *nl = (struct net_local *)dev->priv;
        struct plip_local *snd = &nl->snd_data;
@@ -941,8 +929,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
    This routine gets exclusive access to the parallel port by allocating
    its IRQ line.
  */
-static int
-plip_open(struct device *dev)
+static int plip_open(struct device *dev)
 {
        struct net_local *nl = (struct net_local *)dev->priv;
        int i;
@@ -985,8 +972,7 @@ plip_open(struct device *dev)
 }
 
 /* The inverse routine to plip_open (). */
-static int
-plip_close(struct device *dev)
+static int plip_close(struct device *dev)
 {
        struct net_local *nl = (struct net_local *)dev->priv;
        struct plip_local *snd = &nl->snd_data;
@@ -1019,17 +1005,15 @@ plip_close(struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *
-plip_get_stats(struct device *dev)
+static struct net_device_stats *plip_get_stats(struct device *dev)
 {
        struct net_local *nl = (struct net_local *)dev->priv;
-       struct enet_statistics *r = &nl->enet_stats;
+       struct net_device_stats *r = &nl->enet_stats;
 
        return r;
 }
 
-static int
-plip_config(struct device *dev, struct ifmap *map)
+static int plip_config(struct device *dev, struct ifmap *map)
 {
        if (dev->flags & IFF_UP)
                return -EBUSY;
@@ -1043,8 +1027,7 @@ plip_config(struct device *dev, struct ifmap *map)
        return 0;
 }
 
-static int
-plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
        struct net_local *nl = (struct net_local *) dev->priv;
        struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
@@ -1092,8 +1075,7 @@ static struct device dev_plip[] = {
        }
 };
 
-int
-init_module(void)
+int init_module(void)
 {
        int no_parameters=1;
        int devices=0;
@@ -1134,8 +1116,7 @@ init_module(void)
        return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
        int i;
 
index 1b7a3bc779e580f1136f99276390fc51b9d80491..fce53604adcab727c962e19ff260d8c87c2c4547 100644 (file)
@@ -183,7 +183,7 @@ static int ppp_dev_open (struct device *);
 static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
 static int ppp_dev_close (struct device *);
 static int ppp_dev_xmit (sk_buff *, struct device *);
-static struct enet_statistics *ppp_dev_stats (struct device *);
+static struct net_device_stats *ppp_dev_stats (struct device *);
 
 /*
  * TTY callbacks
@@ -3080,11 +3080,11 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  * Generate the statistic information for the /proc/net/dev listing.
  */
 
-static struct enet_statistics *
+static struct net_device_stats *
 ppp_dev_stats (struct device *dev)
 {
        struct ppp *ppp = dev2ppp (dev);
-       static struct enet_statistics ppp_stats;
+       static struct net_device_stats ppp_stats;
 
        ppp_stats.rx_packets          = ppp->stats.ppp_ipackets;
        ppp_stats.rx_errors           = ppp->stats.ppp_ierrors;
index 8a8d8456ed3e14bde483f72061eb2aac599ef43f..8be502656972d2a4f2a7cdedc58c4d40e0621c90 100644 (file)
@@ -124,7 +124,7 @@ static int pt_send_packet(struct sk_buff *skb, struct device *dev);
 static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int pt_close(struct device *dev);
 static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static struct enet_statistics *pt_get_stats(struct device *dev);
+static struct net_device_stats *pt_get_stats(struct device *dev);
 static void pt_rts(struct pt_local *lp, int x);
 static void pt_rxisr(struct device *dev);
 static void pt_txisr(struct pt_local *lp);
@@ -175,10 +175,10 @@ static void switchbuffers(struct pt_local *lp)
 
 static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb)
 {
-    char kickflag;
-    unsigned long flags;
-    char *ptr;
-    struct device *dev;
+       char kickflag;
+       unsigned long flags;
+       char *ptr;
+       struct device *dev;
 
        /* First, let's see if this packet is actually a KISS packet */
        ptr = skb->data;
@@ -215,73 +215,78 @@ static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb)
                return;
        }
 
-    lp->stats.tx_packets++;
-
-    save_flags(flags);
-    cli();
-    kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
-    restore_flags(flags);
+       lp->stats.tx_packets++;
+       lp->stats.tx_bytes+=skb->len;
+       save_flags(flags);
+       cli();
+       kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
+       restore_flags(flags);
 
 #ifdef PT_DEBUG
        printk(KERN_DEBUG "PT: hardware_send_packet(): kickflag = %d (%d).\n", kickflag, lp->base & CHANA);
 #endif
-    skb_queue_tail(&lp->sndq, skb);
-    if (kickflag) {
+       skb_queue_tail(&lp->sndq, skb);
+       if (kickflag) 
+       {
         /* Simulate interrupt to transmit */
-            if (lp->dmachan)
-            {
-               pt_txisr(lp);
-            } else {
-               save_flags(flags);
+               if (lp->dmachan)
+                       pt_txisr(lp);
+               else 
+               {
+                       save_flags(flags);
                        cli();
-               if (lp->tstate == IDLE)
-                       pt_txisr(lp);
-               restore_flags(flags);
-            }
-    }
+                       if (lp->tstate == IDLE)
+                               pt_txisr(lp);
+                       restore_flags(flags);
+               }
+       }
 } /* hardware_send_packet() */
 
 static void setup_rx_dma(struct pt_local *lp)
 {
-    unsigned long flags;
-    int cmd;
-    unsigned long dma_abs;
-    unsigned char dmachan;
+       unsigned long flags;
+       int cmd;
+       unsigned long dma_abs;
+       unsigned char dmachan;
 
-    save_flags(flags);
-    cli();
+       save_flags(flags);
+       cli();
 
-    dma_abs = (unsigned long) (lp->rcvbuf->data);
-    dmachan = lp->dmachan;
-    cmd = lp->base + CTL;
+       dma_abs = (unsigned long) (lp->rcvbuf->data);
+       dmachan = lp->dmachan;
+       cmd = lp->base + CTL;
 
-    if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))
-       panic("PI: RX buffer violates DMA boundary!");
+       if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))
+               panic("PI: RX buffer violates DMA boundary!");
 
-    /* Get ready for RX DMA */
-    wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+       /* Get ready for RX DMA */
+       wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
 
-    disable_dma(dmachan);
-    clear_dma_ff(dmachan);
+       disable_dma(dmachan);
+       clear_dma_ff(dmachan);
 
-    /* Set DMA mode register to single transfers, incrementing address,
-     *  auto init, writes
-     */
-    set_dma_mode(dmachan, DMA_MODE_READ | 0x10);
-    set_dma_addr(dmachan, dma_abs);
-    set_dma_count(dmachan, lp->bufsiz);
-    enable_dma(dmachan);
+       /*
+        *      Set DMA mode register to single transfers, incrementing address,
+        *      auto init, writes
+        */
 
-    /* If a packet is already coming in, this line is supposed to
-          avoid receiving a partial packet.
-     */
-    wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC);
+       set_dma_mode(dmachan, DMA_MODE_READ | 0x10);
+       set_dma_addr(dmachan, dma_abs);
+       set_dma_count(dmachan, lp->bufsiz);
+       enable_dma(dmachan);
+
+       /*
+        *      If a packet is already coming in, this line is supposed to
+        *      avoid receiving a partial packet.
+        */
 
-    /* Enable RX dma */
-    wrtscc(lp->cardbase, cmd, R1,
-      WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+       wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC);
 
-    restore_flags(flags);
+       /* Enable RX dma */
+       wrtscc(lp->cardbase, cmd, R1,
+               WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+
+       restore_flags(flags);
 }
 
 static void setup_tx_dma(struct pt_local *lp, int length)
@@ -324,79 +329,76 @@ static void free_p(struct sk_buff *skb)
  */
 static void scc_init(struct device *dev)
 {
-    unsigned long flags;
-    struct pt_local *lp = (struct pt_local*) dev->priv;
-    register int cmd = lp->base + CTL;
-    int tc, br;
+       unsigned long flags;
+       struct pt_local *lp = (struct pt_local*) dev->priv;
+       register int cmd = lp->base + CTL;
+       int tc, br;
 
 #ifdef PT_DEBUG
        printk(KERN_DEBUG "PT: scc_init(): (%d).\n", lp->base & CHANA);
 #endif
-    save_flags(flags);
-    cli();
+       save_flags(flags);
+       cli();
 
-    /* We may put something here to enable_escc */
+       /* We may put something here to enable_escc */
 
-    if (cmd & CHANA)
-    {
-        wrtscc(lp->cardbase, cmd, R9, CHRA);           /* Reset channel A */
-        wrtscc(lp->cardbase, cmd, R2, 0xff);           /* Initialise interrupt vector */
-    } else {
-       wrtscc(lp->cardbase, cmd, R9, CHRB);            /* Reset channel B */
-    }
+       if (cmd & CHANA)
+       {
+               wrtscc(lp->cardbase, cmd, R9, CHRA);    /* Reset channel A */
+               wrtscc(lp->cardbase, cmd, R2, 0xff);    /* Initialise interrupt vector */
+       }
+       else
+               wrtscc(lp->cardbase, cmd, R9, CHRB);    /* Reset channel B */
 
-    /* Deselect all Rx and Tx interrupts */
-    wrtscc(lp->cardbase, cmd, R1, 0);
+       /* Deselect all Rx and Tx interrupts */
+       wrtscc(lp->cardbase, cmd, R1, 0);
 
-    /* Turn off external interrupts (like CTS/CD) */
-    wrtscc(lp->cardbase, cmd, R15, 0);
+       /* Turn off external interrupts (like CTS/CD) */
+       wrtscc(lp->cardbase, cmd, R15, 0);
 
-    /* X1 clock, SDLC mode */
-    wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK);
+       /* X1 clock, SDLC mode */
+       wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK);
 
        /* Preset CRC and set mode */
        if (lp->nrzi)
+               /* Preset Tx CRC, put into NRZI mode */
+               wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);
+       else
+               /* Preset Tx CRC, put into NRZ mode */
+               wrtscc(lp->cardbase, cmd, R10, CRCPS);
+
+       /* Tx/Rx parameters */
+       if (lp->speed)          /* Use internal clocking */
+              /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */
+              wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI);
+       else    /* Use external clocking */
        {
-       /* Preset Tx CRC, put into NRZI mode */
-       wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);
-    } else {
-       /* Preset Tx CRC, put into NRZ mode */
-       wrtscc(lp->cardbase, cmd, R10, CRCPS);
-    }
-
-    /* Tx/Rx parameters */
-    if (lp->speed)             /* Use internal clocking */
-    {
-       /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */
-       wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI);
-
-    } else {                   /* Use external clocking */
-           /* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */
-           wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR);
-           wrtscc(lp->cardbase,cmd, R14, 0);   /* wiz1 */
-    }
+               /* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */
+               wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR);
+               wrtscc(lp->cardbase,cmd, R14, 0);       /* wiz1 */
+       }
 
-    /* Null out SDLC start address */
-    wrtscc(lp->cardbase, cmd, R6, 0);
+       /* Null out SDLC start address */
+       wrtscc(lp->cardbase, cmd, R6, 0);
 
-    /* SDLC flag */
-    wrtscc(lp->cardbase, cmd, R7, FLAG);
+       /* SDLC flag */
+       wrtscc(lp->cardbase, cmd, R7, FLAG);
 
-    /* Setup Tx but don't enable it */
-    wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);
+       /* Setup Tx but don't enable it */
+       wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);
 
-    /* Setup Rx */
-    wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);
+       /* Setup Rx */
+       wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);
 
-    /* Setup the BRG, turn it off first */
-    wrtscc(lp->cardbase, cmd, R14, BRSRC);
+       /* Setup the BRG, turn it off first */
+       wrtscc(lp->cardbase, cmd, R14, BRSRC);
 
-    /* set the 32x time constant for the BRG in Rx mode */
+       /* set the 32x time constant for the BRG in Rx mode */
        if (lp->speed)
        {
                br = lp->speed;
                tc = ((lp->xtal / 32) / (br * 2)) - 2;
-           wrtscc(lp->cardbase, cmd, R12, tc & 0xff);          /* lower byte */
+               wrtscc(lp->cardbase, cmd, R12, tc & 0xff);              /* lower byte */
                wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff);       /* upper byte */
        }
 
@@ -409,36 +411,37 @@ static void scc_init(struct device *dev)
                /* DPLL frm BRG, BRG src PCLK */
                wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR);
                wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */
-           wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);    /* Enable the BRG */
+               wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);        /* Enable the BRG */
 
            /* Turn off external clock port */
-        if (lp->base & CHANA)
-            outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
-        else
-            outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
-    } else {
+               if (lp->base & CHANA)
+                       outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
+               else
+                       outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
+       }
+       else
+       {
                /* DPLL frm rtxc,BRG src PCLK */
-/*             wrtscc(lp->cardbase, cmd, R14, BRSRC | SSRTxC);*/
-        /* Turn on external clock port */
-        if (lp->base & CHANA)
-            outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
-        else
-            outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
-    }
+               /* Turn on external clock port */
+               if (lp->base & CHANA)
+                       outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
+               else
+                       outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
+       }
 
-    if (!lp->dmachan)
+       if (!lp->dmachan)
                wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB));
 
-    wrtscc(lp->cardbase, cmd, R15, BRKIE);     /* ABORT int */
+       wrtscc(lp->cardbase, cmd, R15, BRKIE);  /* ABORT int */
 
        /* Turn on the DTR to tell modem we're alive */
        if (lp->base & CHANA)
-           outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) );
+               outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) );
        else
-       outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) );
+               outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) );
 
-    /* Now, turn on the receiver and hunt for a flag */
-    wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 );
+       /* Now, turn on the receiver and hunt for a flag */
+       wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 );
 
        restore_flags(flags);
 
@@ -1075,14 +1078,15 @@ static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
     return ret;
 }
 
-/* Get the current statistics. This may be called with the card open or
-   closed. */
-static struct netstats *
- pt_get_stats(struct device *dev)
+/*
+ *     Get the current statistics.
+ *     This may be called with the card open or closed. 
+ */
+static struct net_device_stats *pt_get_stats(struct device *dev)
 {
-    struct pt_local *lp = (struct pt_local *) dev->priv;
-
-    return &lp->stats;
+       struct pt_local *lp = (struct pt_local *) dev->priv;
+       return &lp->stats;
 }
 
 
@@ -1102,13 +1106,16 @@ static void tdelay(struct pt_local *lp, int time)
        if (!lp->dmachan)
                wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB);
 
-    if (lp->base & CHANA) {
-        outb_p(time & 0xff, lp->cardbase + TMR1);
-        outb_p((time >> 8)&0xff, lp->cardbase + TMR1);
-    } else {
-        outb_p(time & 0xff, lp->cardbase + TMR2);
-        outb_p((time >> 8)&0xff, lp->cardbase + TMR2);
-    }
+       if (lp->base & CHANA) 
+       {
+               outb_p(time & 0xff, lp->cardbase + TMR1);
+               outb_p((time >> 8)&0xff, lp->cardbase + TMR1);
+       }
+       else
+       {
+               outb_p(time & 0xff, lp->cardbase + TMR2);
+               outb_p((time >> 8)&0xff, lp->cardbase + TMR2);
+       }
 } /* tdelay */
 
 
@@ -1379,6 +1386,7 @@ static void pt_rxisr(struct device *dev)
                     memcpy(cfix, lp->rcvbuf->data, pkt_len - 1);
                  skb->protocol = ntohs(ETH_P_AX25);
                  skb->mac.raw=skb->data;
+                 lp->stats.rx_bytes+=skb->len;
                  IS_SKB(skb);
                  netif_rx(skb);
                  lp->stats.rx_packets++;
@@ -1767,21 +1775,21 @@ EXPORT_NO_SYMBOLS;
 
 int init_module(void)
 {
-    return pt_init();
+       return pt_init();
 }
 
 void cleanup_module(void)
 {
-    free_irq(pt0a.irq, NULL);  /* IRQs and IO Ports are shared */
-    release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE);
-    irq2dev_map[pt0a.irq] = NULL;
+       free_irq(pt0a.irq, NULL);       /* IRQs and IO Ports are shared */
+       release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE);
+       irq2dev_map[pt0a.irq] = NULL;
 
-    kfree(pt0a.priv);
-    pt0a.priv = NULL;
-    unregister_netdev(&pt0a);
+       kfree(pt0a.priv);
+       pt0a.priv = NULL;
+       unregister_netdev(&pt0a);
 
-    kfree(pt0b.priv);
-    pt0b.priv = NULL;
-    unregister_netdev(&pt0b);
+       kfree(pt0b.priv);
+       pt0b.priv = NULL;
+       unregister_netdev(&pt0b);
 }
 #endif
index d2cc1065ad9a9c0770cad2442463c1452f292f20..9ab17f501577652ba3992940d8eef8c5a9e29e5e 100644 (file)
@@ -6,9 +6,6 @@
  */
 #define DMA_BUFF_SIZE 2200
 
-/* Network statistics, with the same names as 'struct enet_statistics'. */
-#define netstats enet_statistics
-
 #define ON 1
 #define OFF 0
 
 #define SIOCGPIIRQ             0x5006  /* get only IRQ */
 #define SIOCSPIIRQ             0x5007  
 
-struct pt_req  {
-    int cmd;
-    int speed;
-    int clockmode;
-    int txdelay;
-    unsigned char persist;
-    int slotime; 
-    int squeldelay;
-    int dmachan;    
-    int irq;    
+struct pt_req
+{
+       int cmd;
+       int speed;
+       int clockmode;
+       int txdelay;
+       unsigned char persist;
+       int slotime; 
+       int squeldelay;
+       int dmachan;    
+       int irq;    
 };
 
 /* SCC Interrupt vectors, if we have set 'status low' */
@@ -124,53 +122,53 @@ struct pt_req  {
 #ifdef __KERNEL__
 
 /* Information that needs to be kept for each channel. */
-struct pt_local {
-    struct netstats stats; /* %%%dp*/
-    long open_time;             /* Useless example local info. */
-    unsigned long xtal; 
-
-    struct mbuf *rcvbuf;/* Buffer for current rx packet */
-    struct mbuf *rxdmabuf1; /* DMA rx buffer */
-    struct mbuf *rxdmabuf2; /* DMA rx buffer */
-
-    int bufsiz;         /* Size of rcvbuf */
-    char *rcp;          /* Pointer into rcvbuf */
-
-    struct sk_buff_head sndq;  /* Packets awaiting transmission */
-    int sndcnt;         /* Number of packets on sndq */
-    struct sk_buff *sndbuf;/* Current buffer being transmitted */
-    char *txdmabuf;     /* Transmit DMA buffer */
-       char *txptr;            /* Used by B port tx */
+struct pt_local
+{
+       struct net_device_stats stats; /* %%%dp*/
+       long open_time;             /* Useless example local info. */
+       unsigned long xtal; 
+
+       struct mbuf *rcvbuf;/* Buffer for current rx packet */
+       struct mbuf *rxdmabuf1; /* DMA rx buffer */
+       struct mbuf *rxdmabuf2; /* DMA rx buffer */
+
+       int bufsiz;                     /* Size of rcvbuf                       */
+       char *rcp;                      /* Pointer into rcvbuf                  */
+       struct sk_buff_head sndq;       /* Packets awaiting transmission        */
+       int sndcnt;                     /* Number of packets on sndq            */
+       struct sk_buff *sndbuf;         /* Current buffer being transmitted     */
+       char *txdmabuf;                 /* Transmit DMA buffer                  */
+       char *txptr;                    /* Used by B port tx                    */
        int txcnt;                      
-    char tstate;        /* Transmitter state */
-#define IDLE    0       /* Transmitter off, no data pending */
-#define ACTIVE  1       /* Transmitter on, sending data */
-#define UNDERRUN 2      /* Transmitter on, flushing CRC */
-#define FLAGOUT 3       /* CRC sent - attempt to start next frame */
-#define DEFER 4         /* Receive Active - DEFER Transmit */
-#define ST_TXDELAY 5    /* Sending leading flags */
+       char tstate;                    /* Transmitter state                    */
+#define IDLE    0       /* Transmitter off, no data pending            */
+#define ACTIVE  1       /* Transmitter on, sending data                */
+#define UNDERRUN 2      /* Transmitter on, flushing CRC                        */
+#define FLAGOUT 3       /* CRC sent - attempt to start next frame      */
+#define DEFER 4         /* Receive Active - DEFER Transmit             */
+#define ST_TXDELAY 5    /* Sending leading flags                       */
 #define CRCOUT 6
-    char rstate;        /* Set when !DCD goes to 0 (TRUE) */
+       char rstate;        /* Set when !DCD goes to 0 (TRUE)           */
 /* Normal state is ACTIVE if Receive enabled */
-#define RXERROR 2       /* Error -- Aborting current Frame */
-#define RXABORT 3       /* ABORT sequence detected */
-#define TOOBIG 4        /* too large a frame to store */
+#define RXERROR 2       /* Error -- Aborting current Frame             */
+#define RXABORT 3       /* ABORT sequence detected                     */
+#define TOOBIG 4        /* too large a frame to store                  */
        
-    int dev;            /* Device number */
-    int base;       /* Base of I/O registers */
-    int cardbase;     /* Base address of card */
-    int stata;        /* address of Channel A status regs */
-    int statb;        /* address of Channel B status regs */
-    int speed;        /* Line speed, bps */
-    int clockmode;    /* tapr 9600 modem clocking option */
-    int txdelay;      /* Transmit Delay 10 ms/cnt */
-    unsigned char persist;       /* Persistence (0-255) as a % */
-    int slotime;      /* Delay to wait on persistence hit */
-    int squeldelay;   /* Delay after XMTR OFF for squelch tail */
-    struct iface *iface;    /* Associated interface */
-    int dmachan;           /* DMA channel for this port */
-    char saved_RR0;    /* The saved version of RR) that we compare with */
-    int nrzi;                  /* Do we use NRZI (or NRZ) */
+       int dev;                /* Device number */
+       int base;               /* Base of I/O registers */
+       int cardbase;           /* Base address of card */
+       int stata;              /* address of Channel A status regs */
+       int statb;              /* address of Channel B status regs */
+       int speed;              /* Line speed, bps */
+       int clockmode;          /* tapr 9600 modem clocking option */
+       int txdelay;            /* Transmit Delay 10 ms/cnt */
+       unsigned char persist;  /* Persistence (0-255) as a % */
+       int slotime;            /* Delay to wait on persistence hit */
+       int squeldelay;         /* Delay after XMTR OFF for squelch tail */
+       struct iface *iface;    /* Associated interface */
+       int dmachan;            /* DMA channel for this port */
+       char saved_RR0;         /* The saved version of RR) that we compare with */
+       int nrzi;               /* Do we use NRZI (or NRZ) */
 };
 
 #endif
index 0dfb7c623d55719b430b76da8f0a76c6706dad4e..634abf15210d2662dda3c230337d05b50a502ded 100644 (file)
@@ -204,7 +204,7 @@ static int scc_net_tx(struct sk_buff *skb, struct device *dev);
 static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 static int scc_net_set_mac_address(struct device *dev, void *addr);
 static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
-static struct enet_statistics * scc_net_get_stats(struct device *dev);
+static struct net_device_stats * scc_net_get_stats(struct device *dev);
 
 static unsigned char *SCC_DriverName = "scc";
 
@@ -1663,12 +1663,6 @@ static int scc_net_tx(struct sk_buff *skb, struct device *dev)
                 dev->trans_start = jiffies;
         }
         
-       if (skb == NULL)
-       {
-               dev_tint(dev);
-               return 0;
-       }
-       
        if (scc == NULL || scc->magic != SCC_MAGIC)
        {
                dev_kfree_skb(skb, FREE_WRITE);
@@ -1971,12 +1965,12 @@ static int scc_net_set_mac_address(struct device *dev, void *addr)
 static int  scc_net_header(struct sk_buff *skb, struct device *dev, 
        unsigned short type, void *daddr, void *saddr, unsigned len)
 {
-    return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+       return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
 }
 
 /* ----> get statistics <---- */
 
-static struct enet_statistics *scc_net_get_stats(struct device *dev)
+static struct net_device_stats *scc_net_get_stats(struct device *dev)
 {
        struct scc_channel *scc = (struct scc_channel *) dev->priv;
        
index 68a6525f5b5bc8cf5d88b64a43bb3125f12f248c..fcce2801f22ae0d6966a26201dec99598e8723fc 100644 (file)
@@ -82,147 +82,145 @@ static unsigned int valid_mem[]  = {0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000,
 
 static void sdla_read(struct device *dev, int addr, void *buf, short len)
 {
-   unsigned long flags;
-   char          *temp, *base;
-   int           offset, bytes;
-
-   temp = buf;
-   while(len)
-   {
-      offset = addr & SDLA_ADDR_MASK;
-      bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
-      base = (void *) (dev->mem_start + offset);
-
-      save_flags(flags);
-      cli();
-      SDLA_WINDOW(dev, addr);
-      memcpy(temp, base, bytes);
-      restore_flags(flags);
-
-      addr += bytes;
-      temp += bytes;
-      len  -= bytes;
-   }  
+       unsigned long flags;
+       char          *temp, *base;
+       int           offset, bytes;
+
+       temp = buf;
+       while(len)
+       {       
+               offset = addr & SDLA_ADDR_MASK;
+               bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+               base = (void *) (dev->mem_start + offset);
+
+               save_flags(flags);
+               cli();
+               SDLA_WINDOW(dev, addr);
+               memcpy(temp, base, bytes);
+               restore_flags(flags);
+
+               addr += bytes;
+               temp += bytes;
+               len  -= bytes;
+       }  
 }
 
 static void sdla_write(struct device *dev, int addr, void *buf, short len)
 {
-   unsigned long flags;
-   char          *temp, *base;
-   int           offset, bytes;
-
-   temp = buf;
-   while(len)
-   {
-      offset = addr & SDLA_ADDR_MASK;
-      bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
-      base = (void *) (dev->mem_start + offset);
-
-      save_flags(flags);
-      cli();
-      SDLA_WINDOW(dev, addr);
-      memcpy(base, temp, bytes);
-      restore_flags(flags);
-
-      addr += bytes;
-      temp += bytes;
-      len  -= bytes;
-   }
+       unsigned long flags;
+       char          *temp, *base;
+       int           offset, bytes;
+
+       temp = buf;
+       while(len)
+       {
+               offset = addr & SDLA_ADDR_MASK;
+               bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+               base = (void *) (dev->mem_start + offset);
+               save_flags(flags);
+               cli();
+               SDLA_WINDOW(dev, addr);
+               memcpy(base, temp, bytes);
+               restore_flags(flags);
+               addr += bytes;
+               temp += bytes;
+               len  -= bytes;
+       }
 }
 
 static void sdla_clear(struct device *dev)
 {
-   unsigned long flags;
-   char          *base;
-   int           len, addr, bytes;
-
-   len = 65536;
-   addr = 0;
-   bytes = SDLA_WINDOW_SIZE;
-   base = (void *) dev->mem_start;
-
-   save_flags(flags);
-   cli();
-   while(len)
-   {
-      SDLA_WINDOW(dev, addr);
-      memset(base, 0, bytes);
-
-      addr += bytes;
-      len  -= bytes;
-   }
-   restore_flags(flags);
+       unsigned long flags;
+       char          *base;
+       int           len, addr, bytes;
+
+       len = 65536;    
+       addr = 0;
+       bytes = SDLA_WINDOW_SIZE;
+       base = (void *) dev->mem_start;
+
+       save_flags(flags);
+       cli();
+       while(len)
+       {
+               SDLA_WINDOW(dev, addr);
+               memset(base, 0, bytes);
+
+               addr += bytes;
+               len  -= bytes;
+       }
+       restore_flags(flags);
 }
 
 static char sdla_byte(struct device *dev, int addr)
 {
-   unsigned long flags;
-   char          byte, *temp;
+       unsigned long flags;
+       char          byte, *temp;
 
-   temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
+       temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
 
-   save_flags(flags);
-   cli();
-   SDLA_WINDOW(dev, addr);
-   byte = *temp;
-   restore_flags(flags);
+       save_flags(flags);
+       cli();
+       SDLA_WINDOW(dev, addr);
+       byte = *temp;
+       restore_flags(flags);
 
-   return(byte);
+       return(byte);
 }
 
 void sdla_stop(struct device *dev)
 {
-   struct frad_local *flp;
-
-   flp = dev->priv;
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = SDLA_HALT;
-         break;
-      case SDLA_S502E:
-         outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-         outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = SDLA_S502E_ENABLE;
-         break;
-      case SDLA_S507:
-         flp->state &= ~SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-      case SDLA_S508:
-         flp->state &= ~SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-   }
+       struct frad_local *flp;
+
+       flp = dev->priv;
+       switch(flp->type)
+       {
+               case SDLA_S502A:
+                       outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
+                       flp->state = SDLA_HALT;
+                       break;
+               case SDLA_S502E:
+                       outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
+                       outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
+                       flp->state = SDLA_S502E_ENABLE;
+                       break;
+               case SDLA_S507:
+                       flp->state &= ~SDLA_CPUEN;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       break;
+               case SDLA_S508:
+                       flp->state &= ~SDLA_CPUEN;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       break;
+       }
 }
 
 void sdla_start(struct device *dev)
 {
-   struct frad_local *flp;
-
-   flp = dev->priv;
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
-         outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = SDLA_S502A_START;
-         break;
-      case SDLA_S502E:
-         outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
-         outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = 0;
-         break;
-      case SDLA_S507:
-         flp->state |= SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-      case SDLA_S508:
-         flp->state |= SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-   }
+       struct frad_local *flp;
+
+       flp = dev->priv;
+       switch(flp->type)
+       {
+               case SDLA_S502A:
+                       outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
+                       outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+                       flp->state = SDLA_S502A_START;
+                       break;
+               case SDLA_S502E:
+                       outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
+                       outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
+                       flp->state = 0;
+                       break;
+               case SDLA_S507:
+                       flp->state |= SDLA_CPUEN;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       break;
+               case SDLA_S508:
+                       flp->state |= SDLA_CPUEN;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       break;
+       }
 }
 
 /****************************************************
@@ -237,26 +235,26 @@ void sdla_start(struct device *dev)
 
 int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char resp2)
 {
-   unsigned long start, done, now;
-   char          resp, *temp;
-
-   start = now = jiffies;
-   done = jiffies + jiffs;
-
-   temp = (void *)dev->mem_start;
-   temp += z80_addr & SDLA_ADDR_MASK;
-
-   resp = ~resp1;
-   while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
-   {
-      if (jiffies != now)
-      {
-         SDLA_WINDOW(dev, z80_addr);
-         now = jiffies;
-         resp = *temp;
-      }
-   }
-   return(jiffies < done ? jiffies - start : -1);
+       unsigned long start, done, now;
+       char          resp, *temp;
+
+       start = now = jiffies;
+       done = jiffies + jiffs;
+
+       temp = (void *)dev->mem_start;
+       temp += z80_addr & SDLA_ADDR_MASK;
+       
+       resp = ~resp1;
+       while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
+       {
+               if (jiffies != now)
+               {
+                       SDLA_WINDOW(dev, z80_addr);
+                       now = jiffies;
+                       resp = *temp;
+               }
+       }
+       return(jiffies < done ? jiffies - start : -1);
 }
 
 /* constants for Z80 CPU speed */
@@ -267,46 +265,45 @@ int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char
 
 static int sdla_cpuspeed(struct device *dev, struct ifreq *ifr)
 {
-   int  jiffs;
-   char data;
-
-   sdla_start(dev);
-   if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
-      return(-EIO);
-
-   data = LOADER_READY;
-   sdla_write(dev, 0, &data, 1);
-
-   if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
-      return(-EIO);
-
-   sdla_stop(dev);
-   sdla_read(dev, 0, &data, 1);
-
-   if (data == Z80_SCC_BAD)
-      return(-EIO);
-
-   if (data != Z80_SCC_OK)
-      return(-EINVAL);
-
-   if (jiffs < 165)
-      ifr->ifr_mtu = SDLA_CPU_16M;
-   else
-      if (jiffs < 220)
-         ifr->ifr_mtu = SDLA_CPU_10M;
-      else
-         if (jiffs < 258)
-            ifr->ifr_mtu = SDLA_CPU_8M;
-         else
-            if (jiffs < 357)
-               ifr->ifr_mtu = SDLA_CPU_7M;
-            else
-               if (jiffs < 467)
-                  ifr->ifr_mtu = SDLA_CPU_5M;
-               else
-                  ifr->ifr_mtu = SDLA_CPU_3M;
+       int  jiffs;
+       char data;
+
+       sdla_start(dev);
+       if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
+               return(-EIO);
+
+       data = LOADER_READY;
+       sdla_write(dev, 0, &data, 1);
+
+       if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
+               return(-EIO);
+
+       sdla_stop(dev);
+       sdla_read(dev, 0, &data, 1);
+
+       if (data == Z80_SCC_BAD)
+       {
+               printk("%s: SCC bad\n", dev->name);
+               return(-EIO);
+       }
+
+       if (data != Z80_SCC_OK)
+               return(-EINVAL);
+
+       if (jiffs < 165)
+               ifr->ifr_mtu = SDLA_CPU_16M;
+       else if (jiffs < 220)
+               ifr->ifr_mtu = SDLA_CPU_10M;
+       else if (jiffs < 258)
+               ifr->ifr_mtu = SDLA_CPU_8M;
+       else if (jiffs < 357)
+               ifr->ifr_mtu = SDLA_CPU_7M;
+       else if (jiffs < 467)
+               ifr->ifr_mtu = SDLA_CPU_5M;
+       else
+               ifr->ifr_mtu = SDLA_CPU_3M;
  
-   return(0);
+       return(0);
 }
 
 /************************************************
@@ -316,175 +313,174 @@ static int sdla_cpuspeed(struct device *dev, struct ifreq *ifr)
  *
  ************************************************/
 
-struct _dlci_stat {
-   short dlci          __attribute__((packed));
-   char  flags         __attribute__((packed));
+struct _dlci_stat 
+{
+       short dlci              __attribute__((packed));
+       char  flags             __attribute__((packed));
 };
 
-struct _frad_stat {
-   char    flags;
-   struct _dlci_stat dlcis[SDLA_MAX_DLCI];
+struct _frad_stat 
+{
+       char    flags;
+       struct _dlci_stat dlcis[SDLA_MAX_DLCI];
 };
 
 static void sdla_errors(struct device *dev, int cmd, int dlci, int ret, int len, void *data) 
 {
-   struct _dlci_stat *pstatus;
-   short             *pdlci;
-   int               i;
-   char              *state, line[30];
-
-   switch (ret)
-   {
-      case SDLA_RET_MODEM:
-         state = data;
-         if (*state & SDLA_MODEM_DCD_LOW)
-            printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
-         if (*state & SDLA_MODEM_CTS_LOW)
-            printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
-/* I should probably do something about this! */
-         break;
-
-      case SDLA_RET_CHANNEL_OFF:
-         printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
-/* same here */
-         break;
-
-      case SDLA_RET_CHANNEL_ON:
-         printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
-/* same here */
-         break;
-
-      case SDLA_RET_DLCI_STATUS:
-         printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
-         len /= sizeof(struct _dlci_stat);
-         for(pstatus = data, i=0;i < len;i++,pstatus++)
-         {
-            if (pstatus->flags & SDLA_DLCI_NEW)
-               state = "new";
-            else
-               if (pstatus->flags & SDLA_DLCI_DELETED)
-                  state = "deleted";
-               else
-                  if (pstatus->flags & SDLA_DLCI_ACTIVE)
-                     state = "active";
-                  else
-                  {
-                     sprintf(line, "unknown status: %02X", pstatus->flags);
-                     state = line;
-                  }
-            printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
-/* same here */
-         }
-         break;
-
-      case SDLA_RET_DLCI_UNKNOWN:
-         printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
-         len /= sizeof(short);
-         for(pdlci = data,i=0;i < len;i++,pdlci++)
-            printk(" %i", *pdlci);
-         printk("\n");
-         break;
-
-      case SDLA_RET_TIMEOUT:
-         printk(KERN_ERR "%s: Command timed out!\n", dev->name);
-         break;
-
-      case SDLA_RET_BUF_OVERSIZE:
-         printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
-         break;
-
-      case SDLA_RET_BUF_TOO_BIG:
-         printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
-         break;
-
-      case SDLA_RET_CHANNEL_INACTIVE:
-      case SDLA_RET_DLCI_INACTIVE:
-      case SDLA_RET_CIR_OVERFLOW:
-      case SDLA_RET_NO_BUFS:
-         if (cmd == SDLA_INFORMATION_WRITE)
-            break;
-
-      default: 
-         printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
-/* Further processing could be done here */
-         break;
-   }
+       struct _dlci_stat *pstatus;
+       short             *pdlci;
+       int               i;
+       char              *state, line[30];
+
+       switch (ret)
+       {
+               case SDLA_RET_MODEM:
+                       state = data;
+                       if (*state & SDLA_MODEM_DCD_LOW)
+                               printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
+                       if (*state & SDLA_MODEM_CTS_LOW)
+                               printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
+                       /* I should probably do something about this! */
+                       break;
+
+               case SDLA_RET_CHANNEL_OFF:
+                       printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
+                       /* same here */
+                       break;
+
+               case SDLA_RET_CHANNEL_ON:
+                       printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
+                       /* same here */
+                       break;
+
+               case SDLA_RET_DLCI_STATUS:
+                       printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
+                       len /= sizeof(struct _dlci_stat);
+                       for(pstatus = data, i=0;i < len;i++,pstatus++)
+                       {
+                               if (pstatus->flags & SDLA_DLCI_NEW)
+                                       state = "new";
+                               else if (pstatus->flags & SDLA_DLCI_DELETED)
+                                       state = "deleted";
+                               else if (pstatus->flags & SDLA_DLCI_ACTIVE)
+                                       state = "active";
+                               else
+                               {
+                                       sprintf(line, "unknown status: %02X", pstatus->flags);
+                                       state = line;
+                               }
+                               printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
+                               /* same here */
+                       }
+                       break;
+
+               case SDLA_RET_DLCI_UNKNOWN:
+                       printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
+                       len /= sizeof(short);
+                       for(pdlci = data,i=0;i < len;i++,pdlci++)
+                               printk(" %i", *pdlci);
+                       printk("\n");
+                       break;
+
+               case SDLA_RET_TIMEOUT:
+                       printk(KERN_ERR "%s: Command timed out!\n", dev->name);
+                       break;
+
+               case SDLA_RET_BUF_OVERSIZE:
+                       printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
+                       break;
+
+               case SDLA_RET_BUF_TOO_BIG:
+                       printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
+                       break;
+
+               case SDLA_RET_CHANNEL_INACTIVE:
+               case SDLA_RET_DLCI_INACTIVE:
+               case SDLA_RET_CIR_OVERFLOW:
+               case SDLA_RET_NO_BUFS:
+                       if (cmd == SDLA_INFORMATION_WRITE)
+                               break;
+
+               default: 
+                       printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
+                       /* Further processing could be done here */
+                       break;
+       }
 }
 
 static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags, 
                         void *inbuf, short inlen, void *outbuf, short *outlen)
 {
-   static struct _frad_stat status;
-   struct frad_local        *flp;
-   struct sdla_cmd          *cmd_buf;
-   unsigned long            pflags;
-   int                      jiffs, ret, waiting, len;
-   long                     window;
-
-   flp = dev->priv;
-
-   window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
-   cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
-   ret = 0;
-   len = 0;
-   jiffs = jiffies + HZ;  /* 1 second is plenty */
-   save_flags(pflags);
-   cli();
-   SDLA_WINDOW(dev, window);
-   cmd_buf->cmd = cmd;
-   cmd_buf->dlci = dlci;
-   cmd_buf->flags = flags;
-
-   if (inbuf)
-      memcpy(cmd_buf->data, inbuf, inlen);
-
-   cmd_buf->length = inlen;
-
-   cmd_buf->opp_flag = 1;
-   restore_flags(pflags);
-
-   waiting = 1;
-   len = 0;
-   while (waiting && (jiffies <= jiffs))
-   {
-      if (waiting++ % 3) 
-      {
-         save_flags(pflags);
-         cli();
-         SDLA_WINDOW(dev, window);
-         waiting = ((volatile)(cmd_buf->opp_flag));
-         restore_flags(pflags);
-      }
-   }
-   
-   if (!waiting)
-   {
-      save_flags(pflags);
-      cli();
-      SDLA_WINDOW(dev, window);
-      ret = cmd_buf->retval;
-      len = cmd_buf->length;
-      if (outbuf && outlen)
-      {
-         *outlen = *outlen >= len ? len : *outlen;
-
-         if (*outlen)
-            memcpy(outbuf, cmd_buf->data, *outlen);
-      }
-
-      /* This is a local copy that's used for error handling */
-      if (ret)
-         memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
-
-      restore_flags(pflags);
-   }
-   else
-      ret = SDLA_RET_TIMEOUT;
-
-   if (ret != SDLA_RET_OK)
-      sdla_errors(dev, cmd, dlci, ret, len, &status);
-
-   return(ret);
+       static struct _frad_stat status;
+       struct frad_local        *flp;
+       struct sdla_cmd          *cmd_buf;
+       unsigned long            pflags;
+       int                      jiffs, ret, waiting, len;
+       long                     window;
+
+       flp = dev->priv;
+       window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
+       cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
+       ret = 0;
+       len = 0;
+       jiffs = jiffies + HZ;  /* 1 second is plenty */
+       save_flags(pflags);
+       cli();
+       SDLA_WINDOW(dev, window);
+       cmd_buf->cmd = cmd;
+       cmd_buf->dlci = dlci;
+       cmd_buf->flags = flags;
+
+       if (inbuf)
+               amemcpy(cmd_buf->data, inbuf, inlen);
+
+       cmd_buf->length = inlen;
+
+       cmd_buf->opp_flag = 1;
+       restore_flags(pflags);
+
+       waiting = 1;
+       len = 0;
+       while (waiting && (jiffies <= jiffs))
+       {
+               if (waiting++ % 3) 
+               {
+                       save_flags(pflags);
+                       cli();
+                       SDLA_WINDOW(dev, window);
+                       waiting = ((volatile)(cmd_buf->opp_flag));
+                       restore_flags(pflags);
+               }
+       }
+       
+       if (!waiting)
+       {
+               save_flags(pflags);
+               cli();
+               SDLA_WINDOW(dev, window);
+               ret = cmd_buf->retval;
+               len = cmd_buf->length;
+               if (outbuf && outlen)
+               {
+                       *outlen = *outlen >= len ? len : *outlen;
+
+                       if (*outlen)
+                               memcpy(outbuf, cmd_buf->data, *outlen);
+               }
+
+               /* This is a local copy that's used for error handling */
+               if (ret)
+                       memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
+
+               restore_flags(pflags);
+       }
+       else
+               ret = SDLA_RET_TIMEOUT;
+
+       if (ret != SDLA_RET_OK)
+               sdla_errors(dev, cmd, dlci, ret, len, &status);
+
+       return(ret);
 }
 
 /***********************************************
@@ -497,141 +493,141 @@ static int sdla_reconfig(struct device *dev);
 
 int sdla_activate(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+       struct frad_local *flp;
+       int i;
 
-   flp = slave->priv;
+       flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->master[i] == master)
+                       break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+       if (i == CONFIG_DLCI_MAX)
+               return(-ENODEV);
 
-   flp->dlci[i] = abs(flp->dlci[i]);
+       flp->dlci[i] = abs(flp->dlci[i]);
 
-   if (slave->start && (flp->config.station == FRAD_STATION_NODE))
-      sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
+       if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+               sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
 
-   return(0);
+       return(0);
 }
 
 int sdla_deactivate(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+       struct frad_local *flp;
+       int               i;
 
-   flp = slave->priv;
+       flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->master[i] == master)
+                       break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+       if (i == CONFIG_DLCI_MAX)
+               return(-ENODEV);
 
-   flp->dlci[i] = -abs(flp->dlci[i]);
+       flp->dlci[i] = -abs(flp->dlci[i]);
 
-   if (slave->start && (flp->config.station == FRAD_STATION_NODE))
-      sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
+       if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+               sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
 
-   return(0);
+       return(0);
 }
 
 int sdla_assoc(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+       struct frad_local *flp;
+       int               i;
 
-   if (master->type != ARPHRD_DLCI)
-      return(-EINVAL);
+       if (master->type != ARPHRD_DLCI)
+               return(-EINVAL);
 
-   flp = slave->priv;
+       flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-   {
-      if (!flp->master[i])
-         break;
-      if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
-         return(-EADDRINUSE);
-   } 
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+       {
+               if (!flp->master[i])
+                       break;
+               if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
+                       return(-EADDRINUSE);
+       
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-EMLINK);  /* #### Alan: Comments on this ?? */
+       if (i == CONFIG_DLCI_MAX)
+               return(-EMLINK);  /* #### Alan: Comments on this ?? */
 
-   MOD_INC_USE_COUNT;
+       MOD_INC_USE_COUNT;
 
-   flp->master[i] = master;
-   flp->dlci[i] = -*(short *)(master->dev_addr);
-   master->mtu = slave->mtu;
+       flp->master[i] = master;
+       flp->dlci[i] = -*(short *)(master->dev_addr);
+       master->mtu = slave->mtu;
 
-   if (slave->start)
-      if (flp->config.station == FRAD_STATION_CPE)
-         sdla_reconfig(slave);
-      else
-         sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+       if (slave->start)
+               if (flp->config.station == FRAD_STATION_CPE)
+                       sdla_reconfig(slave);
+               else
+                       sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
 
-   return(0);
+       return(0);
 }
 
 int sdla_deassoc(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+       struct frad_local *flp;
+       int               i;
 
-   flp = slave->priv;
+       flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->master[i] == master)
+                       break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+       if (i == CONFIG_DLCI_MAX)
+               return(-ENODEV);
 
-   flp->master[i] = NULL;
-   flp->dlci[i] = 0;
+       flp->master[i] = NULL;
+       flp->dlci[i] = 0;
 
-   MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
 
-   if (slave->start)
-      if (flp->config.station == FRAD_STATION_CPE)
-         sdla_reconfig(slave);
-      else
-         sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+       if (slave->start)
+               if (flp->config.station == FRAD_STATION_CPE)
+                       sdla_reconfig(slave);
+               else
+                       sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
 
-   return(0);
+       return(0);
 }
 
 int sdla_dlci_conf(struct device *slave, struct device *master, int get)
 {
-   struct frad_local *flp;
-   struct dlci_local *dlp;
-   int               i;
-   short             len, ret;
+       struct frad_local *flp;
+       struct dlci_local *dlp;
+       int               i;
+       short             len, ret;
 
-   flp = slave->priv;
+       flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->master[i] == master)
+                       break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+       if (i == CONFIG_DLCI_MAX)
+               return(-ENODEV);
 
-   dlp = master->priv;
+       dlp = master->priv;
 
-   ret = SDLA_RET_OK;
-   len = sizeof(struct dlci_conf);
-   if (slave->start)
-      if (get)
-         ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
-                     NULL, 0, &dlp->config, &len);
-      else
-         ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
-                     &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+       ret = SDLA_RET_OK;
+       len = sizeof(struct dlci_conf);
+       if (slave->start)
+               if (get)
+                       ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+                                   NULL, 0, &dlp->config, &len);
+               else
+                       ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+                                   &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
 
-   return(ret == SDLA_RET_OK ? 0 : -EIO);
+       return(ret == SDLA_RET_OK ? 0 : -EIO);
 }
 
 /**************************
@@ -643,656 +639,643 @@ int sdla_dlci_conf(struct device *slave, struct device *master, int get)
 /* NOTE: the DLCI driver deals with freeing the SKB!! */
 static int sdla_transmit(struct sk_buff *skb, struct device *dev)
 {
-   struct frad_local *flp;
-   int               ret, addr, accept;
-   short             size;
-   unsigned long     flags;
-   struct buf_entry  *pbuf;
-
-   flp = dev->priv;
-   ret = 0;
-   accept = 1;
-
-   if (dev->tbusy) 
-      return(1);
-
-   if (skb == NULL) 
-      return(0);
-
-   if (set_bit(0, (void*)&dev->tbusy) != 0)
-      printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-   else
-   {
-      /*
-       * stupid GateD insists on setting up the multicast router thru us
-       * and we're ill equipped to handle a non Frame Relay packet at this
-       * time!
-       */
-
-      accept = 1;
-      switch (dev->type)
-      {
-         case ARPHRD_FRAD:
-            if (skb->dev->type != ARPHRD_DLCI)
-            {
-               printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
-               accept = 0;
-            }
-            break;
-
-         default:
-            printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
-            accept = 0;
-            break;
-      }
-
-      if (accept)
-      {
-         /* this is frame specific, but till there's a PPP module, it's the default */
-         switch (flp->type)
-         {
-            case SDLA_S502A:
-            case SDLA_S502E:
-               ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
-               break;
-
-            case SDLA_S508:
-               size = sizeof(addr);
-               ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
-               if (ret == SDLA_RET_OK)
-               {
-                  save_flags(flags); 
-                  cli();
-                  SDLA_WINDOW(dev, addr);
-                  pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
-
-                  sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
-
-                  SDLA_WINDOW(dev, addr);
-                  pbuf->opp_flag = 1;
-                  restore_flags(flags);
-               }
-               break;
-         }
-
-         switch (ret)
-         {
-            case SDLA_RET_OK:
-               flp->stats.tx_packets++;
-               ret = DLCI_RET_OK;
-               break;
-
-            case SDLA_RET_CIR_OVERFLOW:
-            case SDLA_RET_BUF_OVERSIZE:
-            case SDLA_RET_NO_BUFS:
-               flp->stats.tx_dropped++;
-               ret = DLCI_RET_DROP;
-               break;
-
-            default:
-               flp->stats.tx_errors++;
-               ret = DLCI_RET_ERR;
-               break;
-         }
-      }
-      dev->tbusy = 0;
-   }
-   return(ret);
+       struct frad_local *flp;
+       int               ret, addr, accept;
+       short             size;
+       unsigned long     flags;
+       struct buf_entry  *pbuf;
+
+       flp = dev->priv;
+       ret = 0;
+       accept = 1;
+
+       if (dev->tbusy) 
+               return(1);
+
+       if (skb == NULL) 
+               return(0);
+
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
+       else
+       {
+               /*
+                * stupid GateD insists on setting up the multicast router thru us
+                * and we're ill equipped to handle a non Frame Relay packet at this
+                * time!
+                */
+
+               accept = 1;
+               switch (dev->type)
+               {
+                       case ARPHRD_FRAD:
+                               if (skb->dev->type != ARPHRD_DLCI)
+                               {
+                                       printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
+                                       accept = 0;
+                               }
+                               break;
+
+                       default:
+                               printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
+                               accept = 0;
+                               break;
+               }
+
+               if (accept)
+               {
+                       /* this is frame specific, but till there's a PPP module, it's the default */
+                       switch (flp->type)
+                       {
+                               case SDLA_S502A:
+                               case SDLA_S502E:
+                                       ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
+                                       break;
+
+                               case SDLA_S508:
+                                       size = sizeof(addr);
+                                       ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
+                                       if (ret == SDLA_RET_OK)
+                                       {
+                                               save_flags(flags); 
+                                               cli();
+                                               SDLA_WINDOW(dev, addr);
+                                               pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+
+                                               sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
+
+                                               SDLA_WINDOW(dev, addr);
+                                               pbuf->opp_flag = 1;
+                                               restore_flags(flags);
+                                       }
+                                       break;
+                       }
+
+                       switch (ret)
+                       {
+                               case SDLA_RET_OK:
+                                       flp->stats.tx_packets++;
+                                       ret = DLCI_RET_OK;
+                                       break;
+
+                               case SDLA_RET_CIR_OVERFLOW:
+                               case SDLA_RET_BUF_OVERSIZE:
+                               case SDLA_RET_NO_BUFS:
+                                       flp->stats.tx_dropped++;
+                                       ret = DLCI_RET_DROP;
+                                       break;
+
+                               default:
+                                       flp->stats.tx_errors++;
+                                       ret = DLCI_RET_ERR;
+                                       break;
+                       }
+               }
+               dev->tbusy = 0;
+       }
+       return(ret);
 }
 
 static void sdla_receive(struct device *dev)
 {
-   struct device     *master;
-   struct frad_local *flp;
-   struct dlci_local *dlp;
-   struct sk_buff    *skb;
-
-   struct sdla_cmd   *cmd;
-   struct buf_info   *pbufi;
-   struct buf_entry  *pbuf;
-
-   unsigned long     flags;
-   int               i, received, success, addr, buf_base, buf_top;
-   short             dlci, len, len2, split;
-
-   flp = dev->priv;
-   success = 1;
-   received = addr = buf_top = buf_base = 0;
-   len = dlci = 0;
-   skb = NULL;
-   master = NULL;
-   cmd = NULL;
-   pbufi = NULL;
-   pbuf = NULL;
-
-   save_flags(flags);
-   cli();
-
-   switch (flp->type)
-   {
-      case SDLA_S502A:
-      case SDLA_S502E:
-         cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
-         SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-         success = cmd->opp_flag;
-         if (!success)
-            break;
-
-         dlci = cmd->dlci;
-         len = cmd->length;
-         break;
-
-      case SDLA_S508:
-         pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
-         SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
-         success = pbuf->opp_flag;
-         if (!success)
-            break;
-
-         buf_top = pbufi->buf_top;
-         buf_base = pbufi->buf_base;
-         dlci = pbuf->dlci;
-         len = pbuf->length;
-         addr = pbuf->buf_addr;
-         break;
-   }
-
-   /* common code, find the DLCI and get the SKB */
-   if (success)
-   {
-      for (i=0;i<CONFIG_DLCI_MAX;i++)
-         if (flp->dlci[i] == dlci)
-            break;
-
-      if (i == CONFIG_DLCI_MAX)
-      {
-         printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
-         flp->stats.rx_errors++;
-         success = 0;
-      }
-   }
-
-   if (success)
-   {
-      master = flp->master[i];
-      skb = dev_alloc_skb(len + sizeof(struct frhdr));
-      if (skb == NULL) 
-      {
-         printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-         flp->stats.rx_dropped++; 
-         success = 0;
-      }
-      else
-         skb_reserve(skb, sizeof(struct frhdr));
-   }
-
-   /* pick up the data */
-   switch (flp->type)
-   {
-      case SDLA_S502A:
-      case SDLA_S502E:
-         if (success)
-            sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
-
-         SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-         cmd->opp_flag = 0;
-         break;
-
-      case SDLA_S508:
-         if (success)
-         {
-            /* is this buffer split off the end of the internal ring buffer */
-            split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
-            len2 = len - split;
-
-            sdla_read(dev, addr, skb_put(skb, len2), len2);
-            if (split)
-               sdla_read(dev, buf_base, skb_put(skb, split), split);
-         }
-
-         /* increment the buffer we're looking at */
-         SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
-         pbuf->opp_flag = 0;
-         break;
-   }
-
-   if (success)
-   {
-      flp->stats.rx_packets++;
-      dlp = master->priv;
-      (*dlp->receive)(skb, master);
-   }
-
-   restore_flags(flags);
+       struct device     *master;
+       struct frad_local *flp;
+       struct dlci_local *dlp;
+       struct sk_buff   *skb;
+
+       struct sdla_cmd *cmd;
+       struct buf_info *pbufi;
+       struct buf_entry  *pbuf;
+
+       unsigned long     flags;
+       int               i, received, success, addr, buf_base, buf_top;
+       short             dlci, len, len2, split;
+
+       flp = dev->priv;
+       success = 1;
+       received = addr = buf_top = buf_base = 0;
+       len = dlci = 0;
+       skb = NULL;
+       master = NULL;
+       cmd = NULL;
+       pbufi = NULL;
+       pbuf = NULL;
+
+       save_flags(flags);
+       cli();
+
+       switch (flp->type)
+       {
+               case SDLA_S502A:
+               case SDLA_S502E:
+                       cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
+                       SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+                       success = cmd->opp_flag;
+                       if (!success)
+                               break;
+
+                       dlci = cmd->dlci;
+                       len = cmd->length;
+                       break;
+
+               case SDLA_S508:
+                       pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
+                       SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
+                       pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
+                       success = pbuf->opp_flag;
+                       if (!success)
+                               break;
+
+                       buf_top = pbufi->buf_top;
+                       buf_base = pbufi->buf_base;
+                       dlci = pbuf->dlci;
+                       len = pbuf->length;
+                       addr = pbuf->buf_addr;
+                       break;
+       }
+
+       /* common code, find the DLCI and get the SKB */
+       if (success)
+       {
+               for (i=0;i<CONFIG_DLCI_MAX;i++)
+                       if (flp->dlci[i] == dlci)
+                               break;
+
+               if (i == CONFIG_DLCI_MAX)
+               {
+                       printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
+                       flp->stats.rx_errors++;
+                       success = 0;
+               }
+       }
+
+       if (success)
+       {
+               master = flp->master[i];
+               skb = dev_alloc_skb(len + sizeof(struct frhdr));
+               if (skb == NULL) 
+               {
+                       printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+                       flp->stats.rx_dropped++; 
+                       success = 0;
+               }
+               else
+                       skb_reserve(skb, sizeof(struct frhdr));
+       }
+
+       /* pick up the data */
+       switch (flp->type)
+       {
+               case SDLA_S502A:
+               case SDLA_S502E:
+                       if (success)
+                               sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
+
+                       SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+                       cmd->opp_flag = 0;
+                       break;
+
+               case SDLA_S508:
+                       if (success)
+                       {
+                               /* is this buffer split off the end of the internal ring buffer */
+                               split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
+                               len2 = len - split;
+
+                               sdla_read(dev, addr, skb_put(skb, len2), len2);
+                               if (split)
+                                       sdla_read(dev, buf_base, skb_put(skb, split), split);
+                       }
+
+                       /* increment the buffer we're looking at */
+                       SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
+                       flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
+                       pbuf->opp_flag = 0;
+                       break;
+       }
+
+       if (success)
+       {
+               flp->stats.rx_packets++;
+               dlp = master->priv;
+               (*dlp->receive)(skb, master);
+       }
+
+       restore_flags(flags);
 }
 
 static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
-   struct device     *dev;
-   struct frad_local *flp;
-   char              byte;
-
-   dev = irq2dev_map[irq];
-
-   if (dev == NULL)
-   {
-      printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
-      return;
-   }
-
-   flp = dev->priv;
-
-   if (!flp->initialized)
-   {
-      printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
-      return;
-   }
-
-   dev->interrupt = 1;
-   byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
-   switch (byte)
-   {
-      case SDLA_INTR_RX:
-         sdla_receive(dev);
-         break;
-
-      /* the command will get an error return, which is processed above */
-      case SDLA_INTR_MODEM:
-      case SDLA_INTR_STATUS:
-         sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
-         break;
-
-      case SDLA_INTR_TX:
-      case SDLA_INTR_COMPLETE:
-      case SDLA_INTR_TIMER:
-         printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
-         break;
-   }
-
-   /* the S502E requires a manual acknowledgement of the interrupt */ 
-   if (flp->type == SDLA_S502E)
-   {
-      flp->state &= ~SDLA_S502E_INTACK;
-      outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-      flp->state |= SDLA_S502E_INTACK;
-      outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-   }
-
-   /* this clears the byte, informing the Z80 we're done */
-   byte = 0;
-   sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
-   dev->interrupt = 0;
+       struct device     *dev;
+       struct frad_local *flp;
+       char              byte;
+
+       dev = irq2dev_map[irq];
+
+       if (dev == NULL)
+       {
+               printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
+               return;
+       }
+
+       flp = dev->priv;
+
+       if (!flp->initialized)
+       {
+               printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
+               return;
+       }
+
+       dev->interrupt = 1;
+       byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
+       switch (byte)
+       {
+               case SDLA_INTR_RX:
+                       sdla_receive(dev);
+                       break;
+
+               /* the command will get an error return, which is processed above */
+               case SDLA_INTR_MODEM:
+               case SDLA_INTR_STATUS:
+                       sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
+                       break;
+
+               case SDLA_INTR_TX:
+               case SDLA_INTR_COMPLETE:
+               case SDLA_INTR_TIMER:
+                       printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
+                       break;
+       }
+
+       /* the S502E requires a manual acknowledgement of the interrupt */ 
+       if (flp->type == SDLA_S502E)
+       {
+               flp->state &= ~SDLA_S502E_INTACK;
+               outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+               flp->state |= SDLA_S502E_INTACK;
+               outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+       }
+
+       /* this clears the byte, informing the Z80 we're done */
+       byte = 0;
+       sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+       dev->interrupt = 0;
 }
 
 static void sdla_poll(unsigned long device)
 {
-   struct device     *dev;
-   struct frad_local *flp;
+       struct device     *dev;
+       struct frad_local *flp;
 
-   dev = (struct device *) device;
-   flp = dev->priv;
+       dev = (struct device *) device;
+       flp = dev->priv;
 
-   if (sdla_byte(dev, SDLA_502_RCV_BUF))
-      sdla_receive(dev);
+       if (sdla_byte(dev, SDLA_502_RCV_BUF))
+               sdla_receive(dev);
 
-   flp->timer.expires = 1;
-   add_timer(&flp->timer);
+       flp->timer.expires = 1;
+       add_timer(&flp->timer);
 }
 
 static int sdla_close(struct device *dev)
 {
-   struct frad_local *flp;
-   struct intr_info  intr;
-   int               len, i;
-   short             dlcis[CONFIG_DLCI_MAX];
-
-   flp = dev->priv;
-
-   len = 0;
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-         dlcis[len++] = abs(flp->dlci[i]);
-   len *= 2;
-
-   if (flp->config.station == FRAD_STATION_NODE)
-   {
-      for(i=0;i<CONFIG_DLCI_MAX;i++)
-         if (flp->dlci[i] > 0) 
-            sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
-      sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
-   }
-
-   memset(&intr, 0, sizeof(intr));
-   /* let's start up the reception */
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         del_timer(&flp->timer); 
-         break;
-
-      case SDLA_S502E:
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
-         flp->state &= ~SDLA_S502E_INTACK;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-
-      case SDLA_S507:
-         break;
-
-      case SDLA_S508:
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
-         flp->state &= ~SDLA_S508_INTEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-   }
-
-   sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-
-   dev->tbusy = 1;
-   dev->start = 0;
-
-   MOD_DEC_USE_COUNT;
-
-   return(0);
+       struct frad_local *flp;
+       struct intr_info  intr;
+       int               len, i;
+       short             dlcis[CONFIG_DLCI_MAX];
+
+       flp = dev->priv;
+
+       len = 0;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->dlci[i])
+                       dlcis[len++] = abs(flp->dlci[i]);
+       len *= 2;
+
+       if (flp->config.station == FRAD_STATION_NODE)
+       {
+               for(i=0;i<CONFIG_DLCI_MAX;i++)
+                       if (flp->dlci[i] > 0) 
+                               sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
+               sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
+       }
+
+       memset(&intr, 0, sizeof(intr));
+       /* let's start up the reception */
+       switch(flp->type)
+       {
+               case SDLA_S502A:
+                       del_timer(&flp->timer); 
+                       break;
+
+               case SDLA_S502E:
+                       sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
+                       flp->state &= ~SDLA_S502E_INTACK;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       break;
+
+               case SDLA_S507:
+                       break;
+
+               case SDLA_S508:
+                       sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
+                       flp->state &= ~SDLA_S508_INTEN;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       break;
+       }
+
+       sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       MOD_DEC_USE_COUNT;
+
+       return(0);
 }
 
 struct conf_data {
-   struct frad_conf config;
-   short            dlci[CONFIG_DLCI_MAX];
+       struct frad_conf config;
+       short            dlci[CONFIG_DLCI_MAX];
 };
 
 static int sdla_open(struct device *dev)
 {
-   struct frad_local *flp;
-   struct dlci_local *dlp;
-   struct conf_data  data;
-   struct intr_info  intr;
-   int               len, i;
-   char              byte;
-
-   flp = dev->priv;
-
-   if (!flp->initialized)
-      return(-EPERM);
-
-   if (!flp->configured)
-      return(-EPERM);
-
-   /* time to send in the configuration */
-   len = 0;
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-         data.dlci[len++] = abs(flp->dlci[i]);
-   len *= 2;
-
-   memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
-   len += sizeof(struct frad_conf);
-
-   sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-   sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
-
-   if (flp->type == SDLA_S508)
-      flp->buffer = 0;
-
-   sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-
-   /* let's start up the reception */
-   memset(&intr, 0, sizeof(intr));
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         flp->timer.expires = 1;
-         add_timer(&flp->timer);
-         break;
-
-      case SDLA_S502E:
-         flp->state |= SDLA_S502E_ENABLE;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state |= SDLA_S502E_INTACK;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         byte = 0;
-         sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
-         intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
-         break;
-
-      case SDLA_S507:
-         break;
-
-      case SDLA_S508:
-         flp->state |= SDLA_S508_INTEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         byte = 0;
-         sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
-         intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
-         intr.irq = dev->irq;
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
-         break;
-   }
-
-   if (flp->config.station == FRAD_STATION_CPE)
-   {
-      byte = SDLA_ICS_STATUS_ENQ;
-      sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
-   }
-   else
-   {
-      sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
-      for(i=0;i<CONFIG_DLCI_MAX;i++)
-         if (flp->dlci[i] > 0)
-            sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
-   }
-
-   /* configure any specific DLCI settings */
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-      {
-         dlp = flp->master[i]->priv;
-         if (dlp->configured)
-            sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
-      }
-
-   dev->tbusy = 0;
-   dev->interrupt = 0;
-   dev->start = 1;
-
-   MOD_INC_USE_COUNT;
-
-   return(0);
+       struct frad_local *flp;
+       struct dlci_local *dlp;
+       struct conf_data  data;
+       struct intr_info  intr;
+       int               len, i;
+       char              byte;
+
+       flp = dev->priv;
+
+       if (!flp->initialized)
+               return(-EPERM);
+
+       if (!flp->configured)
+               return(-EPERM);
+
+       /* time to send in the configuration */
+       len = 0;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->dlci[i])
+                       data.dlci[len++] = abs(flp->dlci[i]);
+       len *= 2;
+
+       memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+       len += sizeof(struct frad_conf);
+
+       sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+       sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
+
+       if (flp->type == SDLA_S508)
+               flp->buffer = 0;
+
+       sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+
+       /* let's start up the reception */
+       memset(&intr, 0, sizeof(intr));
+       switch(flp->type)
+       {
+               case SDLA_S502A:
+                       flp->timer.expires = 1;
+                       add_timer(&flp->timer);
+                       break;
+
+               case SDLA_S502E:
+                       flp->state |= SDLA_S502E_ENABLE;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       flp->state |= SDLA_S502E_INTACK;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       byte = 0;
+                       sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+                       intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
+                       sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
+                       break;
+
+               case SDLA_S507:
+                       break;
+
+               case SDLA_S508:
+                       flp->state |= SDLA_S508_INTEN;
+                       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+                       byte = 0;
+                       sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
+                       intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
+                       intr.irq = dev->irq;
+                       sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
+                       break;
+       }
+
+       if (flp->config.station == FRAD_STATION_CPE)
+       {
+               byte = SDLA_ICS_STATUS_ENQ;
+               sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
+       }
+       else
+       {
+               sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
+               for(i=0;i<CONFIG_DLCI_MAX;i++)
+                       if (flp->dlci[i] > 0)
+                               sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
+       }
+
+       /* configure any specific DLCI settings */
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->dlci[i])
+               {
+                       dlp = flp->master[i]->priv;
+                       if (dlp->configured)
+                               sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
+               }
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       MOD_INC_USE_COUNT;
+
+       return(0);
 }
 
 static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
 {
-   struct frad_local *flp;
-   struct conf_data  data;
-   int               i, err;
-   short             size;
-
-   if (dev->type == 0xFFFF)
-      return(-EUNATCH);
-
-   flp = dev->priv;
-
-   if (!get)
-   {
-      if (dev->start)
-         return(-EBUSY);
-
-      err = verify_area(VERIFY_READ, conf, sizeof(struct frad_conf));
-      if (err)
-         return(err);
-
-      copy_from_user(&data.config, conf, sizeof(struct frad_conf));
-
-      if (data.config.station & ~FRAD_STATION_NODE)
-         return(-EINVAL);
-
-      if (data.config.flags & ~FRAD_VALID_FLAGS)
-         return(-EINVAL);
-
-      if ((data.config.kbaud < 0) || 
-          ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
-         return(-EINVAL);
-
-      if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
-         return(-EINVAL);
-
-      if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
-         return(-EINVAL);
-
-      if ((data.config.T391 < 5) || (data.config.T391 > 30))
-         return(-EINVAL);
-
-      if ((data.config.T392 < 5) || (data.config.T392 > 30))
-         return(-EINVAL);
-
-      if ((data.config.N391 < 1) || (data.config.N391 > 255))
-         return(-EINVAL);
-
-      if ((data.config.N392 < 1) || (data.config.N392 > 10))
-         return(-EINVAL);
-
-      if ((data.config.N393 < 1) || (data.config.N393 > 10))
-         return(-EINVAL);
-
-      memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-      flp->config.flags |= SDLA_DIRECT_RECV;
-
-      if (flp->type == SDLA_S508)
-         flp->config.flags |= SDLA_TX70_RX30;
-
-      if (dev->mtu != flp->config.mtu)
-      {
-         /* this is required to change the MTU */
-         dev->mtu = flp->config.mtu;
-         for(i=0;i<CONFIG_DLCI_MAX;i++)
-            if (flp->master[i])
-               flp->master[i]->mtu = flp->config.mtu;
-      }
-
-      flp->config.mtu += sizeof(struct frhdr);
-
-      /* off to the races! */
-      if (!flp->configured)
-         sdla_start(dev);
-
-      flp->configured = 1;
-   }
-   else
-   {
-      err = verify_area(VERIFY_WRITE, conf, sizeof(struct frad_conf));
-      if (err)
-         return(err);
-
-      /* no sense reading if the CPU isn't started */
-      if (dev->start)
-      {
-         size = sizeof(data);
-         if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
-            return(-EIO);
-      }
-      else
-         if (flp->configured)
-            memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
-         else
-            memset(&data.config, 0, sizeof(struct frad_conf));
-
-      memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-      data.config.flags &= FRAD_VALID_FLAGS;
-      data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
-      copy_to_user(conf, &data.config, sizeof(struct frad_conf));
-   }
-
-   return(0);
+       struct frad_local *flp;
+       struct conf_data  data;
+       int               i, err;
+       short             size;
+
+       if (dev->type == 0xFFFF)
+               return(-EUNATCH);
+
+       flp = dev->priv;
+
+       if (!get)
+       {
+               if (dev->start)
+                       return(-EBUSY);
+
+               if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
+                       return -EFAULT;
+
+               if (data.config.station & ~FRAD_STATION_NODE)
+                       return(-EINVAL);
+
+               if (data.config.flags & ~FRAD_VALID_FLAGS)
+                       return(-EINVAL);
+
+               if ((data.config.kbaud < 0) || 
+                        ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
+                       return(-EINVAL);
+
+               if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
+                       return(-EINVAL);
+
+               if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
+                       return(-EINVAL);
+
+               if ((data.config.T391 < 5) || (data.config.T391 > 30))
+                       return(-EINVAL);
+
+               if ((data.config.T392 < 5) || (data.config.T392 > 30))
+                       return(-EINVAL);
+
+               if ((data.config.N391 < 1) || (data.config.N391 > 255))
+                       return(-EINVAL);
+
+               if ((data.config.N392 < 1) || (data.config.N392 > 10))
+                       return(-EINVAL);
+
+               if ((data.config.N393 < 1) || (data.config.N393 > 10))
+                       return(-EINVAL);
+
+               memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+               flp->config.flags |= SDLA_DIRECT_RECV;
+
+               if (flp->type == SDLA_S508)
+                       flp->config.flags |= SDLA_TX70_RX30;
+
+               if (dev->mtu != flp->config.mtu)
+               {
+                       /* this is required to change the MTU */
+                       dev->mtu = flp->config.mtu;
+                       for(i=0;i<CONFIG_DLCI_MAX;i++)
+                               if (flp->master[i])
+                                       flp->master[i]->mtu = flp->config.mtu;
+               }
+
+               flp->config.mtu += sizeof(struct frhdr);
+
+               /* off to the races! */
+               if (!flp->configured)
+                       sdla_start(dev);
+
+               flp->configured = 1;
+       }
+       else
+       {
+               /* no sense reading if the CPU isn't started */
+               if (dev->start)
+               {
+                       size = sizeof(data);
+                       if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
+                               return(-EIO);
+               }
+               else
+                       if (flp->configured)
+                               memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+                       else
+                               memset(&data.config, 0, sizeof(struct frad_conf));
+
+               memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+               data.config.flags &= FRAD_VALID_FLAGS;
+               data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
+               return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
+       }
+
+       return(0);
 }
 
 static int sdla_xfer(struct device *dev, struct sdla_mem *info, int read)
 {
-   struct sdla_mem mem;
-   int    err;
-   char   *temp;
-
-   err = verify_area(VERIFY_READ, info, sizeof(struct sdla_mem));
-   if (err)
-      return(err);
-
-   copy_from_user(&mem, info, sizeof(mem));
-   if (read)
-   {
-      err = verify_area(VERIFY_WRITE, mem.data, mem.len);
-      if (err)
-         return(err);
-
-      temp = kmalloc(mem.len, GFP_KERNEL);
-      if (!temp)
-         return(-ENOMEM);
-      sdla_read(dev, mem.addr, temp, mem.len);
-      copy_to_user(mem.data, temp, mem.len);
-      kfree(temp);
-   }
-   else
-   {
-      err = verify_area(VERIFY_READ, mem.data, mem.len);
-      if (err)
-         return(err);
-
-      temp = kmalloc(mem.len, GFP_KERNEL);
-      if (!temp)
-         return(-ENOMEM);
-      copy_from_user(temp, mem.data, mem.len);
-      sdla_write(dev, mem.addr, temp, mem.len);
-      kfree(temp);
-   }
-   return(0);
+       struct sdla_mem mem;
+       char    *temp;
+
+       if(copy_from_user(&mem, info, sizeof(mem)))
+               return -EFAULT;
+               
+       if (read)
+       {       
+               temp = kmalloc(mem.len, GFP_KERNEL);
+               if (!temp)
+                       return(-ENOMEM);
+               sdla_read(dev, mem.addr, temp, mem.len);
+               if(copy_to_user(mem.data, temp, mem.len))
+                       return -EFAULT;
+               kfree(temp);
+       }
+       else
+       {
+               temp = kmalloc(mem.len, GFP_KERNEL);
+               if (!temp)
+                       return(-ENOMEM);
+               if(copy_from_user(temp, mem.data, mem.len))
+                       return -EFAULT;
+               sdla_write(dev, mem.addr, temp, mem.len);
+               kfree(temp);
+       }
+       return(0);
 }
 
 static int sdla_reconfig(struct device *dev)
 {
-   struct frad_local *flp;
-   struct conf_data  data;
-   int               i, len;
+       struct frad_local *flp;
+       struct conf_data  data;
+       int               i, len;
 
-   flp = dev->priv;
+       flp = dev->priv;
 
-   len = 0;
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-         data.dlci[len++] = flp->dlci[i];
-   len *= 2;
+       len = 0;
+       for(i=0;i<CONFIG_DLCI_MAX;i++)
+               if (flp->dlci[i])
+                       data.dlci[len++] = flp->dlci[i];
+       len *= 2;
 
-   memcpy(&data, &flp->config, sizeof(struct frad_conf));
-   len += sizeof(struct frad_conf);
+       memcpy(&data, &flp->config, sizeof(struct frad_conf));
+       len += sizeof(struct frad_conf);
 
-   sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-   sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
-   sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+       sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+       sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
+       sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
 
-   return(0);
+       return(0);
 }
 
 static int sdla_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
-   struct frad_local *flp;
+       struct frad_local *flp;
 
-   flp = dev->priv;
+       if(!suser())
+               return -EPERM;
+               
+       flp = dev->priv;
 
-   if (!flp->initialized)
-      return(-EPERM);
+       if (!flp->initialized)
+               return(-EINVAL);
 
-   switch (cmd)
-   {
-      case FRAD_GET_CONF:
-      case FRAD_SET_CONF:
-         return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF));
+       switch (cmd)
+       {
+               case FRAD_GET_CONF:
+               case FRAD_SET_CONF:
+                       return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF));
 
-      case SDLA_IDENTIFY:
-         ifr->ifr_flags = flp->type;
-         break;
+               case SDLA_IDENTIFY:
+                       ifr->ifr_flags = flp->type;
+                       break;
 
-      case SDLA_CPUSPEED:
-         return(sdla_cpuspeed(dev, ifr)); 
+               case SDLA_CPUSPEED:
+                       return(sdla_cpuspeed(dev, ifr)); 
 
 /* ==========================================================
 NOTE:  This is rather a useless action right now, as the
@@ -1300,391 +1283,396 @@ NOTE:  This is rather a useless action right now, as the
        FR.  However, Sangoma has modules for a number of
        other protocols in the works.
 ============================================================*/
-      case SDLA_PROTOCOL:
-         if (flp->configured)
-            return(-EALREADY);
-
-         switch (ifr->ifr_flags)
-         {
-            case ARPHRD_FRAD:
-               dev->type = ifr->ifr_flags;
-               dev->family = AF_UNSPEC;
-               break;
-
-            default:
-               return(-ENOPROTOOPT);
-         }
-         break;
-
-      case SDLA_CLEARMEM:
-         sdla_clear(dev);
-         break;
-
-      case SDLA_WRITEMEM:
-      case SDLA_READMEM:
-         return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
-
-      case SDLA_START:
-         sdla_start(dev);
-         break;
-
-      case SDLA_STOP:
-         sdla_stop(dev);
-         break;
-
-      default:
-         return(-EOPNOTSUPP);
-   }
-   return(0);
+               case SDLA_PROTOCOL:
+                       if (flp->configured)
+                               return(-EALREADY);
+
+                       switch (ifr->ifr_flags)
+                       {
+                               case ARPHRD_FRAD:
+                                       dev->type = ifr->ifr_flags;
+                                       dev->family = AF_UNSPEC;
+                                       break;
+                               default:
+                                       return(-ENOPROTOOPT);
+                       }
+                       break;
+
+               case SDLA_CLEARMEM:
+                       sdla_clear(dev);
+                       break;
+
+               case SDLA_WRITEMEM:
+               case SDLA_READMEM:
+                       return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
+
+               case SDLA_START:
+                       sdla_start(dev);
+                       break;
+
+               case SDLA_STOP:
+                       sdla_stop(dev);
+                       break;
+
+               default:
+                       return(-EOPNOTSUPP);
+       }
+       return(0);
 }
 
 int sdla_change_mtu(struct device *dev, int new_mtu)
 {
-   struct frad_local *flp;
+       struct frad_local *flp;
 
-   flp = dev->priv;
+       flp = dev->priv;
 
-   if (dev->start)
-      return(-EBUSY);
+       if (dev->start)
+               return(-EBUSY);
 
-   /* for now, you can't change the MTU! */
-   return(-EACCES);
+       /* for now, you can't change the MTU! */
+       return(-EOPNOTSUPP);
 }
 
 int sdla_set_config(struct device *dev, struct ifmap *map)
 {
-   struct frad_local *flp;
-   int               i;
-   char              byte;
+       struct frad_local *flp;
+       int               i;
+       char              byte;
 
-   flp = dev->priv;
+       flp = dev->priv;
 
-   if (flp->initialized)
-      return(-EINVAL);
+       if (flp->initialized)
+               return(-EINVAL);
 
-   for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
-      if (valid_port[i] == map->base_addr)
-         break;   
+       for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
+               if (valid_port[i] == map->base_addr)
+                       break;   
 
-   if (i == sizeof(valid_port) / sizeof(int))
-      return(-EINVAL);
+       if (i == sizeof(valid_port) / sizeof(int))
+               return(-EINVAL);
 
-   dev->base_addr = map->base_addr;
-   request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
+       dev->base_addr = map->base_addr;
+       request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
 
-   /* test for card types, S502A, S502E, S507, S508                 */
-   /* these tests shut down the card completely, so clear the state */
-   flp->type = SDLA_UNKNOWN;
-   flp->state = 0;
+       /* test for card types, S502A, S502E, S507, S508                 */
+       /* these tests shut down the card completely, so clear the state */
+       flp->type = SDLA_UNKNOWN;
+       flp->state = 0;
    
-   for(i=1;i<SDLA_IO_EXTENTS;i++)
-      if (inb(dev->base_addr + i) != 0xFF)
-        break;
-
-   if (i == SDLA_IO_EXTENTS)
-   {   
-      outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-      if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
-      {
-         outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
-         if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
-         {
-            outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-            flp->type = SDLA_S502E;
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
-         if (inb(dev->base_addr + i) != byte)
-            break;
-
-      if (i == SDLA_IO_EXTENTS)
-      {
-         outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-         if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
-         {
-            outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-            if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
-            {
-               outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-               flp->type = SDLA_S507;
-            }
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-      if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
-      {
-         outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-         if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
-         {
-            outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-            flp->type = SDLA_S508;
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-      if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-      {
-         outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-         if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-         {
-            outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-            if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
-            {
-               outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-               flp->type = SDLA_S502A;
-            }
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
-      return(-ENODEV);
-   }
-
-   switch(dev->base_addr)
-   {
-      case 0x270:
-      case 0x280:
-      case 0x380: 
-      case 0x390:
-         if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-            return(-EINVAL);
-   }
-
-   switch (map->irq)
-   {
-      case 2:
-         if (flp->type != SDLA_S502E)
-            return(-EINVAL);
-         break;
-
-      case 10:
-      case 11:
-      case 12:
-      case 15:
-      case 4:
-         if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-            return(-EINVAL);
-
-      case 3:
-      case 5:
-      case 7:
-         if (flp->type == SDLA_S502A)
-            return(-EINVAL);
-         break;
-
-      default:
-         return(-EINVAL);
-   }
-   dev->irq = map->irq;
-
-   if (request_irq(dev->irq, &sdla_isr, 0, dev->name, NULL)) 
-      return(-EADDRINUSE);
-
-   irq2dev_map[dev->irq] = dev;
-
-   if (flp->type == SDLA_S507)
-   {
-      switch(dev->irq)
-      {
-         case 3:
-            flp->state = SDLA_S507_IRQ3;
-            break;
-         case 4:
-            flp->state = SDLA_S507_IRQ4;
-            break;
-         case 5:
-            flp->state = SDLA_S507_IRQ5;
-            break;
-         case 7:
-            flp->state = SDLA_S507_IRQ7;
-            break;
-         case 10:
-            flp->state = SDLA_S507_IRQ10;
-            break;
-         case 11:
-            flp->state = SDLA_S507_IRQ11;
-            break;
-         case 12:
-            flp->state = SDLA_S507_IRQ12;
-            break;
-         case 15:
-            flp->state = SDLA_S507_IRQ15;
-            break;
-      }
-   }
-
-   for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
-      if (valid_mem[i] == map->mem_start)
-         break;   
-
-   if (i == sizeof(valid_mem) / sizeof(int))
-      return(-EINVAL);
-
-   if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
-      return(-EINVAL);
-
-   if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
-      return(-EINVAL);
-
-   if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
-      return(-EINVAL);
-
-   dev->mem_start = map->mem_start;
-   dev->mem_end = dev->mem_start + 0x2000;
-
-   byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
-   byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-      case SDLA_S502E:
-         switch (map->mem_start >> 16)
-         {
-            case 0x0A:
-               byte |= SDLA_S502_SEG_A;
-               break;
-            case 0x0C:
-               byte |= SDLA_S502_SEG_C;
-               break;
-            case 0x0D:
-               byte |= SDLA_S502_SEG_D;
-               break;
-            case 0x0E:
-               byte |= SDLA_S502_SEG_E;
-               break;
-         }
-         break;
-      case SDLA_S507:
-         switch (map->mem_start >> 16)
-         {
-            case 0x0A:
-               byte |= SDLA_S507_SEG_A;
-               break;
-            case 0x0B:
-               byte |= SDLA_S507_SEG_B;
-               break;
-            case 0x0C:
-               byte |= SDLA_S507_SEG_C;
-               break;
-            case 0x0E:
-               byte |= SDLA_S507_SEG_E;
-               break;
-         }
-         break;
-      case SDLA_S508:
-         switch (map->mem_start >> 16)
-         {
-            case 0x0A:
-               byte |= SDLA_S508_SEG_A;
-               break;
-            case 0x0C:
-               byte |= SDLA_S508_SEG_C;
-               break;
-            case 0x0D:
-               byte |= SDLA_S508_SEG_D;
-               break;
-            case 0x0E:
-               byte |= SDLA_S508_SEG_E;
-               break;
-         }
-         break;
-   }
-
-   /* set the memory bits, and enable access */
-   outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
-   switch(flp->type)
-   {
-      case SDLA_S502E:
-         flp->state = SDLA_S502E_ENABLE;
-         break;
-      case SDLA_S507:
-         flp->state |= SDLA_MEMEN;
-         break;
-      case SDLA_S508:
-         flp->state = SDLA_MEMEN;
-         break;
-   }
-   outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-
-   flp->initialized = 1;
-   return(0);
+       for(i=1;i<SDLA_IO_EXTENTS;i++)
+               if (inb(dev->base_addr + i) != 0xFF)
+                       break;
+
+       if (i == SDLA_IO_EXTENTS)
+       {   
+               outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
+               if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
+               {
+                       outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
+                       if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
+                       {
+                               outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+                               flp->type = SDLA_S502E;
+                       }
+               }
+       }
+
+       if (flp->type == SDLA_UNKNOWN)
+       {
+               for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
+                       if (inb(dev->base_addr + i) != byte)
+                               break;
+
+               if (i == SDLA_IO_EXTENTS)
+               {
+                       outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+                       if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
+                       {
+                               outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
+                               if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
+                               {
+                                       outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+                                       flp->type = SDLA_S507;
+                               }
+                       }
+               }
+       }
+
+       if (flp->type == SDLA_UNKNOWN)
+       {
+               outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+               if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
+               {
+                       outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
+                       if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
+                       {
+                               outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+                               flp->type = SDLA_S508;
+                       }
+               }
+       }
+
+       if (flp->type == SDLA_UNKNOWN)
+       {
+               outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
+               if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
+               {
+                       outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+                       if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
+                       {
+                               outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
+                               if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
+                               {
+                                       outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+                                       flp->type = SDLA_S502A;
+                               }
+                       }
+               }
+       }
+
+       if (flp->type == SDLA_UNKNOWN)
+       {
+               printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
+               return(-ENODEV);
+       }
+
+       switch(dev->base_addr)
+       {
+               case 0x270:
+               case 0x280:
+               case 0x380: 
+               case 0x390:
+                       if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
+                               return(-EINVAL);
+       }
+
+       switch (map->irq)
+       {
+               case 2:
+                       if (flp->type != SDLA_S502E)
+                               return(-EINVAL);
+                       break;
+
+               case 10:
+               case 11:
+               case 12:
+               case 15:
+               case 4:
+                       if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
+                               return(-EINVAL);
+
+               case 3:
+               case 5:
+               case 7:
+                       if (flp->type == SDLA_S502A)
+                               return(-EINVAL);
+                       break;
+
+               default:
+                       return(-EINVAL);
+       }
+       dev->irq = map->irq;
+
+       if (request_irq(dev->irq, &sdla_isr, 0, dev->name, NULL)) 
+               return(-EAGAIN);
+
+       irq2dev_map[dev->irq] = dev;
+
+       if (flp->type == SDLA_S507)
+       {
+               switch(dev->irq)
+               {
+                       case 3:
+                               flp->state = SDLA_S507_IRQ3;
+                               break;
+                       case 4:
+                               flp->state = SDLA_S507_IRQ4;
+                               break;
+                       case 5:
+                               flp->state = SDLA_S507_IRQ5;
+                               break;
+                       case 7:
+                               flp->state = SDLA_S507_IRQ7;
+                               break;
+                       case 10:
+                               flp->state = SDLA_S507_IRQ10;
+                               break;
+                       case 11:
+                               flp->state = SDLA_S507_IRQ11;
+                               break;
+                       case 12:
+                               flp->state = SDLA_S507_IRQ12;
+                               break;
+                       case 15:
+                               flp->state = SDLA_S507_IRQ15;
+                               break;
+               }
+       }
+
+       for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
+               if (valid_mem[i] == map->mem_start)
+                       break;   
+
+       if (i == sizeof(valid_mem) / sizeof(int))
+       /*
+        *      FIXME:
+        *      BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN
+        *      ALL THESE CASES
+        *
+        */
+               return(-EINVAL);
+
+       if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
+               return(-EINVAL);
+
+       if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
+               return(-EINVAL);
+
+       if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
+               return(-EINVAL);
+
+       dev->mem_start = map->mem_start;
+       dev->mem_end = dev->mem_start + 0x2000;
+
+       byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
+       byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
+       switch(flp->type)
+       {
+               case SDLA_S502A:
+               case SDLA_S502E:
+                       switch (map->mem_start >> 16)
+                       {
+                               case 0x0A:
+                                       byte |= SDLA_S502_SEG_A;
+                                       break;
+                               case 0x0C:
+                                       byte |= SDLA_S502_SEG_C;
+                                       break;
+                               case 0x0D:
+                                       byte |= SDLA_S502_SEG_D;
+                                       break;
+                               case 0x0E:
+                                       byte |= SDLA_S502_SEG_E;
+                                       break;
+                       }
+                       break;
+               case SDLA_S507:
+                       switch (map->mem_start >> 16)
+                       {
+                               case 0x0A:
+                                       byte |= SDLA_S507_SEG_A;
+                                       break;
+                               case 0x0B:
+                                       byte |= SDLA_S507_SEG_B;
+                                       break;
+                               case 0x0C:
+                                       byte |= SDLA_S507_SEG_C;
+                                       break;
+                               case 0x0E:
+                                       byte |= SDLA_S507_SEG_E;
+                                       break;
+                       }
+                       break;
+               case SDLA_S508:
+                       switch (map->mem_start >> 16)
+                       {
+                               case 0x0A:
+                                       byte |= SDLA_S508_SEG_A;
+                                       break;
+                               case 0x0C:
+                                       byte |= SDLA_S508_SEG_C;
+                                       break;
+                               case 0x0D:
+                                       byte |= SDLA_S508_SEG_D;
+                                       break;
+                               case 0x0E:
+                                       byte |= SDLA_S508_SEG_E;
+                                       break;
+                       }
+                       break;
+       }
+
+       /* set the memory bits, and enable access */
+       outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
+
+       switch(flp->type)
+       {
+               case SDLA_S502E:
+                       flp->state = SDLA_S502E_ENABLE;
+                       break;
+               case SDLA_S507:
+                       flp->state |= SDLA_MEMEN;
+                       break;
+               case SDLA_S508:
+                       flp->state = SDLA_MEMEN;
+                       break;
+       }
+       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+
+       flp->initialized = 1;
+       return(0);
 }
  
-static struct enet_statistics *sdla_stats(struct device *dev)
+static struct net_device_stats *sdla_stats(struct device *dev)
 {
-   struct frad_local *flp;
+       struct frad_local *flp;
+       flp = dev->priv;
 
-   flp = dev->priv;
-
-   return(&flp->stats);
+       return(&flp->stats);
 }
 
 int sdla_init(struct device *dev)
 {
-   struct frad_local *flp;
-
-   /* allocate the private data structure */
-   flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL);
-   if (!flp)
-      return(-ENOMEM);
-
-   memset(flp, 0, sizeof(struct frad_local));
-   dev->priv = flp;
-
-   dev->flags           = 0;
-   dev->open            = sdla_open;
-   dev->stop            = sdla_close;
-   dev->do_ioctl        = sdla_ioctl;
-   dev->set_config      = sdla_set_config;
-   dev->get_stats       = sdla_stats;
-   dev->hard_start_xmit = sdla_transmit;
-   dev->change_mtu     = sdla_change_mtu;
-
-   dev->type            = 0xFFFF;
-   dev->family          = AF_UNSPEC;
-   dev->pa_alen         = 0;
-   dev->pa_addr         = 0;
-   dev->pa_dstaddr      = 0;
-   dev->pa_brdaddr      = 0;
-   dev->pa_mask         = 0;
-   dev->hard_header_len = 0;
-   dev->addr_len        = 0;
-   dev->mtu             = SDLA_MAX_MTU;
-
-   dev_init_buffers(dev);
+       struct frad_local *flp;
+
+       /* allocate the private data structure */
+       flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL);
+       if (!flp)
+               return(-ENOMEM);
+
+       memset(flp, 0, sizeof(struct frad_local));
+       dev->priv = flp;
+
+       dev->flags              = 0;
+       dev->open               = sdla_open;
+       dev->stop               = sdla_close;
+       dev->do_ioctl           = sdla_ioctl;
+       dev->set_config         = sdla_set_config;
+       dev->get_stats          = sdla_stats;
+       dev->hard_start_xmit    = sdla_transmit;
+       dev->change_mtu         = sdla_change_mtu;
+
+       dev->type               = 0xFFFF;
+       dev->family             = AF_UNSPEC;
+       dev->pa_alen            = 0;
+       dev->pa_addr            = 0;
+       dev->pa_dstaddr         = 0;
+       dev->pa_brdaddr         = 0;
+       dev->pa_mask            = 0;
+       dev->hard_header_len = 0;
+       dev->addr_len           = 0;
+       dev->mtu                = SDLA_MAX_MTU;
+
+       dev_init_buffers(dev);
    
-   flp->activate        = sdla_activate;
-   flp->deactivate      = sdla_deactivate;
-   flp->assoc           = sdla_assoc;
-   flp->deassoc         = sdla_deassoc;
-   flp->dlci_conf       = sdla_dlci_conf;
-
-   init_timer(&flp->timer);
-   flp->timer.expires   = 1;
-   flp->timer.data      = (unsigned long) dev;
-   flp->timer.function  = sdla_poll;
-
-   return(0);
+       flp->activate           = sdla_activate;
+       flp->deactivate         = sdla_deactivate;
+       flp->assoc              = sdla_assoc;
+       flp->deassoc            = sdla_deassoc;
+       flp->dlci_conf          = sdla_dlci_conf;
+
+       init_timer(&flp->timer);
+       flp->timer.expires      = 1;
+       flp->timer.data         = (unsigned long) dev;
+       flp->timer.function     = sdla_poll;
+
+       return(0);
 }
 
 void sdla_setup(void)
 {
-   printk("%s.\n", version);
-   register_frad(devname);
+       printk("%s.\n", version);
+       register_frad(devname);
 }
 
 #ifdef MODULE
@@ -1692,21 +1680,20 @@ static struct device sdla0 = {"sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, sdla_ini
 
 int init_module(void)
 {
-   int result;
-
-   sdla_setup();
-   if ((result = register_netdev(&sdla0)) != 0)
-      return result;
+       int result;
 
-   return 0;
+       sdla_setup();
+       if ((result = register_netdev(&sdla0)) != 0)
+               return result;
+       return 0;
 }
 
 void cleanup_module(void)
 {
-   unregister_netdev(&sdla0);
-   if (sdla0.priv)
-      kfree(sdla0.priv);
-   if (sdla0.irq)
-      free_irq(sdla0.irq, NULL);
+       unregister_netdev(&sdla0);
+       if (sdla0.priv)
+               kfree(sdla0.priv);
+       if (sdla0.irq)
+               free_irq(sdla0.irq, NULL);
 }
 #endif /* MODULE */
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
new file mode 100644 (file)
index 0000000..b7f084f
--- /dev/null
@@ -0,0 +1,1428 @@
+/*****************************************************************************
+* sdla_fr.c    WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 02, 1997 Gene Kozin      Initial version.
+*****************************************************************************/
+
+#if    !defined(__KERNEL__) || !defined(MODULE)
+#error This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/kernel.h>      /* printk(), and other useful stuff */
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/string.h>      /* inline memset(), etc. */
+#include <linux/malloc.h>      /* kmalloc(), kfree() */
+#include <linux/router.h>      /* WAN router definitions */
+#include <linux/wanpipe.h>     /* WANPIPE common user API definitions */
+#include <linux/if_arp.h>      /* ARPHRD_* defines */
+#include <asm/byteorder.h>     /* htons(), etc. */
+#include <asm/io.h>            /* for inb(), outb(), etc. */
+
+#define        _GNUC_
+#include <linux/sdla_fr.h>     /* frame relay firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#define        CMD_OK          0               /* normal firmware return code */
+#define        CMD_TIMEOUT     0xFF            /* firmware command timed out */
+#define        MAX_CMD_RETRY   10              /* max number of firmware retries */
+
+#define        FR_HEADER_LEN   8               /* max encapsulation header size */
+#define        FR_CHANNEL_MTU  1500            /* unfragmented logical channel MTU */
+
+/* Q.922 frame types */
+#define        Q922_UI         0x03            /* Unnumbered Info frame */
+#define        Q922_XID        0xAF            /* ??? */
+
+/****** Data Structures *****************************************************/
+
+/* This is an extention of the 'struct device' we create for each network
+ * interface to keep the rest of channel-specific data.
+ */
+typedef struct fr_channel
+{
+       char name[WAN_IFNAME_SZ+1];     /* interface name, ASCIIZ */
+       unsigned dlci;                  /* logical channel number */
+       unsigned cir;                   /* committed information rate */
+       char state;                     /* channel state */
+       unsigned long state_tick;       /* time of the last state change */
+       sdla_t* card;                   /* -> owner */
+       struct enet_statistics ifstats; /* interface statistics */
+} fr_channel_t;
+
+typedef struct dlci_status
+{
+       unsigned short dlci     PACKED;
+       unsigned char state     PACKED;
+} dlci_status_t;
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+       wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
+
+/* Network device interface */
+static int if_init   (struct device* dev);
+static int if_open   (struct device* dev);
+static int if_close  (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+       unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+       struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* Interrupt handlers */
+static void fr502_isr (sdla_t* card);
+static void fr508_isr (sdla_t* card);
+static void fr502_rx_intr (sdla_t* card);
+static void fr508_rx_intr (sdla_t* card);
+static void tx_intr (sdla_t* card);
+static void spur_intr (sdla_t* card);
+
+/* Background polling routines */
+static void wpf_poll (sdla_t* card);
+
+/* Frame relay firmware interface functions */
+static int fr_read_version (sdla_t* card, char* str);
+static int fr_configure (sdla_t* card, fr_conf_t *conf);
+static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu);
+static int fr_comm_enable (sdla_t* card);
+static int fr_comm_disable (sdla_t* card);
+static int fr_add_dlci (sdla_t* card, int dlci, int num);
+static int fr_activate_dlci (sdla_t* card, int dlci, int num);
+static int fr_issue_isf (sdla_t* card, int isf);
+static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf);
+static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf);
+
+/* Firmware asynchronous event handlers */
+static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox);
+static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox);
+static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox);
+
+/* Miscellaneous functions */
+static int update_chan_state (struct device* dev);
+static void set_chan_state (struct device* dev, int state);
+static struct device* find_channel (sdla_t* card, unsigned dlci);
+static int is_tx_ready (sdla_t* card);
+static unsigned int dec_to_uint (unsigned char* str, int len);
+static unsigned int hex_to_uint (unsigned char* str, int len);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * Frame relay protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:     0       o.k.
+ *             < 0     failure.
+ */
+int wpf_init (sdla_t* card, wandev_conf_t* conf)
+{
+       union
+       {
+               char str[80];
+               fr_conf_t cfg;
+       } u;
+
+       /* Verify configuration ID */
+       if (conf->config_id != WANCONFIG_FR)
+       {
+               printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+                       card->devname, conf->config_id)
+               ;
+               return -EINVAL;
+       }
+
+       /* Initialize protocol-specific fields of adapter data space */
+       switch (card->hw.fwid)
+       {
+       case SFID_FR502:
+               card->mbox  = (void*)(card->hw.dpmbase + FR502_MBOX_OFFS);
+               card->rxmb  = (void*)(card->hw.dpmbase + FR502_RXMB_OFFS);
+               card->flags = (void*)(card->hw.dpmbase + FR502_FLAG_OFFS);
+               card->isr = &fr502_isr;
+               break;
+
+       case SFID_FR508:
+               card->mbox  = (void*)(card->hw.dpmbase + FR508_MBOX_OFFS);
+               card->flags = (void*)(card->hw.dpmbase + FR508_FLAG_OFFS);
+               card->isr = &fr508_isr;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Read firmware version.  Note that when adapter initializes, it
+        * clears the mailbox, so it may appear that the first command was
+        * executed successfully when in fact it was merely erased. To work
+        * around this, we execute the first command twice.
+        */
+       if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
+               return -EIO
+       ;
+       printk(KERN_INFO "%s: running frame relay firmware v%s\n",
+               card->devname, u.str)
+       ;
+
+       /* Adjust configuration */
+       conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN);
+       conf->bps = min(conf->bps, 2048000);
+
+       /* Configure adapter firmware */
+       memset(&u.cfg, 0, sizeof(u.cfg));
+       u.cfg.mtu       = conf->mtu;
+       u.cfg.t391      = 10;
+       u.cfg.t392      = 15;
+       u.cfg.n391      = 6;
+       u.cfg.n392      = 3;
+       u.cfg.n393      = 4;
+       u.cfg.kbps      = conf->bps / 1000;
+       u.cfg.cir_fwd   = max(min(u.cfg.kbps, 512), 1);
+       u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd;
+       u.cfg.options   = 0x0081;       /* direct Rx, no CIR check */
+       switch (conf->u.fr.signalling)
+       {
+       case WANOPT_FR_Q933:    u.cfg.options |= 0x0200; break;
+       case WANOPT_FR_LMI:     u.cfg.options |= 0x0400; break;
+       }
+       if (conf->station == WANOPT_CPE)
+       {
+               u.cfg.options |= 0x8000;        /* auto config DLCI */
+       }
+       else
+       {
+               u.cfg.station = 1;      /* switch emulation mode */
+               card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16;
+               card->u.f.dlci_num  = max(min(conf->u.fr.dlci_num, 1), 100);
+       }
+       if (conf->clocking == WANOPT_INTERNAL)
+               u.cfg.port |= 0x0001
+       ;
+       if (conf->interface == WANOPT_RS232)
+               u.cfg.port |= 0x0002
+       ;
+       if (conf->u.fr.t391)
+               u.cfg.t391 = min(conf->u.fr.t391, 30)
+       ;
+       if (conf->u.fr.t392)
+               u.cfg.t392 = min(conf->u.fr.t392, 30)
+       ;
+       if (conf->u.fr.n391)
+               u.cfg.n391 = min(conf->u.fr.n391, 255)
+       ;
+       if (conf->u.fr.n392)
+               u.cfg.n392 = min(conf->u.fr.n392, 10)
+       ;
+       if (conf->u.fr.n393)
+               u.cfg.n393 = min(conf->u.fr.n393, 10)
+       ;
+
+       if (fr_configure(card, &u.cfg))
+               return -EIO
+       ;
+
+       if (card->hw.fwid == SFID_FR508)
+       {
+               fr_buf_info_t* buf_info =
+                       (void*)(card->hw.dpmbase + FR508_RXBC_OFFS)
+               ;
+
+               card->rxmb =
+                       (void*)(buf_info->rse_next -
+                       FR_MB_VECTOR + card->hw.dpmbase)
+               ;
+               card->u.f.rxmb_base =
+                       (void*)(buf_info->rse_base -
+                       FR_MB_VECTOR + card->hw.dpmbase)
+               ;
+               card->u.f.rxmb_last =
+                       (void*)(buf_info->rse_base +
+                       (buf_info->rse_num - 1) * sizeof(fr_buf_ctl_t) -
+                       FR_MB_VECTOR + card->hw.dpmbase)
+               ;
+               card->u.f.rx_base = buf_info->buf_base;
+               card->u.f.rx_top  = buf_info->buf_top;
+       }
+       card->wandev.mtu        = conf->mtu;
+       card->wandev.bps        = conf->bps;
+       card->wandev.interface  = conf->interface;
+       card->wandev.clocking   = conf->clocking;
+       card->wandev.station    = conf->station;
+       card->poll              = &wpf_poll;
+       card->wandev.update     = &update;
+       card->wandev.new_if     = &new_if;
+       card->wandev.del_if     = &del_if;
+       card->wandev.state      = WAN_DISCONNECTED;
+       return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+/*
+       sdla_t* card = wandev->private;
+*/
+       return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:     0       o.k.
+ *             < 0     failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
+{
+       sdla_t* card = wandev->private;
+       fr_channel_t* chan;
+       int err = 0;
+
+       if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+       {
+               printk(KERN_INFO "%s: invalid interface name!\n",
+                       card->devname)
+               ;
+               return -EINVAL;
+       }
+
+       /* allocate and initialize private data */
+       chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
+       if (chan == NULL)
+               return -ENOMEM
+       ;
+       memset(chan, 0, sizeof(fr_channel_t));
+       strcpy(chan->name, conf->name);
+       chan->card = card;
+
+       /* verify media address */
+       if (is_digit(conf->addr[0]))
+       {
+               int dlci = dec_to_uint(conf->addr, 0);
+
+               if (dlci && (dlci <= 4095))
+               {
+                       chan->dlci = dlci;
+               }
+               else
+               {
+                       printk(KERN_ERR
+                               "%s: invalid DLCI %u on interface %s!\n",
+                               wandev->name, dlci, chan->name)
+                       ;
+                       err = -EINVAL;
+               }
+       }
+       else
+       {
+               printk(KERN_ERR
+                       "%s: invalid media address on interface %s!\n",
+                       wandev->name, chan->name)
+               ;
+               err = -EINVAL;
+       }
+       if (err)
+       {
+               kfree(chan);
+               return err;
+       }
+
+       /* prepare network device data space for registration */
+       dev->name = chan->name;
+       dev->init = &if_init;
+       dev->priv = chan;
+       return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+       if (dev->priv)
+       {
+               kfree(dev->priv);
+               dev->priv = NULL;
+       }
+       return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct device* dev)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       wan_device_t* wandev = &card->wandev;
+       int i;
+
+       /* Initialize device driver entry points */
+       dev->open               = &if_open;
+       dev->stop               = &if_close;
+       dev->hard_header        = &if_header;
+       dev->rebuild_header     = &if_rebuild_hdr;
+       dev->hard_start_xmit    = &if_send;
+       dev->get_stats          = &if_stats;
+
+       /* Initialize media-specific parameters */
+       dev->family             = AF_INET;      /* address family */
+       dev->type               = ARPHRD_DLCI;  /* ARP h/w type */
+       dev->mtu                = FR_CHANNEL_MTU;
+       dev->hard_header_len    = FR_HEADER_LEN;/* media header length */
+       dev->addr_len           = 2;            /* hardware address length */
+       *(unsigned short*)dev->dev_addr = htons(chan->dlci);
+
+       /* Initialize hardware parameters (just for reference) */
+       dev->irq        = wandev->irq;
+       dev->dma        = wandev->dma;
+       dev->base_addr  = wandev->ioport;
+       dev->mem_start  = wandev->maddr;
+       dev->mem_end    = wandev->maddr + wandev->msize - 1;
+
+       /* Initialize socket buffers */
+       for (i = 0; i < DEV_NUMBUFFS; ++i)
+               skb_queue_head_init(&dev->buffs[i])
+       ;
+       set_chan_state(dev, WAN_DISCONNECTED);
+       return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o if this is the first open, then enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct device* dev)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       int err = 0;
+
+       if (dev->start)
+               return -EBUSY           /* only one open is allowed */
+       ;
+       if (set_bit(0, (void*)&card->wandev.critical))
+               return -EAGAIN;
+       ;
+       if (!card->open_cnt)
+       {
+               if ((fr_comm_enable(card)) ||
+                   (fr_set_intr_mode(card, 0x03, card->wandev.mtu)))
+               {
+                       err = -EIO;
+                       goto done;
+               }
+               if (card->wandev.station == WANOPT_CPE)
+               {
+                       /* CPE: issue full status enquiry */
+                       fr_issue_isf(card, FR_ISF_FSE);
+               }
+               else    /* Switch: activate DLCI(s) */
+               {
+                       fr_add_dlci(card,
+                               card->u.f.node_dlci, card->u.f.dlci_num)
+                       ;
+                       fr_activate_dlci(card,
+                               card->u.f.node_dlci, card->u.f.dlci_num)
+                       ;
+               }
+               wanpipe_set_state(card, WAN_CONNECTED);
+       }
+       dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
+       dev->interrupt = 0;
+       dev->tbusy = 0;
+       dev->start = 1;
+       wanpipe_open(card);
+       update_chan_state(dev);
+
+done:
+       card->wandev.critical = 0;
+       return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last open, then disable communications and interrupts.
+ * o reset flags.
+ */
+static int if_close (struct device* dev)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+
+       if (set_bit(0, (void*)&card->wandev.critical))
+               return -EAGAIN;
+       ;
+       dev->start = 0;
+       wanpipe_close(card);
+       if (!card->open_cnt)
+       {
+               wanpipe_set_state(card, WAN_DISCONNECTED);
+               fr_set_intr_mode(card, 0, 0);
+               fr_comm_disable(card);
+       }
+       card->wandev.critical = 0;
+       return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:     media header length.
+ */
+static int if_header (struct sk_buff* skb, struct device* dev,
+       unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+       int hdr_len = 0;
+
+       skb->protocol = type;
+       hdr_len = wan_encapsulate(skb, dev);
+       if (hdr_len < 0)
+       {
+               hdr_len = 0;
+               skb->protocol = 0;
+       }
+       skb_push(skb, 1);
+       skb->data[0] = Q922_UI;
+       ++hdr_len;
+       return hdr_len;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:     1       physical address resolved.
+ *             0       physical address not resolved
+ */
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+                          struct sk_buff* skb)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+
+       printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+               card->devname, dev->name)
+       ;
+       return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:     0       complete (socket buffer must be freed)
+ *             non-0   packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, struct device* dev)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       int retry = 0;
+
+       if (skb == NULL)
+       {
+               /* If we get here, some higher layer thinks we've missed an
+                * tx-done interrupt.
+                */
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: interface %s got kicked!\n",
+                       card->devname, dev->name)
+               ;
+#endif
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (set_bit(0, (void*)&card->wandev.critical))
+       {
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: if_send() hit critical section!\n",
+                       card->devname)
+               ;
+#endif
+               return 1;
+       }
+
+       if (set_bit(0, (void*)&dev->tbusy))
+       {
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+                       card->devname, dev->name)
+               ;
+#endif
+               ++chan->ifstats.collisions;
+               retry = 1;
+       }
+       else if ((card->wandev.state != WAN_CONNECTED) ||
+           (chan->state != WAN_CONNECTED))
+               ++chan->ifstats.tx_dropped
+       ;
+       else if (!is_tx_ready(card))
+               retry = 1
+       ;
+       else
+       {
+               int err = (card->hw.fwid == SFID_FR508) ?
+                       fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
+                       fr502_send(card, chan->dlci, 0, skb->len, skb->data)
+               ;
+               if (err) ++chan->ifstats.tx_errors;
+               else ++chan->ifstats.tx_packets;
+       }
+       if (!retry)
+       {
+               dev_kfree_skb(skb, FREE_WRITE);
+               dev->tbusy = 0;
+       }
+       card->wandev.critical = 0;
+       return retry;
+}
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+static struct enet_statistics* if_stats (struct device* dev)
+{
+       fr_channel_t* chan = dev->priv;
+
+       return &chan->ifstats;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * S502 frame relay interrupt service routine.
+ */
+static void fr502_isr (sdla_t* card)
+{
+       fr502_flags_t* flags = card->flags;
+
+       switch (flags->iflag)
+       {
+       case 0x01:      /* receive interrupt */
+               fr502_rx_intr(card);
+               break;
+
+       case 0x02:      /* transmit interrupt */
+               flags->imask &= ~0x02;
+               tx_intr(card);
+               break;
+
+       default:
+               spur_intr(card);
+       }
+       flags->iflag = 0;
+}
+
+/*============================================================================
+ * S508 frame relay interrupt service routine.
+ */
+static void fr508_isr (sdla_t* card)
+{
+       fr508_flags_t* flags = card->flags;
+       fr_buf_ctl_t* bctl;
+
+       switch (flags->iflag)
+       {
+       case 0x01:      /* receive interrupt */
+               fr508_rx_intr(card);
+               break;
+
+       case 0x02:      /* transmit interrupt */
+               bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
+                       card->hw.dpmbase)
+               ;
+               bctl->flag = 0x90;      /* disable further Tx interrupts */
+               tx_intr(card);
+               break;
+
+       default:
+               spur_intr(card);
+       }
+       flags->iflag = 0;
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void fr502_rx_intr (sdla_t* card)
+{
+       fr_mbox_t* mbox = card->rxmb;
+       struct sk_buff* skb;
+       struct device* dev;
+       fr_channel_t* chan;
+       unsigned dlci, len;
+       void* buf;
+
+       sdla_mapmem(&card->hw, FR502_RX_VECTOR);
+       dlci = mbox->cmd.dlci;
+       len  = mbox->cmd.length;
+
+       /* Find network interface for this packet */
+       dev = find_channel(card, dlci);
+       if (dev == NULL)
+       {
+               /* Invalid channel, discard packet */
+               printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
+                       card->devname, dlci)
+               ;
+               goto rx_done;
+       }
+       chan = dev->priv;
+       if (!dev->start)
+       {
+               ++chan->ifstats.rx_dropped;
+               goto rx_done;
+       }
+
+       /* Allocate socket buffer */
+       skb = dev_alloc_skb(len);
+       if (skb == NULL)
+       {
+               printk(KERN_INFO "%s: no socket buffers available!\n",
+                       card->devname)
+               ;
+               ++chan->ifstats.rx_dropped;
+               goto rx_done;
+       }
+
+       /* Copy data to the socket buffer */
+       buf = skb_put(skb, len);
+       memcpy(buf, mbox->data, len);
+       sdla_mapmem(&card->hw, FR_MB_VECTOR);
+
+       /* Decapsulate packet and pass it up the protocol stack */
+       skb->dev = dev;
+       buf = skb_pull(skb, 1); /* remove hardware header */
+       if (!wan_type_trans(skb, dev))
+       {
+               /* can't decapsulate packet */
+               dev_kfree_skb(skb, FREE_READ);
+               ++chan->ifstats.rx_errors;
+       }
+       else
+       {
+               netif_rx(skb);
+               ++chan->ifstats.rx_packets;
+       }
+
+rx_done:
+       sdla_mapmem(&card->hw, FR_MB_VECTOR);
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void fr508_rx_intr (sdla_t* card)
+{
+       fr_buf_ctl_t* frbuf = card->rxmb;
+       struct sk_buff* skb;
+       struct device* dev;
+       fr_channel_t* chan;
+       unsigned dlci, len, offs;
+       void* buf;
+
+       if (frbuf->flag != 0x01)
+       {
+               printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
+                       card->devname, (unsigned)frbuf)
+               ;
+               return;
+       }
+       len  = frbuf->length;
+       dlci = frbuf->dlci;
+       offs = frbuf->offset;
+
+       /* Find network interface for this packet */
+       dev = find_channel(card, dlci);
+       if (dev == NULL)
+       {
+               /* Invalid channel, discard packet */
+               printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
+                       card->devname, dlci)
+               ;
+               goto rx_done;
+       }
+       chan = dev->priv;
+       if (!dev->start)
+       {
+               ++chan->ifstats.rx_dropped;
+               goto rx_done;
+       }
+
+       /* Allocate socket buffer */
+       skb = dev_alloc_skb(len);
+       if (skb == NULL)
+       {
+               printk(KERN_INFO "%s: no socket buffers available!\n",
+                       card->devname)
+               ;
+               ++chan->ifstats.rx_dropped;
+               goto rx_done;
+       }
+
+       /* Copy data to the socket buffer */
+       if ((offs + len) > card->u.f.rx_top)
+       {
+               unsigned tmp = card->u.f.rx_top - offs;
+
+               buf = skb_put(skb, tmp);
+               sdla_peek(&card->hw, offs, buf, tmp);
+               offs = card->u.f.rx_base;
+               len -= tmp;
+       }
+       buf = skb_put(skb, len);
+       sdla_peek(&card->hw, offs, buf, len);
+
+       /* Decapsulate packet and pass it up the protocol stack */
+       skb->dev = dev;
+       buf = skb_pull(skb, 1); /* remove hardware header */
+       if (!wan_type_trans(skb, dev))
+       {
+               /* can't decapsulate packet */
+               dev_kfree_skb(skb, FREE_READ);
+               ++chan->ifstats.rx_errors;
+       }
+       else
+       {
+               netif_rx(skb);
+               ++chan->ifstats.rx_packets;
+       }
+
+rx_done:
+       /* Release buffer element and calculate a pointer to the next one */
+       frbuf->flag = 0;
+       card->rxmb = ++frbuf;
+       if ((void*)frbuf > card->u.f.rxmb_last)
+               card->rxmb = card->u.f.rxmb_base
+       ;
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void tx_intr (sdla_t* card)
+{
+       printk(KERN_INFO "%s: transmit interrupt!\n", card->devname);
+}
+
+/*============================================================================
+ * Spurious interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void spur_intr (sdla_t* card)
+{
+       printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * time-dependent housekeeping work.
+ *
+ * o fetch asynchronous network events.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+static void wpf_poll (sdla_t* card)
+{
+       fr502_flags_t* flags = card->flags;
+
+       if (flags->event)
+       {
+               fr_mbox_t* mbox = card->mbox;
+               int err;
+
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->cmd.command = FR_READ_STATUS;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+               if (err) fr_event(card, err, mbox);
+       }
+}
+
+/****** Frame Relay Firmware-Specific Functions *****************************/
+
+/*============================================================================
+ * Read firmware code version.
+ * o fill string str with firmware version info. 
+ */
+static int fr_read_version (sdla_t* card, char* str)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->cmd.command = FR_READ_CODE_VERSION;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       if (!err && str)
+       {
+               int len = mbox->cmd.length;
+
+               memcpy(str, mbox->data, len);
+               str[len] = '\0';
+       }
+       return err;
+}
+
+/*============================================================================
+ * Set global configuration.
+ */
+static int fr_configure (sdla_t* card, fr_conf_t *conf)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int dlci = card->u.f.node_dlci;
+       int dlci_num = card->u.f.dlci_num;
+       int err, i;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               memcpy(mbox->data, conf, sizeof(fr_conf_t));
+               if (dlci_num) for (i = 0; i < dlci_num; ++i)
+                       ((fr_conf_t*)mbox->data)->dlci[i] = dlci + i
+               ;
+               mbox->cmd.command = FR_SET_CONFIG;
+               mbox->cmd.length =
+                       sizeof(fr_conf_t) + dlci_num * sizeof(short)
+               ;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               if (card->hw.fwid == SFID_FR502)
+               {
+                       fr502_intr_ctl_t* ictl = (void*)mbox->data;
+
+                       memset(ictl, 0, sizeof(fr502_intr_ctl_t));
+                       ictl->mode   = mode;
+                       ictl->tx_len = mtu;
+                       mbox->cmd.length = sizeof(fr502_intr_ctl_t);
+               }
+               else
+               {
+                       fr508_intr_ctl_t* ictl = (void*)mbox->data;
+
+                       memset(ictl, 0, sizeof(fr508_intr_ctl_t));
+                       ictl->mode   = mode;
+                       ictl->tx_len = mtu;
+                       ictl->irq    = card->hw.irq;
+                       mbox->cmd.length = sizeof(fr508_intr_ctl_t);
+               }
+               mbox->cmd.command = FR_SET_INTR_MODE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Enable communications.
+ */
+static int fr_comm_enable (sdla_t* card)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->cmd.command = FR_COMM_ENABLE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Disable communications. 
+ */
+static int fr_comm_disable (sdla_t* card)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->cmd.command = FR_COMM_DISABLE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Add DLCI(s) (Access Node only!). 
+ */
+static int fr_add_dlci (sdla_t* card, int dlci, int num)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err, i;
+
+       do
+       {
+               unsigned short* dlci_list = (void*)mbox->data;
+
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               for (i = 0; i < num; ++i)
+                       dlci_list[i] = dlci + i
+               ;
+               mbox->cmd.length  = num * sizeof(short);
+               mbox->cmd.command = FR_ADD_DLCI;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Activate DLCI(s) (Access Node only!). 
+ */
+static int fr_activate_dlci (sdla_t* card, int dlci, int num)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err, i;
+
+       do
+       {
+               unsigned short* dlci_list = (void*)mbox->data;
+
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               for (i = 0; i < num; ++i)
+                       dlci_list[i] = dlci + i
+               ;
+               mbox->cmd.length  = num * sizeof(short);
+               mbox->cmd.command = FR_ACTIVATE_DLCI;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Issue in-channel signalling frame. 
+ */
+static int fr_issue_isf (sdla_t* card, int isf)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->data[0] = isf;
+               mbox->cmd.length  = 1;
+               mbox->cmd.command = FR_ISSUE_IS_FRAME;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Send a frame (S502 version). 
+ */
+static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               memcpy(mbox->data, buf, len);
+               mbox->cmd.dlci    = dlci;
+               mbox->cmd.attr    = attr;
+               mbox->cmd.length  = len;
+               mbox->cmd.command = FR_WRITE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+       return err;
+}
+
+/*============================================================================
+ * Send a frame (S508 version). 
+ */
+static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf)
+{
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->cmd.dlci    = dlci;
+               mbox->cmd.attr    = attr;
+               mbox->cmd.length  = len;
+               mbox->cmd.command = FR_WRITE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+
+       if (!err)
+       {
+               fr_buf_ctl_t* frbuf = (void*)(*(unsigned long*)mbox->data -
+                       FR_MB_VECTOR + card->hw.dpmbase)
+               ;
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+               sdla_poke(&card->hw, frbuf->offset, buf, len);
+               frbuf->flag = 0x01;
+               restore_flags(flags);
+       }
+       return err;
+}
+
+/****** Firmware Asynchronous Event Handlers ********************************/
+
+/*============================================================================
+ * Main asyncronous event/error handler.
+ *     This routine is called whenever firmware command returns non-zero
+ *     return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
+{
+       switch (event)
+       {
+       case FRRES_MODEM_FAILURE:
+               return fr_modem_failure(card, mbox);
+
+       case FRRES_CHANNEL_DOWN:
+               wanpipe_set_state(card, WAN_DISCONNECTED);
+               return 1;
+
+       case FRRES_CHANNEL_UP:
+               wanpipe_set_state(card, WAN_CONNECTED);
+               return 1;
+
+       case FRRES_DLCI_CHANGE:
+               return fr_dlci_change(card, mbox);
+
+       case FRRES_DLCI_MISMATCH:
+               printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname);
+               return 1;
+
+       case CMD_TIMEOUT:
+               printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+                       card->devname, mbox->cmd.command)
+               ;
+               break;
+
+       default:
+               printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+                       card->devname, mbox->cmd.command, event)
+               ;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Handle modem error.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox)
+{
+       printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n",
+               card->devname, mbox->data[0])
+       ;
+       switch (mbox->cmd.command)
+       {
+       case FR_WRITE:
+       case FR_READ:
+               return 0;
+       }
+       return 1;
+}
+
+/*============================================================================
+ * Handle DLCI status change.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
+{
+       dlci_status_t* status = (void*)mbox->data;
+       int cnt = mbox->cmd.length / sizeof(dlci_status_t);
+
+       for (; cnt; --cnt, ++status)
+       {
+               unsigned short dlci = status->dlci;
+               struct device* dev = find_channel(card, dlci);
+
+               if (status->state & 0x01)
+               {
+                       printk(KERN_INFO
+                               "%s: DLCI %u has been deleted!\n",
+                               card->devname, dlci)
+                       ;
+                       if (dev && dev->start)
+                               set_chan_state(dev, WAN_DISCONNECTED)
+                       ;
+               }
+               else if (status->state & 0x02)
+               {
+                       printk(KERN_INFO
+                               "%s: DLCI %u becomes active!\n",
+                               card->devname, dlci)
+                       ;
+                       if (dev && dev->start)
+                               set_chan_state(dev, WAN_CONNECTED)
+                       ;
+               }
+       }
+       return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Update channel state. 
+ */
+static int update_chan_state (struct device* dev)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       fr_mbox_t* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+               mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       }
+       while (err && retry-- && fr_event(card, err, mbox));
+
+       if (!err)
+       {
+               unsigned short* list = (void*)mbox->data;
+               int cnt = mbox->cmd.length / sizeof(short);
+
+               for (; cnt; --cnt, ++list)
+               {
+                       if (*list == chan->dlci)
+                       {
+                               set_chan_state(dev, WAN_CONNECTED);
+                               break;
+                       }
+               }
+       }
+       return err;
+}
+
+/*============================================================================
+ * Set channel state.
+ */
+static void set_chan_state (struct device* dev, int state)
+{
+       fr_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (chan->state != state)
+       {
+               switch (state)
+               {
+               case WAN_CONNECTED:
+                       printk (KERN_INFO "%s: interface %s connected!\n",
+                               card->devname, dev->name)
+                       ;
+                       break;
+
+               case WAN_CONNECTING:
+                       printk (KERN_INFO "%s: interface %s connecting...\n",
+                               card->devname, dev->name)
+                       ;
+                       break;
+
+               case WAN_DISCONNECTED:
+                       printk (KERN_INFO "%s: interface %s disconnected!\n",
+                               card->devname, dev->name)
+                       ;
+                       break;
+               }
+               chan->state = state;
+       }
+       chan->state_tick = jiffies;
+       restore_flags(flags);
+}
+
+/*============================================================================
+ * Find network device by its channel number.
+ */
+static struct device* find_channel (sdla_t* card, unsigned dlci)
+{
+       struct device* dev;
+
+       for (dev = card->wandev.dev; dev; dev = dev->slave)
+               if (((fr_channel_t*)dev->priv)->dlci == dlci) break
+       ;
+       return dev;
+}
+
+/*============================================================================
+ * Check to see if a frame can be sent. If no transmit buffers available,
+ * enable transmit interrupts.
+ *
+ * Return:     1 - Tx buffer(s) available
+ *             0 - no buffers available
+ */
+static int is_tx_ready (sdla_t* card)
+{
+       if (card->hw.fwid == SFID_FR508)
+       {
+               fr508_flags_t* flags = card->flags;
+               unsigned char sb = inb(card->hw.port);
+
+               if (sb & 0x02) return 1;
+               flags->imask |= 0x02;
+       }
+       else
+       {
+               fr502_flags_t* flags = card->flags;
+
+               if (flags->tx_ready) return 1;
+               flags->imask |= 0x02;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted.
+ */
+static unsigned int dec_to_uint (unsigned char* str, int len)
+{
+       unsigned val;
+
+       if (!len) len = strlen(str);
+       for (val = 0; len && is_digit(*str); ++str, --len)
+               val = (val * 10) + (*str - (unsigned)'0')
+       ;
+       return val;
+}
+
+/*============================================================================
+ * Convert hex string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are conferted.
+ */
+static unsigned int hex_to_uint (unsigned char* str, int len)
+{
+       unsigned val, ch;
+
+       if (!len) len = strlen(str);
+       for (val = 0; len; ++str, --len)
+       {
+               ch = *str;
+               if (is_digit(ch))
+                       val = (val << 4) + (ch - (unsigned)'0')
+               ;
+               else if (is_hex_digit(ch))
+                       val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10)
+               ;
+               else break;
+       }
+       return val;
+}
+
+/****** End *****************************************************************/
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
new file mode 100644 (file)
index 0000000..2afde8a
--- /dev/null
@@ -0,0 +1,1025 @@
+/*****************************************************************************
+* sdla_ppp.c   WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 06, 1997 Gene Kozin      Initial version.
+*****************************************************************************/
+
+#if    !defined(__KERNEL__) || !defined(MODULE)
+#error This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/kernel.h>      /* printk(), and other useful stuff */
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/string.h>      /* inline memset(), etc. */
+#include <linux/malloc.h>      /* kmalloc(), kfree() */
+#include <linux/router.h>      /* WAN router definitions */
+#include <linux/wanpipe.h>     /* WANPIPE common user API definitions */
+#include <linux/if_arp.h>      /* ARPHRD_* defines */
+#include <asm/byteorder.h>     /* htons(), etc. */
+
+#define        _GNUC_
+#include <linux/sdla_ppp.h>            /* PPP firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef _DEBUG_
+#define        STATIC
+#else
+#define        STATIC          static
+#endif
+
+#define        CMD_OK          0               /* normal firmware return code */
+#define        CMD_TIMEOUT     0xFF            /* firmware command timed out */
+
+#define        PPP_DFLT_MTU    1500            /* default MTU */
+#define        PPP_MAX_MTU     4000            /* maximum MTU */
+#define PPP_HDR_LEN    1
+
+#define        CONNECT_TIMEOUT (90*HZ)         /* link connection timeout */
+#define        HOLD_DOWN_TIME  (30*HZ)         /* link hold down time */
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+       wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
+
+/* Network device interface */
+static int if_init   (struct device* dev);
+static int if_open   (struct device* dev);
+static int if_close  (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+       unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+       struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* PPP firmware interface functions */
+static int ppp_read_version (sdla_t* card, char* str);
+static int ppp_configure (sdla_t* card, void* data);
+static int ppp_set_intr_mode (sdla_t* card, unsigned mode);
+static int ppp_comm_enable (sdla_t* card);
+static int ppp_comm_disable (sdla_t* card);
+static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto);
+static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb);
+
+/* Interrupt handlers */
+STATIC void wpp_isr (sdla_t* card);
+static void rx_intr (sdla_t* card);
+static void tx_intr (sdla_t* card);
+
+/* Background polling routines */
+static void wpp_poll (sdla_t* card);
+static void poll_active (sdla_t* card);
+static void poll_connecting (sdla_t* card);
+static void poll_disconnected (sdla_t* card);
+
+/* Miscellaneous functions */
+static int config502 (sdla_t* card);
+static int config508 (sdla_t* card);
+static void show_disc_cause (sdla_t* card, unsigned cause);
+static unsigned char bps_to_speed_code (unsigned long bps);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * PPP protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:     0       o.k.
+ *             < 0     failure.
+ */
+int wpp_init (sdla_t* card, wandev_conf_t* conf)
+{
+       union
+       {
+               char str[80];
+       } u;
+
+       /* Verify configuration ID */
+       if (conf->config_id != WANCONFIG_PPP)
+       {
+               printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+                       card->devname, conf->config_id)
+               ;
+               return -EINVAL;
+       }
+
+       /* Initialize protocol-specific fields */
+       switch (card->hw.fwid)
+       {
+       case SFID_PPP502:
+               card->mbox  = (void*)(card->hw.dpmbase + PPP502_MB_OFFS);
+               card->flags = (void*)(card->hw.dpmbase + PPP502_FLG_OFFS);
+               break;
+
+       case SFID_PPP508:
+               card->mbox  = (void*)(card->hw.dpmbase + PPP508_MB_OFFS);
+               card->flags = (void*)(card->hw.dpmbase + PPP508_FLG_OFFS);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Read firmware version.  Note that when adapter initializes, it
+        * clears the mailbox, so it may appear that the first command was
+        * executed successfully when in fact it was merely erased. To work
+        * around this, we execute the first command twice.
+        */
+       if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
+               return -EIO
+       ;
+       printk(KERN_INFO "%s: running PPP firmware v%s\n",
+               card->devname, u.str)
+       ;
+
+       /* Adjust configuration and set defaults */
+       card->wandev.mtu = (conf->mtu) ?
+               min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU
+       ;
+       card->wandev.bps        = conf->bps;
+       card->wandev.interface  = conf->interface;
+       card->wandev.clocking   = conf->clocking;
+       card->wandev.station    = conf->station;
+       card->isr               = &wpp_isr;
+       card->poll              = &wpp_poll;
+       card->wandev.update     = &update;
+       card->wandev.new_if     = &new_if;
+       card->wandev.del_if     = &del_if;
+       card->wandev.state      = WAN_DISCONNECTED;
+       return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+/*
+       sdla_t* card = wandev->private;
+*/
+       return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:     0       o.k.
+ *             < 0     failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
+{
+       sdla_t* card = wandev->private;
+
+       if (wandev->ndev)
+               return -EEXIST
+       ;
+       if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+       {
+               printk(KERN_INFO "%s: invalid interface name!\n",
+                       card->devname)
+               ;
+               return -EINVAL;
+       }
+
+       /* initialize data */
+       strcpy(card->u.p.if_name, conf->name);
+
+       /* prepare network device data space for registration */
+       dev->name = card->u.p.if_name;
+       dev->init = &if_init;
+       dev->priv = card;
+       return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+       return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct device* dev)
+{
+       sdla_t* card = dev->priv;
+       wan_device_t* wandev = &card->wandev;
+       int i;
+
+       /* Initialize device driver entry points */
+       dev->open               = &if_open;
+       dev->stop               = &if_close;
+       dev->hard_header        = &if_header;
+       dev->rebuild_header     = &if_rebuild_hdr;
+       dev->hard_start_xmit    = &if_send;
+       dev->get_stats          = &if_stats;
+
+       /* Initialize media-specific parameters */
+       dev->family             = AF_INET;      /* address family */
+       dev->type               = ARPHRD_PPP;   /* ARP h/w type */
+       dev->mtu                = wandev->mtu;
+       dev->hard_header_len    = PPP_HDR_LEN;  /* media header length */
+
+       /* Initialize hardware parameters (just for reference) */
+       dev->irq                = wandev->irq;
+       dev->dma                = wandev->dma;
+       dev->base_addr          = wandev->ioport;
+       dev->mem_start          = wandev->maddr;
+       dev->mem_end            = wandev->maddr + wandev->msize - 1;
+
+       /* Initialize socket buffers */
+       for (i = 0; i < DEV_NUMBUFFS; ++i)
+               skb_queue_head_init(&dev->buffs[i])
+       ;
+       return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct device* dev)
+{
+       sdla_t* card = dev->priv;
+       int err = 0;
+
+       if (dev->start)
+               return -EBUSY           /* only one open is allowed */
+       ;
+       if (set_bit(0, (void*)&card->wandev.critical))
+               return -EAGAIN;
+       ;
+       if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card))
+       {
+               err = -EIO;
+               goto split;
+       }
+
+       /* Initialize Rx/Tx buffer control fields */
+       if (card->hw.fwid == SFID_PPP502)
+       {
+               ppp502_buf_info_t* info =
+                       (void*)(card->hw.dpmbase + PPP502_BUF_OFFS)
+               ;
+
+               card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
+                       info->txb_offs)
+               ;
+               card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
+                       (info->txb_num - 1)
+               ;
+               card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
+                       info->rxb_offs)
+               ;
+               card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
+                       (info->rxb_num - 1)
+               ;
+       }
+       else
+       {
+               ppp508_buf_info_t* info =
+                       (void*)(card->hw.dpmbase + PPP508_BUF_OFFS)
+               ;
+
+               card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
+                       (info->txb_ptr - PPP508_MB_VECT))
+               ;
+               card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
+                       (info->txb_num - 1)
+               ;
+               card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
+                       (info->rxb_ptr - PPP508_MB_VECT))
+               ;
+               card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
+                       (info->rxb_num - 1)
+               ;
+               card->u.p.rx_base = info->rxb_base;
+               card->u.p.rx_top  = info->rxb_end;
+       }
+       card->u.p.txbuf = card->u.p.txbuf_base;
+       card->rxmb = card->u.p.rxbuf_base;
+
+       if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card))
+       {
+               err = -EIO;
+               goto split;
+       }
+       wanpipe_set_state(card, WAN_CONNECTING);
+       wanpipe_open(card);
+       dev->mtu = min(dev->mtu, card->wandev.mtu);
+       dev->interrupt = 0;
+       dev->tbusy = 0;
+       dev->start = 1;
+
+split:
+       card->wandev.critical = 0;
+       return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last open, then disable communications and interrupts.
+ * o reset flags.
+ */
+static int if_close (struct device* dev)
+{
+       sdla_t* card = dev->priv;
+
+       if (set_bit(0, (void*)&card->wandev.critical))
+               return -EAGAIN;
+       ;
+       dev->start = 0;
+       wanpipe_close(card);
+       wanpipe_set_state(card, WAN_DISCONNECTED);
+       ppp_set_intr_mode(card, 0);
+       ppp_comm_disable(card);
+       card->wandev.critical = 0;
+       return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If packet type is not
+ * supported, set skb->protocol to 0 and discard packet later.
+ *
+ * Return:     media header length.
+ */
+static int if_header (struct sk_buff* skb, struct device* dev,
+       unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+       switch (type)
+       {
+       case ETH_P_IP:
+       case ETH_P_IPX:
+               skb->protocol = type;
+               break;
+
+       default:
+               skb->protocol = 0;
+       }
+       return PPP_HDR_LEN;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:     1       physical address resolved.
+ *             0       physical address not resolved
+ */
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+                          struct sk_buff* skb)
+{
+       sdla_t* card = dev->priv;
+
+       printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+               card->devname, dev->name)
+       ;
+       return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o execute adapter send command.
+ * o free socket buffer
+ *
+ * Return:     0       complete (socket buffer must be freed)
+ *             non-0   packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, struct device* dev)
+{
+       sdla_t* card = dev->priv;
+       int retry = 0;
+
+       if (skb == NULL)
+       {
+               /* If we get here, some higher layer thinks we've missed an
+                * tx-done interrupt.
+                */
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: interface %s got kicked!\n",
+                       card->devname, dev->name)
+               ;
+#endif
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (set_bit(0, (void*)&card->wandev.critical))
+       {
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: if_send() hit critical section!\n",
+                       card->devname)
+               ;
+#endif
+               return 1;
+       }
+
+       if (set_bit(0, (void*)&dev->tbusy))
+       {
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+                       card->devname, dev->name)
+               ;
+#endif
+               ++card->wandev.stats.collisions;
+               retry = 1;
+       }
+       else if (card->wandev.state != WAN_CONNECTED)
+               ++card->wandev.stats.tx_dropped
+       ;
+       else if (!skb->protocol)
+               ++card->wandev.stats.tx_errors
+       ;
+       else if (ppp_send(card, skb->data, skb->len, skb->protocol))
+       {
+               ppp_flags_t* flags = card->flags;
+
+               flags->imask |= 0x02;   /* unmask Tx interrupts */
+               retry = 1;
+       }
+       else ++card->wandev.stats.tx_packets;
+
+       if (!retry)
+       {
+               dev_kfree_skb(skb, FREE_WRITE);
+               dev->tbusy = 0;
+       }
+       card->wandev.critical = 0;
+       return retry;
+}
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+static struct enet_statistics* if_stats (struct device* dev)
+{
+       sdla_t* card = dev->priv;
+
+       return &card->wandev.stats;
+}
+
+/****** PPP Firmware Interface Functions ************************************/
+
+/*============================================================================
+ * Read firmware code version.
+ *     Put code version as ASCII string in str. 
+ */
+static int ppp_read_version (sdla_t* card, char* str)
+{
+       ppp_mbox_t* mb = card->mbox;
+       int err;
+
+       memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+       mb->cmd.command = PPP_READ_CODE_VERSION;
+       err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+       if (err != CMD_OK) ppp_error(card, err, mb);
+       else if (str)
+       {
+               int len = mb->cmd.length;
+
+               memcpy(str, mb->data, len);
+               str[len] = '\0';
+       }
+       return err;
+}
+
+/*============================================================================
+ * Configure PPP firmware.
+ */
+static int ppp_configure (sdla_t* card, void* data)
+{
+       ppp_mbox_t* mb = card->mbox;
+       int data_len = (card->hw.fwid == SFID_PPP502) ?
+               sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t)
+       ;
+       int err;
+
+       memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+       memcpy(mb->data, data, data_len);
+       mb->cmd.length  = data_len;
+       mb->cmd.command = PPP_SET_CONFIG;
+       err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+       if (err != CMD_OK) ppp_error(card, err, mb);
+       return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int ppp_set_intr_mode (sdla_t* card, unsigned mode)
+{
+       ppp_mbox_t* mb = card->mbox;
+       int err;
+
+       memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+       mb->data[0] = mode;
+       switch (card->hw.fwid)
+       {
+       case SFID_PPP502:
+               mb->cmd.length  = 1;
+               break;
+
+       case SFID_PPP508:
+       default:
+               mb->data[1] = card->hw.irq;
+               mb->cmd.length = 2;
+       }
+       mb->cmd.command = PPP_SET_INTR_FLAGS;
+       err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+       if (err != CMD_OK) ppp_error(card, err, mb);
+       return err;
+}
+
+/*============================================================================
+ * Enable communications.
+ */
+static int ppp_comm_enable (sdla_t* card)
+{
+       ppp_mbox_t* mb = card->mbox;
+       int err;
+
+       memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+       mb->cmd.command = PPP_COMM_ENABLE;
+       err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+       if (err != CMD_OK) ppp_error(card, err, mb);
+       return err;
+}
+
+/*============================================================================
+ * Disable communications.
+ */
+static int ppp_comm_disable (sdla_t* card)
+{
+       ppp_mbox_t* mb = card->mbox;
+       int err;
+
+       memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+       mb->cmd.command = PPP_COMM_DISABLE;
+       err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+       if (err != CMD_OK) ppp_error(card, err, mb);
+       return err;
+}
+
+/*============================================================================
+ * Send packet.
+ *     Return: 0 - o.k.
+ *             1 - no transmit buffers available
+ */
+static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto)
+{
+       ppp_buf_ctl_t* txbuf = card->u.p.txbuf;
+       unsigned long addr, cpu_flags;
+
+       if (txbuf->flag)
+               return 1
+       ;
+       if (card->hw.fwid == SFID_PPP502)
+               addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]
+       ; 
+       else addr = txbuf->buf.ptr;
+
+       save_flags(cpu_flags);
+       cli();
+       sdla_poke(&card->hw, addr, data, len);
+       restore_flags(cpu_flags);
+       txbuf->length = len;            /* frame length */
+       if (proto == ETH_P_IPX)
+               txbuf->proto = 0x01     /* protocol ID */
+       ;
+       txbuf->flag = 1;                /* start transmission */
+
+       /* Update transmit buffer control fields */
+       card->u.p.txbuf = ++txbuf;
+       if ((void*)txbuf > card->u.p.txbuf_last)
+               card->u.p.txbuf = card->u.p.txbuf_base
+       ;
+       return 0;
+}
+
+/****** Firmware Error Handler **********************************************/
+
+/*============================================================================
+ * Firmware error handler.
+ *     This routine is called whenever firmware command returns non-zero
+ *     return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb)
+{
+       unsigned cmd = mb->cmd.command;
+
+       switch (err)
+       {
+       case CMD_TIMEOUT:
+               printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+                       card->devname, cmd)
+               ;
+               break;
+
+       default:
+               printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+                       card->devname, cmd, err)
+               ;
+       }
+       return 0;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * PPP interrupt service routine.
+ */
+STATIC void wpp_isr (sdla_t* card)
+{
+       ppp_flags_t* flags = card->flags;
+
+       switch (flags->iflag)
+       {
+       case 0x01:      /* receive interrupt */
+               rx_intr(card);
+               break;
+
+       case 0x02:      /* transmit interrupt */
+               flags->imask &= ~0x02;
+               tx_intr(card);
+               break;
+
+       default:        /* unexpected interrupt */
+               printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
+                       card->devname, flags->iflag)
+               ;
+       }
+       flags->iflag = 0;
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void rx_intr (sdla_t* card)
+{
+       ppp_buf_ctl_t* rxbuf = card->rxmb;
+       struct device* dev = card->wandev.dev;
+       struct sk_buff* skb;
+       unsigned len;
+       void* buf;
+
+       if (rxbuf->flag != 0x01)
+       {
+               printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
+                       card->devname, (unsigned)rxbuf)
+               ;
+               return;
+       }
+
+       if (!dev || !dev->start)
+               goto rx_done
+       ;
+       len  = rxbuf->length;
+
+       /* Allocate socket buffer */
+       skb = dev_alloc_skb(len);
+       if (skb == NULL)
+       {
+               printk(KERN_INFO "%s: no socket buffers available!\n",
+                       card->devname)
+               ;
+               ++card->wandev.stats.rx_dropped;
+               goto rx_done;
+       }
+
+       /* Copy data to the socket buffer */
+       if (card->hw.fwid == SFID_PPP502)
+       {
+               unsigned addr = (rxbuf->buf.o_p[1] << 8) + rxbuf->buf.o_p[0]; 
+
+               buf = skb_put(skb, len);
+               sdla_peek(&card->hw, addr, buf, len);
+       }
+       else
+       {
+               unsigned addr = rxbuf->buf.ptr;
+
+               if ((addr + len) > card->u.p.rx_top)
+               {
+                       unsigned tmp = card->u.p.rx_top - addr;
+
+                       buf = skb_put(skb, tmp);
+                       sdla_peek(&card->hw, addr, buf, tmp);
+                       addr = card->u.p.rx_base;
+                       len -= tmp;
+               }
+               buf = skb_put(skb, len);
+               sdla_peek(&card->hw, addr, buf, len);
+       }
+
+       /* Decapsulate packet and pass it up the protocol stack */
+       switch (rxbuf->proto)
+       {
+       case 0x00:
+               skb->protocol = htons(ETH_P_IP);
+               break;
+
+       case 0x01:
+               skb->protocol = htons(ETH_P_IPX);
+               break;
+       }
+       skb->dev = dev;
+       netif_rx(skb);
+       ++card->wandev.stats.rx_packets;
+
+rx_done:
+       /* Release buffer element and calculate a pointer to the next one */
+       rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
+       card->rxmb = ++rxbuf;
+       if ((void*)rxbuf > card->u.p.rxbuf_last)
+               card->rxmb = card->u.p.rxbuf_base
+       ;
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ */
+static void tx_intr (sdla_t* card)
+{
+       struct device* dev = card->wandev.dev;
+
+       if (!dev || !dev->start)
+               return
+       ;
+       dev->tbusy = 0;
+       dev_tint(dev);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thread' to allow for
+ * time-dependent housekeeping work.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+static void wpp_poll (sdla_t* card)
+{
+       switch(card->wandev.state)
+       {
+       case WAN_CONNECTED:
+               poll_active(card);
+               break;
+
+       case WAN_CONNECTING:
+               poll_connecting(card);
+               break;
+
+       case WAN_DISCONNECTED:
+               poll_disconnected(card);
+               break;
+       }
+}
+
+/*============================================================================
+ * Monitor active link phase.
+ */
+static void poll_active (sdla_t* card)
+{
+       ppp_flags_t* flags = card->flags;
+
+       if (flags->disc_cause & 0x03)
+       {
+               wanpipe_set_state(card, WAN_DISCONNECTED);
+               show_disc_cause(card, flags->disc_cause);
+       }
+}
+
+/*============================================================================
+ * Monitor link establishment phase.
+ * o if connection timed out, disconnect the link.
+ */
+static void poll_connecting (sdla_t* card)
+{
+       ppp_flags_t* flags = card->flags;
+
+       if (flags->lcp_state == 0x09)
+       {
+               wanpipe_set_state(card, WAN_CONNECTED);
+       }
+       else if (flags->disc_cause & 0x03)
+       {
+               wanpipe_set_state(card, WAN_DISCONNECTED);
+               show_disc_cause(card, flags->disc_cause);
+       }
+}
+
+/*============================================================================
+ * Monitor physical link disconnected phase.
+ *  o if interface is up and the hold-down timeout has expired, then retry
+ *    connection.
+ */
+static void poll_disconnected (sdla_t* card)
+{
+       struct device* dev = card->wandev.dev;
+
+       if (dev && dev->start &&
+           ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
+       {
+               wanpipe_set_state(card, WAN_CONNECTING);
+               ppp_comm_enable(card);
+       }
+}
+
+/****** Miscellaneous Functions *********************************************/
+
+/*============================================================================
+ * Configure S502 adapter.
+ */
+static int config502 (sdla_t* card)
+{
+       ppp502_conf_t cfg;
+
+       /* Prepare PPP configuration structure */
+       memset(&cfg, 0, sizeof(ppp502_conf_t));
+
+       if (card->wandev.clocking)
+               cfg.line_speed = bps_to_speed_code(card->wandev.bps)
+       ;
+       cfg.txbuf_num           = 4;
+       cfg.mtu_local           = card->wandev.mtu;
+       cfg.mtu_remote          = card->wandev.mtu;
+       cfg.restart_tmr         = 30;
+       cfg.auth_rsrt_tmr       = 30;
+       cfg.auth_wait_tmr       = 300;
+       cfg.mdm_fail_tmr        = 5;
+       cfg.dtr_drop_tmr        = 1;
+       cfg.connect_tmout       = 900;
+       cfg.conf_retry          = 10;
+       cfg.term_retry          = 2;
+       cfg.fail_retry          = 5;
+       cfg.auth_retry          = 10;
+       cfg.ip_options          = 0x80;
+       cfg.ipx_options         = 0xA0;
+/*
+       cfg.ip_local            = dev->pa_addr;
+       cfg.ip_remote           = dev->pa_dstaddr;
+*/
+       return ppp_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Configure S508 adapter.
+ */
+static int config508 (sdla_t* card)
+{
+       ppp508_conf_t cfg;
+
+       /* Prepare PPP configuration structure */
+       memset(&cfg, 0, sizeof(ppp508_conf_t));
+
+       if (card->wandev.clocking)
+               cfg.line_speed = card->wandev.bps
+       ;
+       if (card->wandev.interface == WANOPT_RS232)
+               cfg.conf_flags |= 0x0020;
+       ;
+       cfg.txbuf_percent       = 60;   /* % of Tx bufs */
+       cfg.mtu_local           = card->wandev.mtu;
+       cfg.mtu_remote          = card->wandev.mtu;
+       cfg.restart_tmr         = 30;
+       cfg.auth_rsrt_tmr       = 30;
+       cfg.auth_wait_tmr       = 300;
+       cfg.mdm_fail_tmr        = 5;
+       cfg.dtr_drop_tmr        = 1;
+       cfg.connect_tmout       = 900;
+       cfg.conf_retry          = 10;
+       cfg.term_retry          = 2;
+       cfg.fail_retry          = 5;
+       cfg.auth_retry          = 10;
+       cfg.ip_options          = 0x80;
+       cfg.ipx_options         = 0xA0;
+/*
+       cfg.ip_local            = dev->pa_addr;
+       cfg.ip_remote           = dev->pa_dstaddr;
+*/
+       return ppp_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Show disconnection cause.
+ */
+static void show_disc_cause (sdla_t* card, unsigned cause)
+{
+       if (cause & 0x0002) printk(KERN_INFO
+               "%s: link terminated by peer\n", card->devname)
+       ;
+       else if (cause & 0x0004) printk(KERN_INFO
+               "%s: link terminated by user\n", card->devname)
+       ;
+       else if (cause & 0x0008) printk(KERN_INFO
+               "%s: authentication failed\n", card->devname)
+       ;
+       else if (cause & 0x0010) printk(KERN_INFO
+               "%s: authentication protocol negotiation failed\n",
+               card->devname)
+       ;
+       else if (cause & 0x0020) printk(KERN_INFO
+               "%s: peer's request for authentication rejected\n",
+               card->devname)
+       ;
+       else if (cause & 0x0040) printk(KERN_INFO
+               "%s: MRU option rejected by peer\n", card->devname)
+       ;
+       else if (cause & 0x0080) printk(KERN_INFO
+               "%s: peer's MRU was too small\n", card->devname)
+       ;
+       else if (cause & 0x0100) printk(KERN_INFO
+               "%s: failed to negotiate peer's LCP options\n",
+               card->devname)
+       ;
+       else if (cause & 0x0200) printk(KERN_INFO
+               "%s: failed to negotiate peer's IPCP options\n",
+               card->devname)
+       ;
+       else if (cause & 0x0400) printk(KERN_INFO
+               "%s: failed to negotiate peer's IPXCP options\n",
+               card->devname)
+       ;
+}
+
+/*============================================================================
+ * Convert line speed in bps to a number used by S502 code.
+ */
+static unsigned char bps_to_speed_code (unsigned long bps)
+{
+       unsigned char   number;
+
+       if (bps <= 1200)        number = 0x01 ;
+       else if (bps <= 2400)   number = 0x02;
+       else if (bps <= 4800)   number = 0x03;
+       else if (bps <= 9600)   number = 0x04;
+       else if (bps <= 19200)  number = 0x05;
+       else if (bps <= 38400)  number = 0x06;
+       else if (bps <= 45000)  number = 0x07;
+       else if (bps <= 56000)  number = 0x08;
+       else if (bps <= 64000)  number = 0x09;
+       else if (bps <= 74000)  number = 0x0A;
+       else if (bps <= 112000) number = 0x0B;
+       else if (bps <= 128000) number = 0x0C;
+       else number = 0x0D;
+
+       return number;
+}
+
+/****** End *****************************************************************/
diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
new file mode 100644 (file)
index 0000000..f0a8095
--- /dev/null
@@ -0,0 +1,1961 @@
+/*****************************************************************************
+* sdla_x25.c   WANPIPE(tm) Multiprotocol WAN Link Driver.  X.25 module.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 07, 1997 Gene Kozin      Initial version.
+*****************************************************************************/
+
+#if    !defined(__KERNEL__) || !defined(MODULE)
+#error This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/kernel.h>      /* printk(), and other useful stuff */
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/string.h>      /* inline memset(), etc. */
+#include <linux/malloc.h>      /* kmalloc(), kfree() */
+#include <linux/router.h>      /* WAN router definitions */
+#include <linux/wanpipe.h>     /* WANPIPE common user API definitions */
+#include <asm/byteorder.h>     /* htons(), etc. */
+
+#define        _GNUC_
+#include <linux/sdla_x25.h>    /* X.25 firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#define        CMD_OK          0               /* normal firmware return code */
+#define        CMD_TIMEOUT     0xFF            /* firmware command timed out */
+#define        MAX_CMD_RETRY   10              /* max number of firmware retries */
+
+#define        X25_CHAN_MTU    4096            /* unfragmented logical channel MTU */
+#define        X25_HRDHDR_SZ   6               /* max encapsulation header size */
+#define        X25_CONCT_TMOUT (90*HZ)         /* link connection timeout */
+#define        X25_RECON_TMOUT (10*HZ)         /* link connection timeout */
+#define        CONNECT_TIMEOUT (90*HZ)         /* link connection timeout */
+#define        HOLD_DOWN_TIME  (30*HZ)         /* link hold down time */
+
+/****** Data Structures *****************************************************/
+
+/* This is an extention of the 'struct device' we create for each network
+ * interface to keep the rest of X.25 channel-specific data.
+ */
+typedef struct x25_channel
+{
+       char name[WAN_IFNAME_SZ+1];     /* interface name, ASCIIZ */
+       char addr[WAN_ADDRESS_SZ+1];    /* media address, ASCIIZ */
+       unsigned lcn;                   /* logical channel number */
+       unsigned tx_pkt_size;
+       unsigned short protocol;        /* ethertype, 0 - multiplexed */
+       char svc;                       /* 0 - permanent, 1 - switched */
+       char state;                     /* channel state */
+       char drop_sequence;             /* mark sequence for dropping */
+       unsigned long state_tick;       /* time of the last state change */
+       unsigned idle_timeout;          /* sec, before disconnecting */
+       unsigned hold_timeout;          /* sec, before re-connecting */
+       struct sk_buff* rx_skb;         /* receive socket buffer */
+       struct sk_buff* tx_skb;         /* transmit socket buffer */
+       sdla_t* card;                   /* -> owner */
+       int ch_idx;
+       struct enet_statistics ifstats; /* interface statistics */
+} x25_channel_t;
+
+typedef struct x25_call_info
+{
+       char dest[17];                  /* ASCIIZ destination address */
+       char src[17];                   /* ASCIIZ source address */
+       char nuser;                     /* number of user data bytes */
+       unsigned char user[127];        /* user data */
+       char nfacil;                    /* number of facilities */
+       struct
+       {
+               unsigned char code;
+               unsigned char parm;
+       } facil[64];                    /* facilities */
+} x25_call_info_t;
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+       wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
+
+/* Network device interface */
+static int if_init   (struct device* dev);
+static int if_open   (struct device* dev);
+static int if_close  (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+       unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+       struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* Interrupt handlers */
+static void wpx_isr    (sdla_t* card);
+static void rx_intr    (sdla_t* card);
+static void tx_intr    (sdla_t* card);
+static void status_intr        (sdla_t* card);
+static void event_intr (sdla_t* card);
+static void spur_intr  (sdla_t* card);
+
+/* Background polling routines */
+static void wpx_poll (sdla_t* card);
+static void poll_disconnected (sdla_t* card);
+static void poll_connecting (sdla_t* card);
+static void poll_active (sdla_t* card);
+
+/* X.25 firmware interface functions */
+static int x25_get_version (sdla_t* card, char* str);
+static int x25_configure (sdla_t* card, TX25Config* conf);
+static int x25_set_intr_mode (sdla_t* card, int mode);
+static int x25_close_hdlc (sdla_t* card);
+static int x25_open_hdlc (sdla_t* card);
+static int x25_setup_hdlc (sdla_t* card);
+static int x25_set_dtr (sdla_t* card, int dtr);
+static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);
+static int x25_place_call (sdla_t* card, x25_channel_t* chan);
+static int x25_accept_call (sdla_t* card, int lcn, int qdm);
+static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);
+static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);
+static int x25_fetch_events (sdla_t* card);
+static int x25_error (sdla_t* card, int err, int cmd, int lcn);
+
+/* X.25 asynchronous event handlers */
+static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+
+/* Miscellaneous functions */
+static int connect (sdla_t* card);
+static int disconnect (sdla_t* card);
+static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
+static int chan_connect (struct device* dev);
+static int chan_disc (struct device* dev);
+static void set_chan_state (struct device* dev, int state);
+static int chan_send (struct device* dev, struct sk_buff* skb);
+static unsigned char bps_to_speed_code (unsigned long bps);
+static unsigned int dec_to_uint (unsigned char* str, int len);
+static unsigned int hex_to_uint (unsigned char* str, int len);
+static void parse_call_info (unsigned char* str, x25_call_info_t* info);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * X.25 Protocol Initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and X.25 firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:     0       o.k.
+ *             < 0     failure.
+ */
+int wpx_init (sdla_t* card, wandev_conf_t* conf)
+{
+       union
+       {
+               char str[80];
+               TX25Config cfg;
+       } u;
+
+       /* Verify configuration ID */
+       if (conf->config_id != WANCONFIG_X25)
+       {
+               printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+                       card->devname, conf->config_id)
+               ;
+               return -EINVAL;
+       }
+
+       /* Initialize protocol-specific fields */
+       card->mbox  = (void*)(card->hw.dpmbase + X25_MBOX_OFFS);
+       card->rxmb  = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
+       card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
+
+       /* Read firmware version.  Note that when adapter initializes, it
+        * clears the mailbox, so it may appear that the first command was
+        * executed successfully when in fact it was merely erased. To work
+        * around this, we execute the first command twice.
+        */
+       if (x25_get_version(card, NULL) || x25_get_version(card, u.str))
+               return -EIO
+       ;
+       printk(KERN_INFO "%s: running X.25 firmware v%s\n",
+               card->devname, u.str)
+       ;
+
+       /* Configure adapter. Here we set resonable defaults, then parse
+        * device configuration structure and set configuration options.
+        * Most configuration options are verified and corrected (if
+        * necessary) since we can't rely on the adapter to do so and don't
+        * want it to fail either.
+        */
+       memset(&u.cfg, 0, sizeof(u.cfg));
+       u.cfg.t1                = 3;
+       u.cfg.n2                = 10;
+       u.cfg.autoHdlc          = 1;            /* automatic HDLC connection */
+       u.cfg.hdlcWindow        = 7;
+       u.cfg.pktWindow         = 2;
+       u.cfg.station           = 1;            /* DTE */
+       u.cfg.options           = 0x0010;       /* disable D-bit pragmatics */
+       u.cfg.ccittCompat       = 1988;
+       u.cfg.t10t20            = 30;
+       u.cfg.t11t21            = 30;
+       u.cfg.t12t22            = 30;
+       u.cfg.t13t23            = 30;
+       u.cfg.t16t26            = 30;
+       u.cfg.t28               = 30;
+       u.cfg.r10r20            = 5;
+       u.cfg.r12r22            = 5;
+       u.cfg.r13r23            = 5;
+
+       if (conf->clocking != WANOPT_EXTERNAL)
+               u.cfg.baudRate = bps_to_speed_code(conf->bps)
+       ;
+       if (conf->station != WANOPT_DTE)
+       {
+               u.cfg.station = 0;              /* DCE mode */
+       }
+
+       /* adjust MTU */
+       if (!conf->mtu || (conf->mtu >= 1024))
+               card->wandev.mtu = 1024
+       ;
+       else if (conf->mtu >= 512)
+               card->wandev.mtu = 512
+       ;
+       else if (conf->mtu >= 256)
+               card->wandev.mtu = 256
+       ;
+       else if (conf->mtu >= 128)
+               card->wandev.mtu = 128
+       ;
+       else conf->mtu = 64;
+       u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
+
+       if (conf->u.x25.hi_pvc)
+       {
+               card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
+               card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
+       }
+       if (conf->u.x25.hi_svc)
+       {
+               card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
+               card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
+       }
+       u.cfg.loPVC       = card->u.x.lo_pvc;
+       u.cfg.hiPVC       = card->u.x.hi_pvc;
+       u.cfg.loTwoWaySVC = card->u.x.lo_svc;
+       u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
+
+       if (conf->u.x25.hdlc_window)
+               u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7)
+       ;
+       if (conf->u.x25.pkt_window)
+               u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7)
+       ;
+       if (conf->u.x25.t1)
+               u.cfg.t1 = min(conf->u.x25.t1, 30)
+       ;
+       u.cfg.t2 = min(conf->u.x25.t2, 29);
+       u.cfg.t4 = min(conf->u.x25.t4, 240);
+       if (conf->u.x25.n2)
+               u.cfg.n2 = min(conf->u.x25.n2, 30)
+       ;
+       if (conf->u.x25.ccitt_compat)
+               u.cfg.ccittCompat = conf->u.x25.ccitt_compat
+       ;
+
+       /* initialize adapter */
+       if ((x25_configure(card, &u.cfg) != CMD_OK) ||
+           (x25_close_hdlc(card) != CMD_OK) ||         /* close HDLC link */
+           (x25_set_dtr(card, 0) != CMD_OK))           /* drop DTR */
+               return -EIO
+       ;
+
+       /* Initialize protocol-specific fields of adapter data space */
+       card->wandev.bps        = conf->bps;
+       card->wandev.interface  = conf->interface;
+       card->wandev.clocking   = conf->clocking;
+       card->wandev.station    = conf->station;
+       card->isr               = &wpx_isr;
+       card->poll              = &wpx_poll;
+       card->wandev.update     = &update;
+       card->wandev.new_if     = &new_if;
+       card->wandev.del_if     = &del_if;
+       card->wandev.state      = WAN_DISCONNECTED;
+       return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+/*
+       sdla_t* card = wandev->private;
+*/
+       return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:     0       o.k.
+ *             < 0     failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
+{
+       sdla_t* card = wandev->private;
+       x25_channel_t* chan;
+       int err = 0;
+
+       if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+       {
+               printk(KERN_INFO "%s: invalid interface name!\n",
+                       card->devname)
+               ;
+               return -EINVAL;
+       }
+
+       /* allocate and initialize private data */
+       chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL);
+       if (chan == NULL)
+               return -ENOMEM
+       ;
+       memset(chan, 0, sizeof(x25_channel_t));
+       strcpy(chan->name, conf->name);
+       chan->card = card;
+
+       /* verify media address */
+       if (conf->addr[0] == '@')               /* SVC */
+       {
+               chan->svc = 1;
+               chan->protocol = ETH_P_IP;
+               strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
+       }
+       else if (is_digit(conf->addr[0]))       /* PVC */
+       {
+               int lcn = dec_to_uint(conf->addr, 0);
+
+               if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc))
+               {
+                       chan->lcn = lcn;
+               }
+               else
+               {
+                       printk(KERN_ERR
+                               "%s: PVC %u is out of range on interface %s!\n",
+                               wandev->name, lcn, chan->name)
+                       ;
+                       err = -EINVAL;
+               }
+       }
+       else
+       {
+               printk(KERN_ERR
+                       "%s: invalid media address on interface %s!\n",
+                       wandev->name, chan->name)
+               ;
+               err = -EINVAL;
+       }
+       if (err)
+       {
+               kfree(chan);
+               return err;
+       }
+
+       /* prepare network device data space for registration */
+       dev->name = chan->name;
+       dev->init = &if_init;
+       dev->priv = chan;
+       return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+       if (dev->priv)
+       {
+               kfree(dev->priv);
+               dev->priv = NULL;
+       }
+       return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       wan_device_t* wandev = &card->wandev;
+       int i;
+
+       /* Initialize device driver entry points */
+       dev->open               = &if_open;
+       dev->stop               = &if_close;
+       dev->hard_header        = &if_header;
+       dev->rebuild_header     = &if_rebuild_hdr;
+       dev->hard_start_xmit    = &if_send;
+       dev->get_stats          = &if_stats;
+
+       /* Initialize media-specific parameters */
+       dev->family             = AF_INET;      /* address family */
+       dev->type               = 30;           /* ARP h/w type */
+       dev->mtu                = X25_CHAN_MTU;
+       dev->hard_header_len    = X25_HRDHDR_SZ; /* media header length */
+       dev->addr_len           = 2;            /* hardware address length */
+       if (!chan->svc)
+               *(unsigned short*)dev->dev_addr = htons(chan->lcn)
+       ;
+
+       /* Initialize hardware parameters (just for reference) */
+       dev->irq        = wandev->irq;
+       dev->dma        = wandev->dma;
+       dev->base_addr  = wandev->ioport;
+       dev->mem_start  = wandev->maddr;
+       dev->mem_end    = wandev->maddr + wandev->msize - 1;
+
+       /* Initialize socket buffers */
+       for (i = 0; i < DEV_NUMBUFFS; ++i)
+               skb_queue_head_init(&dev->buffs[i])
+       ;
+       set_chan_state(dev, WAN_DISCONNECTED);
+       return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o prevent module from unloading by incrementing use count
+ * o if link is disconnected then initiate connection
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+
+       if (dev->start)
+               return -EBUSY           /* only one open is allowed */
+       ;
+       if (set_bit(0, (void*)&card->wandev.critical))
+               return -EAGAIN;
+       ;
+
+       dev->interrupt = 0;
+       dev->tbusy = 0;
+       dev->start = 1;
+       wanpipe_open(card);
+
+       /* If this is the first open, initiate physical connection */
+       if (card->open_cnt == 1)
+               connect(card)
+       ;
+       card->wandev.critical = 0;
+       return 0;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o reset flags.
+ * o if there's no more open channels then disconnect physical link.
+ */
+static int if_close (struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+
+       if (set_bit(0, (void*)&card->wandev.critical))
+               return -EAGAIN;
+       ;
+       dev->start = 0;
+       if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING))
+               chan_disc(dev)
+       ;
+       wanpipe_close(card);
+
+       /* If this is the last close, disconnect physical link */
+       if (!card->open_cnt)
+               disconnect(card)
+       ;
+       card->wandev.critical = 0;
+       return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:     media header length.
+ */
+static int if_header (struct sk_buff* skb, struct device* dev,
+       unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+       x25_channel_t* chan = dev->priv;
+       int hdr_len = dev->hard_header_len;
+
+       skb->protocol = type;
+       if (!chan->protocol)
+       {
+               hdr_len = wan_encapsulate(skb, dev);
+               if (hdr_len < 0)
+               {
+                       hdr_len = 0;
+                       skb->protocol = 0;
+               }
+       }
+       return hdr_len;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:     1       physical address resolved.
+ *             0       physical address not resolved
+ */
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+                          struct sk_buff* skb)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+
+       printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+               card->devname, dev->name)
+       ;
+       return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission).
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:     0       complete (socket buffer must be freed)
+ *             non-0   packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       int retry = 0, queued = 0;
+
+       if (skb == NULL)
+       {
+               /* If we get here, some higher layer thinks we've missed a
+                * tx-done interrupt.
+                */
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: interface %s got kicked!\n",
+                       card->devname, dev->name)
+               ;
+#endif
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (set_bit(0, (void*)&card->wandev.critical))
+       {
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: if_send() hit critical section!\n",
+                       card->devname)
+               ;
+#endif
+               return 1;
+       }
+
+       if (set_bit(0, (void*)&dev->tbusy))
+       {
+#ifdef _DEBUG_
+               printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+                       card->devname, dev->name)
+               ;
+#endif
+               ++chan->ifstats.collisions;
+               retry = 1;
+       }
+       else if (chan->protocol && (chan->protocol != skb->protocol))
+       {
+               printk(KERN_INFO
+                       "%s: unsupported Ethertype 0x%04X on interface %s!\n",
+                       card->devname, skb->protocol, dev->name)
+               ;
+               ++chan->ifstats.tx_errors;
+       }
+       else if (card->wandev.state != WAN_CONNECTED)
+               ++chan->ifstats.tx_dropped
+       ;
+       else switch (chan->state)
+       {
+       case WAN_CONNECTED:
+               dev->trans_start = jiffies;
+               queued = chan_send(dev, skb);
+               if (queued) chan->tx_skb = skb;
+               break;
+
+       case WAN_DISCONNECTED:
+               /* Try to establish connection. If succeded, then start
+                * transmission, else drop a packet.
+                */
+               if (chan_connect(dev) == 0)
+               {
+                       dev->trans_start = jiffies;
+                       queued = chan_send(dev, skb);
+                       if (queued) chan->tx_skb = skb;
+                       break;
+               }
+               /* else fall through */
+
+       default:
+               ++chan->ifstats.tx_dropped;
+       }
+
+       if (!retry && !queued)
+       {
+               dev_kfree_skb(skb, FREE_WRITE);
+               dev->tbusy = 0;
+       }
+       card->wandev.critical = 0;
+       return retry;
+}
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+static struct enet_statistics* if_stats (struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+
+       return &chan->ifstats;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * X.25 Interrupt Service Routine.
+ */
+static void wpx_isr (sdla_t* card)
+{
+       TX25Status* status = card->flags;
+
+       switch (status->iflags)
+       {
+       case 0x01:              /* receive interrupt */
+               rx_intr(card);
+               break;
+
+       case 0x02:              /* transmit interrupt */
+               tx_intr(card);
+               break;
+
+       case 0x04:              /* modem status interrupt */
+               status_intr(card);
+               break;
+
+       case 0x10:              /* network event interrupt */
+               event_intr(card);
+               break;
+
+       default:                /* unwanter interrupt */
+               spur_intr(card);
+       }
+       status->iflags = 0;     /* clear interrupt condition */
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ * This routine handles fragmented IP packets using M-bit according to the
+ * RFC1356.
+ * o map ligical channel number to network interface.
+ * o allocate socket buffer or append received packet to the existing one.
+ * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
+ *   decapsulate packet and pass socket buffer to the protocol stack.
+ *
+ * Notes:
+ * 1. When allocating a socket buffer, if M-bit is set then more data is
+ *    comming and we have to allocate buffer for the maximum IP packet size
+ *    expected on this channel.
+ * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
+ *    socket buffers available) the whole packet sequence must be discarded.
+ */
+static void rx_intr (sdla_t* card)
+{
+       TX25Mbox* rxmb = card->rxmb;
+       unsigned lcn = rxmb->cmd.lcn;           /* logical channel number */
+       unsigned len = rxmb->cmd.length;        /* packet length */
+       unsigned qdm = rxmb->cmd.qdm;           /* Q,D and M bits */
+       wan_device_t* wandev = &card->wandev;
+       struct device* dev = get_dev_by_lcn(wandev, lcn);
+       x25_channel_t* chan;
+       struct sk_buff* skb;
+       void* bufptr;
+
+       if (dev == NULL)
+       {
+               /* Invalid channel, discard packet */
+               printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
+                       card->devname, lcn)
+               ;
+               return;
+       }
+
+       chan = dev->priv;
+       if (chan->drop_sequence)
+       {
+               if (!(qdm & 0x01)) chan->drop_sequence = 0;
+               return;
+       }
+
+       skb = chan->rx_skb;
+       if (skb == NULL)
+       {
+               /* Allocate new socket buffer */
+               int bufsize = (qdm & 0x01) ? dev->mtu : len;
+
+               skb = dev_alloc_skb(bufsize + dev->hard_header_len);
+               if (skb == NULL)
+               {
+                       printk(KERN_INFO "%s: no socket buffers available!\n",
+                               card->devname)
+                       ;
+                       chan->drop_sequence = 1;        /* set flag */
+                       ++chan->ifstats.rx_dropped;
+                       return;
+               }
+               skb->dev = dev;
+               skb->protocol = htons(chan->protocol);
+               chan->rx_skb = skb;
+       }
+
+       if (skb_tailroom(skb) < len)
+       {
+               /* No room for the packet. Call off the whole thing! */
+               dev_kfree_skb(skb, FREE_READ);
+               chan->rx_skb = NULL;
+               if (qdm & 0x01) chan->drop_sequence = 1;
+
+               printk(KERN_INFO "%s: unexpectedly long packet sequence "
+                       "on interface %s!\n", card->devname, dev->name)
+               ;
+               ++chan->ifstats.rx_length_errors;
+               return;
+       }
+
+       /* Append packet to the socket buffer */
+       bufptr = skb_put(skb, len);
+       memcpy(bufptr, rxmb->data, len);
+       if (qdm & 0x01) return;         /* more data is comming */
+
+       dev->last_rx = jiffies;         /* timestamp */
+       chan->rx_skb = NULL;            /* dequeue packet */
+
+       /* Decapsulate packet, if necessary */
+       if (!skb->protocol && !wan_type_trans(skb, dev))
+       {
+               /* can't decapsulate packet */
+               dev_kfree_skb(skb, FREE_READ);
+               ++chan->ifstats.rx_errors;
+       }
+       else
+       {
+               netif_rx(skb);
+               ++chan->ifstats.rx_packets;
+       }
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ *     o Release socket buffer
+ *     o Clear 'tbusy' flag
+ */
+static void tx_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Modem status interrupt handler.
+ */
+static void status_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Network event interrupt handler.
+ */
+static void event_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Spurious interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void spur_intr (sdla_t* card)
+{
+       printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * time-dependent housekeeping work.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+static void wpx_poll (sdla_t* card)
+{
+       switch(card->wandev.state)
+       {
+       case WAN_CONNECTED:
+               poll_active(card);
+               break;
+
+       case WAN_CONNECTING:
+               poll_connecting(card);
+               break;
+
+       case WAN_DISCONNECTED:
+               poll_disconnected(card);
+       }
+}
+
+/*============================================================================
+ * Handle physical link establishment phase.
+ * o if connection timed out, disconnect the link.
+ */
+static void poll_connecting (sdla_t* card)
+{
+       TX25Status* status = card->flags;
+
+       if (status->gflags & X25_HDLC_ABM)
+       {
+               wanpipe_set_state(card, WAN_CONNECTED);
+               x25_set_intr_mode(card, 0x81);  /* enable Rx interrupts */
+       }
+       else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
+           disconnect(card)
+       ;
+}
+
+/*============================================================================
+ * Handle physical link disconnected phase.
+ * o if hold-down timeout has expired and there are open interfaces, connect
+ *   link.
+ */
+static void poll_disconnected (sdla_t* card)
+{
+       if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
+               connect(card)
+       ;
+}
+
+/*============================================================================
+ * Handle active link phase.
+ * o fetch X.25 asynchronous events.
+ * o kick off transmission on all interfaces.
+ */
+static void poll_active (sdla_t* card)
+{
+       struct device* dev;
+
+       /* Fetch X.25 asynchronous events */
+       x25_fetch_events(card);
+
+       for (dev = card->wandev.dev; dev; dev = dev->slave)
+       {
+               x25_channel_t* chan = dev->priv;
+               struct sk_buff* skb = chan->tx_skb;
+
+               /* If there is a packet queued for transmission then kick
+                * the channel's send routine. When transmission is complete
+                * or if error has occured, release socket buffer and reset
+                * 'tbusy' flag.
+                */
+               if (skb && (chan_send(dev, skb) == 0))
+               {
+                       chan->tx_skb = NULL;
+                       dev->tbusy = 0;
+                       dev_kfree_skb(skb, FREE_WRITE);
+               }
+
+               /* If SVC has been idle long enough, close virtual circuit */
+
+/*
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+
+               restore_flags(flags);
+*/
+       }
+}
+
+/****** SDLA Firmware-Specific Functions *************************************
+ * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
+ * asynchronous events' such as restart, interrupt, incomming call request,
+ * call clear request, etc.  They can't be ignored and have to be delt with
+ * immediately.  To tackle with this problem we execute each interface command
+ * in a loop until good return code is received or maximum number of retries
+ * is reached.  Each interface command returns non-zero return code, an
+ * asynchronous event/error handler x25_error() is called.
+ */
+
+/*============================================================================
+ * Read X.25 firmware version.
+ *     Put code version as ASCII string in str. 
+ */
+static int x25_get_version (sdla_t* card, char* str)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.command = X25_READ_CODE_VERSION;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_READ_CODE_VERSION, 0))
+       ;
+
+       if (!err && str)
+       {
+               int len = mbox->cmd.length;
+
+               memcpy(str, mbox->data, len);
+               str[len] = '\0';
+       }
+       return err;
+}
+
+/*============================================================================
+ * Configure adapter.
+ */
+static int x25_configure (sdla_t* card, TX25Config* conf)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
+               mbox->cmd.length  = sizeof(TX25Config);
+               mbox->cmd.command = X25_SET_CONFIGURATION;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_SET_CONFIGURATION, 0))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Close HDLC link.
+ */
+static int x25_close_hdlc (sdla_t* card)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.command = X25_HDLC_LINK_CLOSE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_HDLC_LINK_CLOSE, 0))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Open HDLC link.
+ */
+static int x25_open_hdlc (sdla_t* card)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.command = X25_HDLC_LINK_OPEN;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_HDLC_LINK_OPEN, 0))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Setup HDLC link.
+ */
+static int x25_setup_hdlc (sdla_t* card)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.command = X25_HDLC_LINK_SETUP;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_HDLC_LINK_SETUP, 0))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Set (raise/drop) DTR.
+ */
+static int x25_set_dtr (sdla_t* card, int dtr)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->data[0] = 0;
+               mbox->data[2] = 0;
+               mbox->data[1] = dtr ? 0x02 : 0x01;
+               mbox->cmd.length  = 3;
+               mbox->cmd.command = X25_SET_GLOBAL_VARS;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_SET_GLOBAL_VARS, 0))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int x25_set_intr_mode (sdla_t* card, int mode)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->data[0] = mode;
+               if (card->hw.fwid == SFID_X25_508)
+               {
+                       mbox->data[1] = card->hw.irq;
+                       mbox->cmd.length = 2;
+               }
+               else mbox->cmd.length  = 1;
+               mbox->cmd.command = X25_SET_INTERRUPT_MODE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_SET_INTERRUPT_MODE, 0))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Read X.25 channel configuration.
+ */
+static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int lcn = chan->lcn;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.lcn     = lcn;
+               mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn))
+       ;
+
+       if (!err)
+       {
+               TX25Status* status = card->flags;
+
+               /* calculate an offset into the array of status bytes */
+               if (card->u.x.hi_svc <= 255) 
+                       chan->ch_idx = lcn - 1
+               ;
+               else
+               {
+                       int offset;
+
+                       switch (mbox->data[0] && 0x1F)
+                       {
+                       case 0x01: offset = status->pvc_map; break;
+                       case 0x03: offset = status->icc_map; break;
+                       case 0x07: offset = status->twc_map; break;
+                       case 0x0B: offset = status->ogc_map; break;
+                       default: offset = 0;
+                       }
+                       chan->ch_idx = lcn - 1 - offset;
+               }
+
+               /* get actual transmit packet size on this channel */
+               switch(mbox->data[1] & 0x38)
+               {
+               case 0x00: chan->tx_pkt_size = 16; break;
+               case 0x08: chan->tx_pkt_size = 32; break;
+               case 0x10: chan->tx_pkt_size = 64; break;
+               case 0x18: chan->tx_pkt_size = 128; break;
+               case 0x20: chan->tx_pkt_size = 256; break;
+               case 0x28: chan->tx_pkt_size = 512; break;
+               case 0x30: chan->tx_pkt_size = 1024; break;
+               }
+               printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
+                       card->devname, lcn, chan->tx_pkt_size)
+               ;
+       }
+       return err;
+}
+
+/*============================================================================
+ * Place X.25 call.
+ */
+static int x25_place_call (sdla_t* card, x25_channel_t* chan)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+       char str[64];
+
+       sprintf(str, "-d%s -uCC", chan->addr);
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               strcpy(mbox->data, str);
+               mbox->cmd.length  = strlen(str);
+               mbox->cmd.command = X25_PLACE_CALL;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_PLACE_CALL, 0))
+       ;
+       if (!err)
+       {
+               chan->lcn = mbox->cmd.lcn;
+               chan->protocol = ETH_P_IP;
+       }
+       return err;
+}
+
+/*============================================================================
+ * Accept X.25 call.
+ */
+static int x25_accept_call (sdla_t* card, int lcn, int qdm)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.lcn     = lcn;
+               mbox->cmd.qdm     = qdm;
+               mbox->cmd.command = X25_ACCEPT_CALL;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_ACCEPT_CALL, lcn))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Clear X.25 call.
+ */
+static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.lcn     = lcn;
+               mbox->cmd.cause   = cause;
+               mbox->cmd.diagn   = diagn;
+               mbox->cmd.command = X25_CLEAR_CALL;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- &&
+                x25_error(card, err, X25_CLEAR_CALL, lcn))
+       ;
+       return err;
+}
+
+/*============================================================================
+ * Send X.25 data packet.
+ */
+static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
+{
+       TX25Mbox* mbox = card->mbox;
+       int retry = MAX_CMD_RETRY;
+       int err;
+
+       do
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               memcpy(mbox->data, buf, len);
+               mbox->cmd.length  = len;
+               mbox->cmd.lcn     = lcn;
+               mbox->cmd.qdm     = qdm;
+               mbox->cmd.command = X25_WRITE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+       } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn));
+       return err;
+}
+
+/*============================================================================
+ * Fetch X.25 asynchronous events.
+ */
+static int x25_fetch_events (sdla_t* card)
+{
+       TX25Status* status = card->flags;
+       TX25Mbox* mbox = card->mbox;
+       int err = 0;
+
+       if (status->gflags & 0x20)
+       {
+               memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+               mbox->cmd.command = X25_IS_DATA_AVAILABLE;
+               err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+               if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
+       }
+       return err;
+}
+
+/*============================================================================
+ * X.25 asynchronous event/error handler.
+ *     This routine is called each time interface command returns non-zero
+ *     return code to handle X.25 asynchronous events and common errors.
+ *     Return non-zero to repeat command or zero to cancel it.
+ *
+ * Notes:
+ * 1. This function may be called recursively, as handling some of the
+ *    asynchronous events (e.g. call request) requires execution of the
+ *    interface command(s) that, in turn, may also return asynchronous
+ *    events.  To avoid re-entrancy problems we copy mailbox to dynamically
+ *    allocated memory before processing events.
+ */
+static int x25_error (sdla_t* card, int err, int cmd, int lcn)
+{
+       int retry = 1;
+       unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length;
+       TX25Mbox* mb;
+
+       mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC);
+       if (mb == NULL)
+       {
+               printk(KERN_ERR "%s: x25_error() out of memory!\n",
+                       card->devname)
+               ;
+               return 0;
+       }
+       memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
+       switch (err)
+       {
+       case 0x40:      /* X.25 asynchronous packet was received */
+               mb->data[dlen] = '\0';
+               switch (mb->cmd.pktType & 0x7F)
+               {
+               case 0x30:              /* incomming call */
+                       retry = incomming_call(card, cmd, lcn, mb);
+                       break;
+
+               case 0x31:              /* connected */
+                       retry = call_accepted(card, cmd, lcn, mb);
+                       break;
+
+               case 0x02:              /* call clear request */
+                       retry = call_cleared(card, cmd, lcn, mb);
+                       break;
+
+               case 0x04:              /* reset request */
+                       printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
+                               "Cause:0x%02X Diagn:0x%02X\n",
+                               card->devname, mb->cmd.lcn, mb->cmd.cause,
+                               mb->cmd.diagn)
+                       ;
+                       break;
+
+               case 0x08:              /* restart request */
+                       retry = restart_event(card, cmd, lcn, mb);
+                       break;
+
+               default:
+                       printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
+                               "Cause:0x%02X Diagn:0x%02X\n",
+                               card->devname, mb->cmd.pktType,
+                               mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn)
+                       ;
+               }
+               break;
+
+       case 0x41:      /* X.25 protocol violation indication */
+               printk(KERN_INFO
+                       "%s: X.25 protocol violation on LCN %d! "
+                       "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
+                       card->devname, mb->cmd.lcn,
+                       mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn)
+               ;
+               break;
+
+       case 0x42:      /* X.25 timeout */
+               retry = timeout_event(card, cmd, lcn, mb);
+               break;
+
+       case 0x43:      /* X.25 retry limit exceeded */
+               printk(KERN_INFO
+                       "%s: exceeded X.25 retry limit on LCN %d! "
+                       "Packet:0x%02X Diagn:0x%02X\n", card->devname,
+                       mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn)
+               ;
+               break;
+
+       case 0x08:      /* modem failure */
+               printk(KERN_INFO "%s: modem failure!\n", card->devname);
+               break;
+
+       case 0x09:      /* N2 retry limit */
+               printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
+                       card->devname)
+               ;
+               break;
+
+       case 0x06:      /* unnumbered frame was received while in ABM */
+               printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
+                       card->devname, mb->data[0])
+               ;
+               break;
+
+       case CMD_TIMEOUT:
+               printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+                       card->devname, cmd)
+               ;
+               retry = 0;      /* abort command */
+               break;
+
+       default:
+               printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+                       card->devname, cmd, err)
+               ;
+               retry = 0;      /* abort command */
+       }
+       kfree(mb);
+       return retry;
+}
+
+/****** X.25 Asynchronous Event Handlers *************************************
+ * These functions are called by the x25_error() and should return 0, if
+ * the command resulting in the asynchronous event must be aborted.
+ */
+
+/*============================================================================
+ * Handle X.25 incomming call request.
+ *     RFC 1356 establishes the following rules:
+ *     1. The first octet in the Call User Data (CUD) field of the call
+ *        request packet contains NLPID identifying protocol encapsulation.
+ *     2. Calls MUST NOT be accepted unless router supports requested
+ *        protocol encapsulation.
+ *     3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when
+ *        clearing a call because protocol encapsulation is not supported.
+ *     4. If an incomming call is received while a call request is pending
+ *        (i.e. call collision has occured), the incomming call shall be
+ *        rejected and call request shall be retried.
+ */
+static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+       wan_device_t* wandev = &card->wandev;
+       int new_lcn = mb->cmd.lcn;
+       struct device* dev = get_dev_by_lcn(wandev, new_lcn);
+       x25_channel_t* chan = NULL;
+       int accept = 0;         /* set to '1' if o.k. to accept call */
+       x25_call_info_t* info;
+
+       /* Make sure there is no call collision */
+       if (dev != NULL)
+       {
+               printk(KERN_INFO
+                       "%s: X.25 incomming call collision on LCN %d!\n",
+                       card->devname, new_lcn)
+               ;
+               x25_clear_call(card, new_lcn, 0, 0);
+               return 1;
+       }
+
+       /* Make sure D bit is not set in call request */
+       if (mb->cmd.qdm & 0x02)
+       {
+               printk(KERN_INFO
+                       "%s: X.25 incomming call on LCN %d with D-bit set!\n",
+                       card->devname, new_lcn)
+               ;
+               x25_clear_call(card, new_lcn, 0, 0);
+               return 1;
+       }
+
+       /* Parse call request data */
+       info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC);
+       if (info == NULL)
+       {
+               printk(KERN_ERR
+                       "%s: not enough memory to parse X.25 incomming call "
+                       "on LCN %d!\n", card->devname, new_lcn);
+               x25_clear_call(card, new_lcn, 0, 0);
+               return 1;
+       }
+       parse_call_info(mb->data, info);
+       printk(KERN_INFO "%s: X.25 incomming call on LCN %d! Call data: %s\n",
+               card->devname, new_lcn, mb->data)
+       ;
+
+       /* Find available channel */
+       for (dev = wandev->dev; dev; dev = dev->slave)
+       {
+               chan = dev->priv;
+
+               if (!chan->svc || (chan->state != WAN_DISCONNECTED))
+                       continue
+               ;
+               if (strcmp(info->src, chan->addr) == 0)
+                       break
+               ;
+       }
+
+       if (dev == NULL)
+       {
+               printk(KERN_INFO "%s: no channels available!\n",
+                       card->devname)
+               ;
+               x25_clear_call(card, new_lcn, 0, 0);
+       }
+
+       /* Check requested protocol encapsulation */
+       else if (info->nuser == 0)
+       {
+               printk(KERN_INFO
+                       "%s: no user data in incomming call on LCN %d!\n",
+                       card->devname, new_lcn)
+               ;
+               x25_clear_call(card, new_lcn, 0, 0);
+       }
+       else switch (info->user[0])
+       {
+       case 0:         /* multiplexed */
+               chan->protocol = 0;
+               accept = 1;
+               break;
+
+       case NLPID_IP:  /* IP datagrams */
+               chan->protocol = ETH_P_IP;
+               accept = 1;
+               break;
+
+       case NLPID_SNAP:
+       default:
+               printk(KERN_INFO
+                       "%s: unsupported NLPID 0x%02X in incomming call "
+                       "on LCN %d!\n", card->devname, info->user[0], new_lcn)
+               ;
+               x25_clear_call(card, new_lcn, 0, 249);
+       }
+
+       if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK))
+       {
+               chan->lcn = new_lcn;
+               if (x25_get_chan_conf(card, chan) == CMD_OK)
+                       set_chan_state(dev, WAN_CONNECTED)
+               ;
+               else x25_clear_call(card, new_lcn, 0, 0);
+       }
+       kfree(info);
+       return 1;
+}
+
+/*============================================================================
+ * Handle accepted call.
+ */
+static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+       unsigned new_lcn = mb->cmd.lcn;
+       struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+       x25_channel_t* chan;
+
+       printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n",
+               card->devname, new_lcn)
+       ;
+       if (dev == NULL)
+       {
+               printk(KERN_INFO
+                       "%s: clearing orphaned connection on LCN %d!\n",
+                       card->devname, new_lcn)
+               ;
+               x25_clear_call(card, new_lcn, 0, 0);
+               return 1;
+       }
+
+       /* Get channel configuration and notify router */
+       chan = dev->priv;
+       if (x25_get_chan_conf(card, chan) != CMD_OK)
+       {
+               x25_clear_call(card, new_lcn, 0, 0);
+               return 1;
+       }
+       set_chan_state(dev, WAN_CONNECTED);
+       return 1;
+}
+
+/*============================================================================
+ * Handle cleared call.
+ */
+static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+       unsigned new_lcn = mb->cmd.lcn;
+       struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+
+       printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
+               "Diagn:0x%02X\n",
+               card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn)
+       ;
+       if (dev == NULL) return 1;
+       set_chan_state(dev, WAN_DISCONNECTED);
+
+       return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
+}
+
+/*============================================================================
+ * Handle X.25 restart event.
+ */
+static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+       wan_device_t* wandev = &card->wandev;
+       struct device* dev;
+
+       printk(KERN_INFO
+               "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
+               card->devname, mb->cmd.cause, mb->cmd.diagn)
+       ;
+
+       /* down all logical channels */
+       for (dev = wandev->dev; dev; dev = dev->slave)
+               set_chan_state(dev, WAN_DISCONNECTED)
+       ;
+       return (cmd == X25_WRITE) ? 0 : 1;
+}
+
+/*============================================================================
+ * Handle timeout event.
+ */
+static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+       unsigned new_lcn = mb->cmd.lcn;
+
+       if (mb->cmd.pktType == 0x05)    /* call request time out */
+       {
+               struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+
+               printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
+                       card->devname, new_lcn)
+               ;
+               if (dev) set_chan_state(dev, WAN_DISCONNECTED);
+       }
+       else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
+               card->devname, mb->cmd.pktType, new_lcn)
+       ;
+       return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Establish physical connection.
+ * o open HDLC and raise DTR
+ *
+ * Return:     0       connection established
+ *             1       connection is in progress
+ *             <0      error
+ */
+static int connect (sdla_t* card)
+{
+       if (x25_open_hdlc(card) || x25_setup_hdlc(card))
+               return -EIO
+       ;
+       wanpipe_set_state(card, WAN_CONNECTING);
+       return 1;
+}
+
+/*============================================================================
+ * Tear down physical connection.
+ * o close HDLC link
+ * o drop DTR
+ *
+ * Return:     0
+ *             <0      error
+ */
+static int disconnect (sdla_t* card)
+{
+       wanpipe_set_state(card, WAN_DISCONNECTED);
+       x25_set_intr_mode(card, 0);     /* disable interrupt generation */
+       x25_close_hdlc(card);           /* close HDLC link */
+       x25_set_dtr(card, 0);           /* drop DTR */
+       return 0;
+}
+
+/*============================================================================
+ * Find network device by its channel number.
+ */
+static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
+{
+       struct device* dev;
+
+       for (dev = wandev->dev; dev; dev = dev->slave)
+               if (((x25_channel_t*)dev->priv)->lcn == lcn) break
+       ;
+       return dev;
+}
+
+/*============================================================================
+ * Initiate connection on the logical channel.
+ * o for PVC we just get channel configuration
+ * o for SVCs place an X.25 call
+ *
+ * Return:     0       connected
+ *             >0      connection in progress
+ *             <0      failure
+ */
+static int chan_connect (struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+
+       if (chan->svc)
+       {
+               if (!chan->addr[0])
+                       return -EINVAL  /* no destination address */
+               ;
+               printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
+                       card->devname, chan->addr)
+               ;
+               if (x25_place_call(card, chan) != CMD_OK)
+                       return -EIO
+               ;
+               set_chan_state(dev, WAN_CONNECTING);
+               return 1;
+       }
+       else
+       {
+               if (x25_get_chan_conf(card, chan) != CMD_OK)
+                       return -EIO
+               ;
+               set_chan_state(dev, WAN_CONNECTED);
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Disconnect logical channel.
+ * o if SVC then clear X.25 call
+ */
+static int chan_disc (struct device* dev)
+{
+       x25_channel_t* chan = dev->priv;
+
+       set_chan_state(dev, WAN_DISCONNECTED);
+       if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0);
+       return 0;
+}
+
+/*============================================================================
+ * Set logical channel state.
+ */
+static void set_chan_state (struct device* dev, int state)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (chan->state != state)
+       {
+               switch (state)
+               {
+               case WAN_CONNECTED:
+                       printk (KERN_INFO "%s: interface %s connected!\n",
+                       card->devname, dev->name)
+                       ;
+                       *(unsigned short*)dev->dev_addr = htons(chan->lcn);
+                       break;
+
+               case WAN_CONNECTING:
+                       printk (KERN_INFO "%s: interface %s connecting...\n",
+                               card->devname, dev->name)
+                       ;
+                       break;
+
+               case WAN_DISCONNECTED:
+                       printk (KERN_INFO "%s: interface %s disconnected!\n",
+                               card->devname, dev->name)
+                       ;
+                       if (chan->svc)
+                               *(unsigned short*)dev->dev_addr = 0
+                       ;
+                       break;
+               }
+               chan->state = state;
+       }
+       chan->state_tick = jiffies;
+       restore_flags(flags);
+}
+
+/*============================================================================
+ * Send packet on a logical channel.
+ *     When this function is called, tx_skb field of the channel data space
+ *     points to the transmit socket buffer.  When transmission is complete,
+ *     release socket buffer and reset 'tbusy' flag.
+ *
+ * Return:     0       - transmission complete
+ *             1       - busy
+ *
+ * Notes:
+ * 1. If packet length is greater than MTU for this channel, we'll fragment
+ *    the packet into 'complete sequence' using M-bit.
+ * 2. When transmission is complete, an event notification should be issued
+ *    to the router.
+ */
+static int chan_send (struct device* dev, struct sk_buff* skb)
+{
+       x25_channel_t* chan = dev->priv;
+       sdla_t* card = chan->card;
+       TX25Status* status = card->flags;
+       unsigned len, qdm;
+
+       /* Check to see if channel is ready */
+       if (!(status->cflags[chan->ch_idx] & 0x40))
+               return 1
+       ;
+       if (skb->len > chan->tx_pkt_size)
+       {
+               len = chan->tx_pkt_size;
+               qdm = 0x01;             /* set M-bit (more data) */
+       }
+       else    /* final packet */
+       {
+               len = skb->len;
+               qdm = 0;
+       }
+       switch(x25_send(card, chan->lcn, qdm, len, skb->data))
+       {
+       case 0x00:      /* success */
+               if (qdm)
+               {
+                       skb_pull(skb, len);
+                       return 1;
+               }
+               ++chan->ifstats.tx_packets;
+               break;
+
+       case 0x33:      /* Tx busy */
+               return 1;
+
+       default:        /* failure */
+               ++chan->ifstats.tx_errors;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Parse X.25 call request data and fill x25_call_info_t structure.
+ */
+static void parse_call_info (unsigned char* str, x25_call_info_t* info)
+{
+       memset(info, 0, sizeof(x25_call_info_t));
+       for (; *str; ++str)
+       {
+               int i;
+               unsigned ch;
+
+               if (*str == '-') switch (str[1])
+               {
+               case 'd':       /* destination address */
+                       for (i = 0; i < 16; ++i)
+                       {
+                               ch = str[2+i];
+                               if (!is_digit(ch)) break;
+                               info->dest[i] = ch;
+                       }
+                       break;
+
+               case 's':       /* source address */
+                       for (i = 0; i < 16; ++i)
+                       {
+                               ch = str[2+i];
+                               if (!is_digit(ch)) break;
+                               info->src[i] = ch;
+                       }
+                       break;
+
+               case 'u':       /* user data */
+                       for (i = 0; i < 127; ++i)
+                       {
+                               ch = str[2+2*i];
+                               if (!is_hex_digit(ch)) break;
+                               info->user[i] = hex_to_uint(&str[2+2*i], 2);
+                       }
+                       info->nuser = i;
+                       break;
+
+               case 'f':       /* facilities */
+                       for (i = 0; i < 64; ++i)
+                       {
+                               ch = str[2+4*i];
+                               if (!is_hex_digit(ch)) break;
+                               info->facil[i].code =
+                                       hex_to_uint(&str[2+4*i], 2)
+                               ;
+                               ch = str[4+4*i];
+                               if (!is_hex_digit(ch)) break;
+                               info->facil[i].parm =
+                                       hex_to_uint(&str[4+4*i], 2)
+                               ;
+                       }
+                       info->nfacil = i;
+                       break;
+               }
+       }
+}
+
+/*============================================================================
+ * Convert line speed in bps to a number used by S502 code.
+ */
+static unsigned char bps_to_speed_code (unsigned long bps)
+{
+       unsigned char   number;
+
+       if (bps <= 1200)        number = 0x01 ;
+       else if (bps <= 2400)   number = 0x02;
+       else if (bps <= 4800)   number = 0x03;
+       else if (bps <= 9600)   number = 0x04;
+       else if (bps <= 19200)  number = 0x05;
+       else if (bps <= 38400)  number = 0x06;
+       else if (bps <= 45000)  number = 0x07;
+       else if (bps <= 56000)  number = 0x08;
+       else if (bps <= 64000)  number = 0x09;
+       else if (bps <= 74000)  number = 0x0A;
+       else if (bps <= 112000) number = 0x0B;
+       else if (bps <= 128000) number = 0x0C;
+       else number = 0x0D;
+
+       return number;
+}
+
+/*============================================================================
+ * Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted.
+ */
+static unsigned int dec_to_uint (unsigned char* str, int len)
+{
+       unsigned val;
+
+       if (!len) len = strlen(str);
+       for (val = 0; len && is_digit(*str); ++str, --len)
+               val = (val * 10) + (*str - (unsigned)'0')
+       ;
+       return val;
+}
+
+/*============================================================================
+ * Convert hex string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are conferted.
+ */
+static unsigned int hex_to_uint (unsigned char* str, int len)
+{
+       unsigned val, ch;
+
+       if (!len) len = strlen(str);
+       for (val = 0; len; ++str, --len)
+       {
+               ch = *str;
+               if (is_digit(ch))
+                       val = (val << 4) + (ch - (unsigned)'0')
+               ;
+               else if (is_hex_digit(ch))
+                       val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10)
+               ;
+               else break;
+       }
+       return val;
+}
+
+/****** End *****************************************************************/
diff --git a/drivers/net/sdladrv.c b/drivers/net/sdladrv.c
new file mode 100644 (file)
index 0000000..d1f3bd0
--- /dev/null
@@ -0,0 +1,1829 @@
+/*****************************************************************************
+* sdladrv.c    SDLA Support Module.  Main module.
+*
+*              This module is a library of common hardware-specific functions
+*              used by all Sangoma drivers.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 20, 1996 Gene Kozin      Version 3.0.0. Complete overhaul.
+* Jul 12, 1996 Gene Kozin      Changes for Linux 2.0 compatibility.
+* Jun 12, 1996 Gene Kozin      Added support for S503 card.
+* Apr 30, 1996 Gene Kozin      SDLA hardware interrupt is acknowledged before
+*                              calling protocolspecific ISR.
+*                              Register I/O ports with Linux kernel.
+*                              Miscellaneous bug fixes.
+* Dec 20, 1995 Gene Kozin      Fixed a bug in interrupt routine.
+* Oct 14, 1995 Gene Kozin      Initial version.
+*****************************************************************************/
+
+/*****************************************************************************
+ * Notes:
+ * ------
+ * 1. This code is ment to be system-independent (as much as possible).  To
+ *    achive this, various macros are used to hide system-specific interfaces.
+ *    To compile this code, one of the following constants must be defined:
+ *
+ *     Platform        Define
+ *     --------        ------
+ *     Linux           _LINUX_
+ *     SCO Unix        _SCO_UNIX_
+ *
+ * 2. Supported adapter types:
+ *
+ *     S502A
+ *     ES502A (S502E)
+ *     S503
+ *     S507
+ *     S508 (S509)
+ *
+ * 3. S502A Notes:
+ *
+ *     There is no separate DPM window enable/disable control in S502A.  It
+ *     opens immediately after a window number it written to the HMCR
+ *     register.  To close the window, HMCR has to be written a value
+ *     ????1111b (e.g. 0x0F or 0xFF).
+ *
+ *     S502A DPM window cannot be located at offset E000 (e.g. 0xAE000).
+ *
+ *     There should be a delay of ??? before reading back S502A status
+ *     register.
+ *
+ * 4. S502E Notes:
+ *
+ *     S502E has a h/w bug: although default IRQ line state is HIGH, enabling
+ *     interrupts by setting bit 1 of the control register (BASE) to '1'
+ *     causes it to go LOW! Therefore, disabling interrupts by setting that
+ *     bit to '0' causes low-to-high transition on IRQ line (ghosty
+ *     interrupt). The same occurs when disabling CPU by resetting bit 0 of
+ *     CPU control register (BASE+3) - see the next note.
+ *
+ *     S502E CPU and DPM control is limited:
+ *
+ *     o CPU cannot be stopped independently. Resetting bit 0 of the CPUi
+ *       control register (BASE+3) shuts the board down entirely, including
+ *       DPM;
+ *
+ *     o DPM access cannot be controlled dynamically. Ones CPU is started,
+ *       bit 1 of the control register (BASE) is used to enable/disable IRQ,
+ *       so that access to shared memory cannot be disabled while CPU is
+ *       running.
+ ****************************************************************************/
+
+#define        _LINUX_
+
+#if    defined(_LINUX_)        /****** Linux *******************************/
+
+#include <linux/config.h>      /* OS configuration options */
+#include <linux/kernel.h>      /* printk(), and other useful stuff */
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/string.h>      /* inline memset(), etc. */
+#include <linux/module.h>      /* support for loadable modules */
+#include <linux/sched.h>       /* for jiffies, HZ, etc. */
+#include <linux/sdladrv.h>     /* API definitions */
+#include <linux/sdlasfm.h>     /* SDLA firmware module definitions */
+#include <asm/io.h>            /* for inb(), outb(), etc. */
+#define _INB(port)             (inb(port))
+#define _OUTB(port, byte)      (outb((byte),(port)))
+#define        SYSTEM_TICK             jiffies
+
+#elif  defined(_SCO_UNIX_)     /****** SCO Unix ****************************/
+#if    !defined(INKERNEL)
+#error This code MUST be compiled in kernel mode!
+#endif
+#include <sys/sdladrv.h>       /* API definitions */
+#include <sys/sdlasfm.h>       /* SDLA firmware module definitions */
+#include <sys/inline.h>                /* for inb(), outb(), etc. */
+#define _INB(port)             (inb(port))
+#define _OUTB(port, byte)      (outb((port),(byte)))
+#define        SYSTEM_TICK             lbolt
+
+#else
+#error Unknown system type!
+#endif
+
+#define        MOD_VERSION     3
+#define        MOD_RELEASE     0
+
+#define        SDLA_IODELAY    100     /* I/O Rd/Wr delay, 10 works for 486DX2-66 */
+#define        EXEC_DELAY      20      /* shared memory access delay, mks */
+#define        EXEC_TIMEOUT    (HZ*2)  /* command timeout, in ticks */
+
+/* I/O port address range */
+#define S502A_IORANGE  3
+#define S502E_IORANGE  4
+#define S503_IORANGE   3
+#define S507_IORANGE   4
+#define S508_IORANGE   4
+
+/* Maximum amount of memory */
+#define S502_MAXMEM    0x10000L
+#define S503_MAXMEM    0x10000L
+#define S507_MAXMEM    0x40000L
+#define S508_MAXMEM    0x40000L
+
+/* Minimum amount of memory */
+#define S502_MINMEM    0x8000L
+#define S503_MINMEM    0x8000L
+#define S507_MINMEM    0x20000L
+#define S508_MINMEM    0x20000L
+
+/****** Function Prototypes *************************************************/
+
+/* Module entry points. These are called by the OS and must be public. */
+int init_module (void);
+void cleanup_module (void);
+
+/* Hardware-specific functions */
+static int sdla_detect (sdlahw_t* hw);
+static int sdla_autodpm        (sdlahw_t* hw);
+static int sdla_setdpm (sdlahw_t* hw);
+static int sdla_load   (sdlahw_t* hw, sfm_t* sfm, unsigned len);
+static int sdla_init   (sdlahw_t* hw);
+static unsigned long sdla_memtest (sdlahw_t* hw);
+static int sdla_bootcfg        (sdlahw_t* hw, sfm_info_t* sfminfo);
+static unsigned char make_config_byte (sdlahw_t* hw);
+static int sdla_start  (sdlahw_t* hw, unsigned addr);
+
+static int init_s502a  (sdlahw_t* hw);
+static int init_s502e  (sdlahw_t* hw);
+static int init_s503   (sdlahw_t* hw);
+static int init_s507   (sdlahw_t* hw);
+static int init_s508   (sdlahw_t* hw);
+
+static int detect_s502a        (int port);
+static int detect_s502e        (int port);
+static int detect_s503 (int port);
+static int detect_s507 (int port);
+static int detect_s508 (int port);
+
+/* Miscellaneous functions */
+static int calibrate_delay (int mks);
+static int get_option_index (unsigned* optlist, unsigned optval);
+static unsigned check_memregion (void* ptr, unsigned len);
+static unsigned        test_memregion (void* ptr, unsigned len);
+static unsigned short checksum (unsigned char* buf, unsigned len);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char modname[]  = "sdladrv";
+static char fullname[] = "SDLA Support Module";
+static char copyright[]        = "(c) 1995-1996 Sangoma Technologies Inc.";
+static unsigned        exec_idle;
+
+/* Hardware configuration options.
+ * These are arrays of configuration options used by verification routines.
+ * The first element of each array is its size (i.e. number of options).
+ */
+static unsigned        s502_port_options[] =
+       { 4, 0x250, 0x300, 0x350, 0x360 }
+;
+static unsigned        s503_port_options[] =
+       { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 }
+;
+static unsigned        s508_port_options[] =
+       { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 }
+;
+
+static unsigned s502a_irq_options[] = { 0 };
+static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 };
+static unsigned s503_irq_options[]  = { 5, 2, 3, 4, 5, 7 };
+static unsigned s508_irq_options[]  = { 8, 3, 4, 5, 7, 10, 11, 12, 15 };
+
+static unsigned s502a_dpmbase_options[] =
+{
+       28,
+       0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000,
+       0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000,
+       0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000,
+       0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000,
+};
+static unsigned s507_dpmbase_options[] =
+{
+       32,
+       0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
+       0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
+       0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+       0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
+};
+static unsigned s508_dpmbase_options[] =       /* incl. S502E and S503 */
+{
+       32,
+       0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
+       0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+       0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
+       0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
+};
+
+/*
+static unsigned        s502_dpmsize_options[] = { 2, 0x2000, 0x10000 };
+static unsigned        s507_dpmsize_options[] = { 2, 0x2000, 0x4000 };
+static unsigned        s508_dpmsize_options[] = { 1, 0x2000 };
+*/
+
+static unsigned        s502a_pclk_options[] = { 2, 3600, 7200 };
+static unsigned        s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 };
+static unsigned        s503_pclk_options[]  = { 3, 7200, 8000, 10000 };
+static unsigned        s507_pclk_options[]  = { 1, 12288 };
+static unsigned        s508_pclk_options[]  = { 1, 16000 };
+
+/* Host memory control register masks */
+static unsigned char s502a_hmcr[] =
+{
+       0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C,       /* A0000 - AC000 */
+       0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C,       /* C0000 - CC000 */
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C,       /* D0000 - DC000 */
+       0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C,       /* E0000 - EC000 */
+};
+static unsigned char s502e_hmcr[] =
+{
+       0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */
+       0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */
+       0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */
+};
+static unsigned char s507_hmcr[] =
+{
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */
+       0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */
+       0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */
+       0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */
+};
+static unsigned char s508_hmcr[] =
+{
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */
+       0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */
+       0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */
+};
+
+static unsigned char s507_irqmask[] =
+{
+       0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
+};
+
+/******* Kernel Loadable Module Entry Points ********************************/
+
+/*============================================================================
+ * Module 'insert' entry point.
+ * o print announcement
+ * o initialize static data
+ * o calibrate SDLA shared memory access delay.
+ *
+ * Return:     0       Ok
+ *             < 0     error.
+ * Context:    process
+ */
+
+#ifdef MODULE
+int init_module (void)
+#else
+int wanpipe_init(void)
+{
+       printk(KERN_INFO "%s v%u.%u %s\n",
+               fullname, MOD_VERSION, MOD_RELEASE, copyright);
+       exec_idle = calibrate_delay(EXEC_DELAY);
+#ifdef WANDEBUG        
+       printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
+#endif 
+       return 0;
+}
+
+#ifdef MODULE
+/*============================================================================
+ * Module 'remove' entry point.
+ * o release all remaining system resources
+ */
+void cleanup_module (void)
+{
+}
+#endif
+
+/******* Kernel APIs ********************************************************/
+
+/*============================================================================
+ * Set up adapter.
+ * o detect adapter type
+ * o verify hardware configuration options
+ * o check for hardware conflicts
+ * o set up adapter shared memory
+ * o test adapter memory
+ * o load firmware
+ * Return:     0       ok.
+ *             < 0     error
+ */
+int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
+{
+       unsigned* irq_opt       = NULL; /* IRQ options */
+       unsigned* dpmbase_opt   = NULL; /* DPM window base options */
+       unsigned* pclk_opt      = NULL; /* CPU clock rate options */
+       int err;
+
+       if (sdla_detect(hw))
+       {
+               printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n",
+                       modname, hw->type, hw->port)
+               ;
+               return -EINVAL;
+       }
+       printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n",
+               modname, hw->type, hw->port)
+       ;
+
+       hw->dpmsize = SDLA_WINDOWSIZE;
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               hw->io_range    = S502A_IORANGE;
+               irq_opt         = s502a_irq_options;
+               dpmbase_opt     = s502a_dpmbase_options;
+               pclk_opt        = s502a_pclk_options;
+               break;
+
+       case SDLA_S502E:
+               hw->io_range    = S502E_IORANGE;
+               irq_opt         = s502e_irq_options;
+               dpmbase_opt     = s508_dpmbase_options;
+               pclk_opt        = s502e_pclk_options;
+               break;
+
+       case SDLA_S503:
+               hw->io_range    = S503_IORANGE;
+               irq_opt         = s503_irq_options;
+               dpmbase_opt     = s508_dpmbase_options;
+               pclk_opt        = s503_pclk_options;
+               break;
+
+       case SDLA_S507:
+               hw->io_range    = S507_IORANGE;
+               irq_opt         = s508_irq_options;
+               dpmbase_opt     = s507_dpmbase_options;
+               pclk_opt        = s507_pclk_options;
+               break;
+
+       case SDLA_S508:
+               hw->io_range    = S508_IORANGE;
+               irq_opt         = s508_irq_options;
+               dpmbase_opt     = s508_dpmbase_options;
+               pclk_opt        = s508_pclk_options;
+               break;
+       }
+
+       /* Verify IRQ configuration options */
+       if (!get_option_index(irq_opt, hw->irq))
+       {
+               printk(KERN_ERR "%s: IRQ %d is illegal!\n",
+                       modname, hw->irq)
+               ;
+               return -EINVAL;
+       } 
+
+       /* Verify CPU clock rate configuration options */
+       if (hw->pclk == 0)
+               hw->pclk = pclk_opt[1]  /* use default */
+       ;
+       else if (!get_option_index(pclk_opt, hw->pclk))
+       {
+               printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
+                       modname, hw->pclk)
+               ;
+               return -EINVAL;
+       } 
+       printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n",
+               modname, hw->pclk)
+       ;
+
+       /* Setup adapter dual-port memory window and test memory */
+       if (hw->dpmbase == 0)
+       {
+               err = sdla_autodpm(hw);
+               if (err)
+               {
+                       printk(KERN_ERR
+                               "%s: can't find available memory region!\n",
+                               modname)
+                       ;
+                       return err;
+               }
+       }
+       else if (!get_option_index(dpmbase_opt, hw->dpmbase))
+       {
+               printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
+                       modname, hw->dpmbase)
+               ;
+               return -EINVAL;
+       } 
+       else if (sdla_setdpm(hw))
+       {
+               printk(KERN_ERR
+                       "%s: 8K memory region at 0x%lX is not available!\n",
+                       modname, hw->dpmbase)
+               ;
+               return -EINVAL;
+       } 
+       printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
+               modname, hw->dpmbase)
+       ;
+       printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
+               modname, hw->memory / 1024)
+       ;
+
+       /* Load firmware. If loader fails then shut down adapter */
+       err = sdla_load(hw, sfm, len);
+       if (err) sdla_down(hw);         /* shutdown adapter */
+       return err;
+} 
+
+/*============================================================================
+ * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
+ */
+int sdla_down (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int i;
+
+       if (!port) return -EFAULT;
+
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               _OUTB(port, 0x08);              /* halt CPU */
+               _OUTB(port, 0x08);
+               _OUTB(port, 0x08);
+               hw->regs[0] = 0x08;
+               _OUTB(port + 1, 0xFF);          /* close memory window */
+               hw->regs[1] = 0xFF;
+               break;
+
+       case SDLA_S502E:
+               _OUTB(port + 3, 0);             /* stop CPU */
+               _OUTB(port, 0);                 /* reset board */
+               for (i = 0; i < S502E_IORANGE; ++i)
+                       hw->regs[i] = 0
+               ;
+               break;
+
+       case SDLA_S503:
+       case SDLA_S507:
+       case SDLA_S508:
+               _OUTB(port, 0);                 /* reset board logic */
+               hw->regs[0] = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Map shared memory window into SDLA adress space.
+ */
+int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
+{
+       unsigned port = hw->port;
+       register int tmp;
+
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+       case SDLA_S502E:
+               if (addr < S502_MAXMEM) /* verify parameter */
+               {
+                       tmp = addr >> 13;       /* convert to register mask */
+                       _OUTB(port + 2, tmp);
+                       hw->regs[2] = tmp;
+               }
+               else return -EINVAL;
+               break;
+
+       case SDLA_S503:
+               if (addr < S503_MAXMEM) /* verify parameter */
+               {
+                       tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70);
+                       _OUTB(port, tmp);
+                       hw->regs[0] = tmp;
+               }
+               else return -EINVAL;
+               break;
+
+       case SDLA_S507:
+               if (addr < S507_MAXMEM)
+               {
+                       if (!(_INB(port) & 0x02))
+                               return -EIO
+                       ;
+                       tmp = addr >> 13;       /* convert to register mask */
+                       _OUTB(port + 2, tmp);
+                       hw->regs[2] = tmp;
+               }
+               else return -EINVAL;
+               break;
+
+       case SDLA_S508:
+               if (addr < S508_MAXMEM)
+               {
+                       tmp = addr >> 13;       /* convert to register mask */
+                       _OUTB(port + 2, tmp);
+                       hw->regs[2] = tmp;
+               }
+               else return -EINVAL;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       hw->vector = addr & 0xFFFFE000L;
+       return 0;
+}
+
+/*============================================================================
+ * Enable interrupt generation.
+ */
+int sdla_inten (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       switch (hw->type)
+       {
+       case SDLA_S502E:
+               /* Note thar interrupt control operations on S502E are allowed
+                * only if CPU is enabled (bit 0 of status register is set).
+                */
+               if (_INB(port) & 0x01)
+               {
+                       _OUTB(port, 0x02);      /* bit1 = 1, bit2 = 0 */
+                       _OUTB(port, 0x06);      /* bit1 = 1, bit2 = 1 */
+                       hw->regs[0] = 0x06;
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S503:
+               tmp = hw->regs[0] | 0x04;
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;              /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+               if (!(_INB(port) & 0x02))               /* verify */
+                       return -EIO
+               ;
+               break;
+
+       case SDLA_S508:
+               tmp = hw->regs[0] | 0x10;
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;              /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+               if (!(_INB(port + 1) & 0x10))           /* verify */
+                       return -EIO
+               ;
+               break;
+
+       case SDLA_S502A:
+       case SDLA_S507:
+               break;
+
+       default:
+               return -EINVAL;
+
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Disable interrupt generation.
+ */
+int sdla_intde (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       switch (hw->type)
+       {
+       case SDLA_S502E:
+               /* Notes:
+                *  1) interrupt control operations are allowed only if CPU is
+                *     enabled (bit 0 of status register is set).
+                *  2) disabling interrupts using bit 1 of control register
+                *     causes IRQ line go high, therefore we are going to use
+                *     0x04 instead: lower it to inhibit interrupts to PC.
+                */
+               if (_INB(port) & 0x01)
+               {
+                       _OUTB(port, hw->regs[0] & ~0x04);
+                       hw->regs[0] &= ~0x04;
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S503:
+               tmp = hw->regs[0] & ~0x04;
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;                      /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+               if (_INB(port) & 0x02)                  /* verify */
+                       return -EIO
+               ;
+               break;
+
+       case SDLA_S508:
+               tmp = hw->regs[0] & ~0x10;
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;                      /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+               if (_INB(port) & 0x10)                  /* verify */
+                       return -EIO
+               ;
+               break;
+
+       case SDLA_S502A:
+       case SDLA_S507:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Acknowledge SDLA hardware interrupt.
+ */
+int sdla_intack (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp;
+
+       switch (hw->type)
+       {
+       case SDLA_S502E:
+               /* To acknoledge hardware interrupt we have to toggle bit 3 of
+                * control register: \_/
+                * Note that interrupt control operations on S502E are allowed
+                * only if CPU is enabled (bit 1 of status register is set).
+                */
+               if (_INB(port) & 0x01)
+               {
+                       tmp = hw->regs[0] & ~0x04;
+                       _OUTB(port, tmp);
+                       tmp |= 0x04;
+                       _OUTB(port, tmp);
+                       hw->regs[0] = tmp;
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S503:
+               if (_INB(port) & 0x04)
+               {
+                       tmp = hw->regs[0] & ~0x08;
+                       _OUTB(port, tmp);
+                       tmp |= 0x08;
+                       _OUTB(port, tmp);
+                       hw->regs[0] = tmp;
+               }
+               break;
+
+       case SDLA_S502A:
+       case SDLA_S507:
+       case SDLA_S508:
+       break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Generate an interrupt to adapter's CPU.
+ */
+int sdla_intr (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               if (!(_INB(port) & 0x40))
+               {
+                       _OUTB(port, 0x10);              /* issue NMI to CPU */
+                       hw->regs[0] = 0x10;
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S507:
+               if ((_INB(port) & 0x06) == 0x06)
+               {
+                       _OUTB(port + 3, 0);
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S508:
+               if (_INB(port + 1) & 0x02)
+               {
+                       _OUTB(port, 0x08);
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S502E:
+       case SDLA_S503:
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Execute Adapter Command.
+ * o Set exec flag.
+ * o Busy-wait until flag is reset.
+ * o Return number of loops made, or 0 if command timed out.
+ */
+int sdla_exec (void* opflag)
+{
+       volatile unsigned char* flag = opflag;
+       unsigned long tstop;
+       int nloops;
+
+       if (*flag) return 0;    /* ???? */
+
+       *flag = 1;
+       tstop = SYSTEM_TICK + EXEC_TIMEOUT;
+       for (nloops = 1; *flag; ++nloops)
+       {
+               unsigned delay = exec_idle;
+               while (--delay);                        /* delay */
+               if (SYSTEM_TICK > tstop) return 0;      /* time is up! */
+       }
+       return nloops;
+}
+
+/*============================================================================
+ * Read absolute adapter memory.
+ * Transfer data from adapter's memory to data buffer.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
+{
+       unsigned long oldvec = hw->vector;
+       unsigned winsize = hw->dpmsize;
+       unsigned curpos, curlen;        /* current offset and block size */
+       unsigned long curvec;           /* current DPM window vector */
+       int err = 0;
+
+       if (addr + len > hw->memory)    /* verify arguments */
+               return -EINVAL
+       ;
+       while (len && !err)
+       {
+               curpos = addr % winsize;        /* current window offset */
+               curvec = addr - curpos;         /* current window vector */
+               curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
+
+               /* Relocate window and copy block of data */
+               err = sdla_mapmem(hw, curvec);
+               memcpy((void*)buf, (void*)(hw->dpmbase + curpos), curlen);
+               addr       += curlen;
+               (char*)buf += curlen;
+               len        -= curlen;
+       }
+
+       /* Restore DPM window position */
+       sdla_mapmem(hw, oldvec);
+       return err;
+}
+
+/*============================================================================
+ * Write Absolute Adapter Memory.
+ * Transfer data from data buffer to adapter's memory.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
+{
+       unsigned long oldvec = hw->vector;
+       unsigned winsize = hw->dpmsize;
+       unsigned curpos, curlen;        /* current offset and block size */
+       unsigned long curvec;           /* current DPM window vector */
+       int err = 0;
+
+       if (addr + len > hw->memory)    /* verify arguments */
+               return -EINVAL
+       ;
+       while (len && !err)
+       {
+               curpos = addr % winsize;        /* current window offset */
+               curvec = addr - curpos;         /* current window vector */
+               curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
+
+               /* Relocate window and copy block of data */
+               sdla_mapmem(hw, curvec);
+               memcpy((void*)(hw->dpmbase + curpos), (void*)buf, curlen);
+               addr       += curlen;
+               (char*)buf += curlen;
+               len        -= curlen;
+       }
+
+       /* Restore DPM window position */
+       sdla_mapmem(hw, oldvec);
+       return err;
+}
+
+#ifdef DONT_COMPIPLE_THIS
+#endif /* DONT_COMPIPLE_THIS */
+
+/****** Hardware-Specific Functions *****************************************/
+
+/*============================================================================
+ * Detect adapter type.
+ * o if adapter type is specified then call detection routine for that adapter
+ *   type.  Otherwise call detection routines for every adapter types until
+ *   adapter is detected.
+ *
+ * Notes:
+ * 1) Detection tests are destructive! Adapter will be left in shutdown state
+ *    after the test.
+ */
+static int sdla_detect (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int err = 0;
+
+       if (!port)
+               return -EFAULT
+       ;
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               if (!detect_s502a(port)) err = -ENODEV;
+               break;
+
+       case SDLA_S502E:
+               if (!detect_s502e(port)) err = -ENODEV;
+               break;
+
+       case SDLA_S503:
+               if (!detect_s503(port)) err = -ENODEV;
+               break;
+
+       case SDLA_S507:
+               if (!detect_s507(port)) err = -ENODEV;
+               break;
+
+       case SDLA_S508:
+               if (!detect_s508(port)) err = -ENODEV;
+               break;
+
+       default:
+               if (detect_s502a(port))
+                       hw->type = SDLA_S502A
+               ;
+               else if (detect_s502e(port))
+                       hw->type = SDLA_S502E
+               ;
+               else if (detect_s503(port))
+                       hw->type = SDLA_S503
+               ;
+               else if (detect_s507(port))
+                       hw->type = SDLA_S507
+               ;
+               else if (detect_s508(port))
+                       hw->type = SDLA_S508
+               ;
+               else err = -ENODEV;
+       }
+       return err;
+}
+
+/*============================================================================
+ * Autoselect memory region. 
+ * o try all available DMP address options from the top down until success.
+ */
+static int sdla_autodpm (sdlahw_t* hw)
+{
+       int i, err = -EINVAL;
+       unsigned* opt;
+
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               opt = s502a_dpmbase_options;
+               break;
+
+       case SDLA_S502E:
+       case SDLA_S503:
+       case SDLA_S508:
+               opt = s508_dpmbase_options;
+               break;
+
+       case SDLA_S507:
+               opt = s507_dpmbase_options;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       for (i = opt[0]; i && err; --i)
+       {
+               hw->dpmbase = opt[i];
+               err = sdla_setdpm(hw);
+       }
+       return err;
+}
+
+/*============================================================================
+ * Set up adapter dual-port memory window. 
+ * o shut down adapter
+ * o make sure that no physical memory exists in this region, i.e entire
+ *   region reads 0xFF and is not writable when adapter is shut down.
+ * o initialize adapter hardware
+ * o make sure that region is usable with SDLA card, i.e. we can write to it
+ *   when adapter is configured.
+ */
+static int sdla_setdpm (sdlahw_t* hw)
+{
+       int err;
+
+       /* Shut down card and verify memory region */
+       sdla_down(hw);
+       if (check_memregion((void*)hw->dpmbase, hw->dpmsize))
+               return -EINVAL
+       ;
+
+       /* Initialize adapter and test on-board memory segment by segment.
+        * If memory size appears to be less than shared memory window size,
+        * assume that memory region is unusable.
+        */
+       err = sdla_init(hw);
+       if (err) return err;
+
+       if (sdla_memtest(hw) < hw->dpmsize)     /* less than window size */
+       {
+               sdla_down(hw);
+               return -EIO;
+       }
+       sdla_mapmem(hw, 0L);    /* set window vector at bottom */
+       return 0;
+}
+
+/*============================================================================
+ * Load adapter from the memory image of the SDLA firmware module. 
+ * o verify firmware integrity and compatibility
+ * o start adapter up
+ */
+static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len)
+{
+       int i;
+
+       /* Verify firmware signature */
+       if (strcmp(sfm->signature, SFM_SIGNATURE))
+       {
+               printk(KERN_ERR "%s: not SDLA firmware!\n",
+                       modname)
+               ;
+               return -EINVAL;
+       }
+
+       /* Verify firmware module format version */
+       if (sfm->version != SFM_VERSION)
+       {
+               printk(KERN_ERR
+                       "%s: firmware format %u rejected! Expecting %u.\n",
+                       modname, sfm->version, SFM_VERSION)
+               ;
+               return -EINVAL;
+       }
+
+       /* Verify firmware module length and checksum */
+       if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
+               (checksum((void*)&sfm->info,
+               sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum))
+       {
+               printk(KERN_ERR "%s: firmware corrupted!\n", modname);
+               return -EINVAL;
+       }
+
+       /* Announce */
+       printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,
+               (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",
+               sfm->info.codeid)
+       ;
+
+       /* Scan through the list of compatible adapters and make sure our
+        * adapter type is listed.
+        */
+       for (i = 0;
+            (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
+            ++i)
+       ;
+       if (i == SFM_MAX_SDLA)
+       {
+               printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
+                       modname, hw->type)
+               ;
+               return -EINVAL;
+       }
+
+       /* Make sure there is enough on-board memory */
+       if (hw->memory < sfm->info.memsize)
+       {
+               printk(KERN_ERR
+                       "%s: firmware needs %lu bytes of on-board memory!\n",
+                       modname, sfm->info.memsize)
+               ;
+               return -EINVAL;
+       }
+
+       /* Move code onto adapter */
+       if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize))
+       {
+               printk(KERN_ERR "%s: failed to load code segment!\n",
+                       modname)
+               ;
+               return -EIO;
+       }
+
+       /* Prepare boot-time configuration data and kick-off CPU */
+       sdla_bootcfg(hw, &sfm->info);
+       if (sdla_start(hw, sfm->info.startoffs))
+       {
+               printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
+                       modname)
+               ;
+               return -EIO;
+       }
+
+       /* position DPM window over the mailbox and enable interrupts */
+        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw))
+       {
+               printk(KERN_ERR "%s: adapter hardware failure!\n",
+                       modname)
+               ;
+               return -EIO;
+       }
+       hw->fwid = sfm->info.codeid;            /* set firmware ID */
+       return 0;
+}
+
+/*============================================================================
+ * Initialize SDLA hardware: setup memory window, IRQ, etc.
+ */
+static int sdla_init (sdlahw_t* hw)
+{
+       int i;
+
+       for (i = 0; i < SDLA_MAXIORANGE; ++i)
+               hw->regs[i] = 0
+       ;
+       switch (hw->type)
+       {
+       case SDLA_S502A: return init_s502a(hw);
+       case SDLA_S502E: return init_s502e(hw);
+       case SDLA_S503:  return init_s503(hw);
+       case SDLA_S507:  return init_s507(hw);
+       case SDLA_S508:  return init_s508(hw);
+       }
+       return -EINVAL;
+}
+
+/*============================================================================
+ * Test adapter on-board memory.
+ * o slide DPM window from the bottom up and test adapter memory segment by
+ *   segment.
+ * Return adapter memory size.
+ */
+static unsigned long sdla_memtest (sdlahw_t* hw)
+{
+       unsigned long memsize;
+       unsigned winsize;
+
+       for (memsize = 0, winsize = hw->dpmsize;
+            !sdla_mapmem(hw, memsize) &&
+               (test_memregion((void*)hw->dpmbase, winsize) == winsize)
+            ;
+            memsize += winsize)
+       ;
+       hw->memory = memsize;
+       return memsize;
+}
+
+/*============================================================================
+ * Prepare boot-time firmware configuration data.
+ * o position DPM window
+ * o initialize configuration data area
+ */
+static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo)
+{
+       unsigned char* data;
+
+       if (!sfminfo->datasize) return 0;       /* nothing to do */
+
+       if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
+               return -EIO
+       ;
+       data = (void*)(hw->dpmbase + (sfminfo->dataoffs - hw->vector));
+       memset(data, 0, sfminfo->datasize);
+
+       data[0x00] = make_config_byte(hw);
+       switch (sfminfo->codeid)
+       {
+       case SFID_X25_502:
+       case SFID_X25_508:
+               data[0x01] = 3;                 /* T1 timer */
+               data[0x03] = 10;                /* N2 */
+               data[0x06] = 7;                 /* HDLC window size */
+               data[0x0B] = 1;                 /* DTE */
+               data[0x0C] = 2;                 /* X.25 packet window size */
+               *(short*)&data[0x0D] = 128;     /* default X.25 data size */
+               *(short*)&data[0x0F] = 128;     /* maximum X.25 data size */
+               break;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Prepare configuration byte identifying adapter type and CPU clock rate.
+ */
+static unsigned char make_config_byte (sdlahw_t* hw)
+{
+       unsigned char byte = 0;
+
+       switch (hw->pclk)
+       {
+               case 5000:  byte = 0x01; break;
+               case 7200:  byte = 0x02; break;
+               case 8000:  byte = 0x03; break;
+               case 10000: byte = 0x04; break;
+               case 16000: byte = 0x05; break;
+       }
+       switch (hw->type)
+       {
+               case SDLA_S502E: byte |= 0x80; break;
+               case SDLA_S503:  byte |= 0x40; break;
+       }
+       return byte;
+}
+
+/*============================================================================
+ * Start adapter's CPU.
+ * o calculate a pointer to adapter's cold boot entry point
+ * o position DPM window
+ * o place boot instruction (jp addr) at cold boot entry point
+ * o start CPU
+ */
+static int sdla_start (sdlahw_t* hw, unsigned addr)
+{
+       unsigned port = hw->port;
+       unsigned char* bootp;
+       int err, tmp, i;
+
+       if (!port) return -EFAULT;
+
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               bootp = (void*)(hw->dpmbase + 0x66);
+               break;
+
+       case SDLA_S502E:
+       case SDLA_S503:
+       case SDLA_S507:
+       case SDLA_S508:
+               bootp = (void*)hw->dpmbase;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       err = sdla_mapmem(hw, 0);
+       if (err) return err;
+
+       *bootp = 0xC3;   /* Z80: 'jp' opcode */
+       bootp++;
+       *((unsigned short*)(bootp)) = addr;
+
+       switch (hw->type)
+       {
+       case SDLA_S502A:
+               _OUTB(port, 0x10);              /* issue NMI to CPU */
+               hw->regs[0] = 0x10;
+               break;
+
+       case SDLA_S502E:
+               _OUTB(port + 3, 0x01);          /* start CPU */
+               hw->regs[3] = 0x01;
+               for (i = 0; i < SDLA_IODELAY; ++i);
+               if (_INB(port) & 0x01)          /* verify */
+               {
+                       /*
+                        * Enabling CPU changes functionality of the
+                        * control register, so we have to reset its
+                        * mirror.
+                        */
+                       _OUTB(port, 0);         /* disable interrupts */
+                       hw->regs[0] = 0;
+               }
+               else return -EIO;
+               break;
+
+       case SDLA_S503:
+               tmp = hw->regs[0] | 0x09;       /* set bits 0 and 3 */
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;              /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);
+               if (!(_INB(port) & 0x01))       /* verify */
+                       return -EIO
+               ;
+               break;
+
+       case SDLA_S507:
+               tmp = hw->regs[0] | 0x02;
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;              /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);
+               if (!(_INB(port) & 0x04))       /* verify */
+                       return -EIO
+               ;
+               break;
+
+       case SDLA_S508:
+               tmp = hw->regs[0] | 0x02;
+               _OUTB(port, tmp);
+               hw->regs[0] = tmp;      /* update mirror */
+               for (i = 0; i < SDLA_IODELAY; ++i);
+               if (!(_INB(port + 1) & 0x02))   /* verify */
+                       return -EIO
+               ;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*============================================================================
+ * Initialize S502A adapter.
+ */
+static int init_s502a (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       if (!detect_s502a(port))
+               return -ENODEV
+       ;
+       hw->regs[0] = 0x08;
+       hw->regs[1] = 0xFF;
+
+       /* Verify configuration options */
+       i = get_option_index(s502a_dpmbase_options, hw->dpmbase);
+       if (i == 0)
+               return -EINVAL
+       ;
+
+       tmp = s502a_hmcr[i - 1];
+       switch (hw->dpmsize)
+       {
+       case 0x2000:
+               tmp |= 0x01;
+               break;
+
+       case 0x10000L:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Setup dual-port memory window (this also enables memory access) */
+       _OUTB(port + 1, tmp);
+       hw->regs[1] = tmp;
+       hw->regs[0] = 0x08;
+       return 0;
+}
+
+/*============================================================================
+ * Initialize S502E adapter.
+ */
+static int init_s502e (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       if (!detect_s502e(port))
+               return -ENODEV
+       ;
+
+       /* Verify configuration options */
+       i = get_option_index(s508_dpmbase_options, hw->dpmbase);
+       if (i == 0)
+               return -EINVAL
+       ;
+
+       tmp = s502e_hmcr[i - 1];
+       switch (hw->dpmsize)
+       {
+       case 0x2000:
+               tmp |= 0x01;
+               break;
+
+       case 0x10000L:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Setup dual-port memory window */
+       _OUTB(port + 1, tmp);
+       hw->regs[1] = tmp;
+
+       /* Enable memory access */
+       _OUTB(port, 0x02);
+       hw->regs[0] = 0x02;
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       return (_INB(port) & 0x02) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Initialize S503 adapter.
+ * ---------------------------------------------------------------------------
+ */
+static int init_s503 (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       if (!detect_s503(port))
+               return -ENODEV
+       ;
+
+       /* Verify configuration options */
+       i = get_option_index(s508_dpmbase_options, hw->dpmbase);
+       if (i == 0)
+               return -EINVAL
+       ;
+
+       tmp = s502e_hmcr[i - 1];
+       switch (hw->dpmsize)
+       {
+       case 0x2000:
+               tmp |= 0x01;
+               break;
+
+       case 0x10000L:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Setup dual-port memory window */
+       _OUTB(port + 1, tmp);
+       hw->regs[1] = tmp;
+
+       /* Enable memory access */
+       _OUTB(port, 0x02);
+       hw->regs[0] = 0x02;     /* update mirror */
+       return 0;
+}
+
+/*============================================================================
+ * Initialize S507 adapter.
+ */
+static int init_s507 (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       if (!detect_s507(port))
+               return -ENODEV
+       ;
+
+       /* Verify configuration options */
+       i = get_option_index(s507_dpmbase_options, hw->dpmbase);
+       if (i == 0)
+               return -EINVAL
+       ;
+
+       tmp = s507_hmcr[i - 1];
+       switch (hw->dpmsize)
+       {
+       case 0x2000:
+               tmp |= 0x01;
+               break;
+
+       case 0x10000L:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Enable adapter's logic */
+       _OUTB(port, 0x01);
+       hw->regs[0] = 0x01;
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (!(_INB(port) & 0x20))
+               return -EIO
+       ;
+
+       /* Setup dual-port memory window */
+       _OUTB(port + 1, tmp);
+       hw->regs[1] = tmp;
+
+       /* Enable memory access */
+       tmp = hw->regs[0] | 0x04;
+       if (hw->irq)
+       {
+               i = get_option_index(s508_irq_options, hw->irq);
+               if (i) tmp |= s507_irqmask[i - 1];
+       }
+       _OUTB(port, tmp);
+       hw->regs[0] = tmp;              /* update mirror */
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       return (_INB(port) & 0x08) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Initialize S508 adapter.
+ */
+static int init_s508 (sdlahw_t* hw)
+{
+       unsigned port = hw->port;
+       int tmp, i;
+
+       if (!detect_s508(port))
+               return -ENODEV
+       ;
+
+       /* Verify configuration options */
+       i = get_option_index(s508_dpmbase_options, hw->dpmbase);
+       if (i == 0)
+               return -EINVAL
+       ;
+
+       /* Setup memory configuration */
+       tmp = s508_hmcr[i - 1];
+       _OUTB(port + 1, tmp);
+       hw->regs[1] = tmp;
+
+       /* Enable memory access */
+       _OUTB(port, 0x04);
+       hw->regs[0] = 0x04;             /* update mirror */
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       return (_INB(port + 1) & 0x04) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Detect S502A adapter.
+ *     Following tests are used to detect S502A adapter:
+ *     1. All registers other than status (BASE) should read 0xFF
+ *     2. After writing 00001000b to control register, status register should
+ *        read 01000000b.
+ *     3. After writing 0 to control register, status register should still
+ *        read  01000000b.
+ *     4. After writing 00000100b to control register, status register should
+ *        read 01000100b.
+ *     Return 1 if detected o.k. or 0 if failed.
+ *     Note:   This test is destructive! Adapter will be left in shutdown
+ *             state after the test.
+ */
+static int detect_s502a (int port)
+{
+       int i, j;
+
+       if (!get_option_index(s502_port_options, port))
+               return 0
+       ;
+       for (j = 1; j < SDLA_MAXIORANGE; ++j)
+       {
+               if (_INB(port + j) != 0xFF)
+                       return 0
+               ;
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       }
+
+       _OUTB(port, 0x08);                      /* halt CPU */
+       _OUTB(port, 0x08);
+       _OUTB(port, 0x08);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0x40)
+               return 0
+       ;
+       _OUTB(port, 0x00);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0x40)
+               return 0
+       ;
+       _OUTB(port, 0x04);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0x44)
+               return 0
+       ;
+
+       /* Reset adapter */
+       _OUTB(port, 0x08);
+       _OUTB(port, 0x08);
+       _OUTB(port, 0x08);
+       _OUTB(port + 1, 0xFF);
+       return 1;
+}
+
+/*============================================================================
+ * Detect S502E adapter.
+ *     Following tests are used to verify adapter presence:
+ *     1. All registers other than status (BASE) should read 0xFF.
+ *     2. After writing 0 to CPU control register (BASE+3), status register
+ *        (BASE) should read 11111000b.
+ *     3. After writing 00000100b to port BASE (set bit 2), status register
+ *        (BASE) should read 11111100b.
+ *     Return 1 if detected o.k. or 0 if failed.
+ *     Note:   This test is destructive! Adapter will be left in shutdown
+ *             state after the test.
+ */
+static int detect_s502e (int port)
+{
+       int i, j;
+
+       if (!get_option_index(s502_port_options, port))
+               return 0
+       ;
+       for (j = 1; j < SDLA_MAXIORANGE; ++j)
+       {
+               if (_INB(port + j) != 0xFF)
+                       return 0
+               ;
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       }
+
+       _OUTB(port + 3, 0);                     /* CPU control reg. */
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0xF8)                 /* read status */
+               return 0
+       ;
+       _OUTB(port, 0x04);                      /* set bit 2 */
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0xFC)                 /* verify */
+               return 0
+       ;
+
+       /* Reset adapter */
+       _OUTB(port, 0);
+       return 1;
+}
+
+/*============================================================================
+ * Detect s503 adapter.
+ *     Following tests are used to verify adapter presence:
+ *     1. All registers other than status (BASE) should read 0xFF.
+ *     2. After writing 0 to control register (BASE), status register (BASE)
+ *        should read 11110000b.
+ *     3. After writing 00000100b (set bit 2) to control register (BASE),
+ *        status register should read 11110010b.
+ *     Return 1 if detected o.k. or 0 if failed.
+ *     Note:   This test is destructive! Adapter will be left in shutdown
+ *             state after the test.
+ */
+static int detect_s503 (int port)
+{
+       int i, j;
+
+       if (!get_option_index(s503_port_options, port))
+               return 0
+       ;
+       for (j = 1; j < SDLA_MAXIORANGE; ++j)
+       {
+               if (_INB(port + j) != 0xFF)
+                       return 0
+               ;
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       }
+
+       _OUTB(port, 0);                         /* reset control reg.*/
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0xF0)                 /* read status */
+               return 0
+       ;
+       _OUTB(port, 0x04);                      /* set bit 2 */
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if (_INB(port) != 0xF2)                 /* verify */
+               return 0
+       ;
+
+       /* Reset adapter */
+       _OUTB(port, 0);
+       return 1;
+}
+
+/*============================================================================
+ * Detect s507 adapter.
+ *     Following tests are used to detect s507 adapter:
+ *     1. All ports should read the same value.
+ *     2. After writing 0x00 to control register, status register should read
+ *        ?011000?b.
+ *     3. After writing 0x01 to control register, status register should read
+ *        ?011001?b.
+ *     Return 1 if detected o.k. or 0 if failed.
+ *     Note:   This test is destructive! Adapter will be left in shutdown
+ *             state after the test.
+ */
+static int detect_s507 (int port)
+{
+       int tmp, i, j;
+
+       if (!get_option_index(s508_port_options, port))
+               return 0
+       ;
+       tmp = _INB(port);
+       for (j = 1; j < S507_IORANGE; ++j)
+       {
+               if (_INB(port + j) != tmp)
+                       return 0
+               ;
+               for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       }
+
+       _OUTB(port, 0x00);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if ((_INB(port) & 0x7E) != 0x30)
+               return 0
+       ;
+       _OUTB(port, 0x01);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if ((_INB(port) & 0x7E) != 0x32)
+               return 0
+       ;
+
+       /* Reset adapter */
+       _OUTB(port, 0x00);
+       return 1;
+}
+
+/*============================================================================
+ * Detect s508 adapter.
+ *     Following tests are used to detect s508 adapter:
+ *     1. After writing 0x00 to control register, status register should read
+ *        ??000000b.
+ *     2. After writing 0x10 to control register, status register should read
+ *        ??010000b
+ *     Return 1 if detected o.k. or 0 if failed.
+ *     Note:   This test is destructive! Adapter will be left in shutdown
+ *             state after the test.
+ */
+static int detect_s508 (int port)
+{
+       int i;
+
+       if (!get_option_index(s508_port_options, port))
+               return 0
+       ;
+       _OUTB(port, 0x00);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if ((_INB(port + 1) & 0x3F) != 0x00)
+               return 0
+       ;
+       _OUTB(port, 0x10);
+       for (i = 0; i < SDLA_IODELAY; ++i);     /* delay */
+       if ((_INB(port + 1) & 0x3F) != 0x10)
+               return 0
+       ;
+
+       /* Reset adapter */
+       _OUTB(port, 0x00);
+       return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Calibrate SDLA memory access delay.
+ * Count number of idle loops made within 1 second and then calculate the
+ * number of loops that should be made to achive desired delay.
+ */
+static int calibrate_delay (int mks)
+{
+       unsigned int delay;
+       unsigned long stop;
+
+       for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay);
+       return (delay/(1000000L/mks) + 1);
+}
+
+/*============================================================================
+ * Get option's index into the options list.
+ *     Return option's index (1 .. N) or zero if option is invalid.
+ */
+static int get_option_index (unsigned* optlist, unsigned optval)
+{
+       int i;
+
+       for (i = 1; i <= optlist[0]; ++i)
+               if (optlist[i] == optval) return i
+       ;
+       return 0;
+}
+
+/*============================================================================
+ * Check memory region to see if it's available. 
+ * Return:     0       ok.
+ */
+static unsigned check_memregion (void* ptr, unsigned len)
+{
+       volatile unsigned char* p = ptr;
+
+       for (; len && (*p == 0xFF); --len, ++p)
+       {
+               *p = 0;                 /* attempt to write 0 */
+               if (*p != 0xFF)         /* still has to read 0xFF */
+               {
+                       *p = 0xFF;      /* restore original value */
+                       break;          /* not good */
+               }
+       }
+       return len;
+}
+
+/*============================================================================
+ * Test memory region.
+ * Return:     size of the region that passed the test.
+ * Note:       Region size must be multiple of 2 !
+ */
+static unsigned test_memregion (void* ptr, unsigned len)
+{
+       volatile unsigned short* w_ptr;
+       unsigned len_w = len >> 1;      /* region len in words */
+       unsigned i;
+
+       for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+               *w_ptr = 0xAA55
+       ;
+       for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+               if (*w_ptr != 0xAA55)
+               {
+                       len_w = i;
+                       break;
+               }
+       ;
+       for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+               *w_ptr = 0x55AA
+       ;
+       for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+               if (*w_ptr != 0x55AA)
+               {
+                       len_w = i;
+                       break;
+               }
+       ;
+       for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0;
+       return len_w << 1;
+}
+
+/*============================================================================
+ * Calculate 16-bit CRC using CCITT polynomial.
+ */
+static unsigned short checksum (unsigned char* buf, unsigned len)
+{
+       unsigned short crc = 0;
+       unsigned mask, flag;
+
+       for (; len; --len, ++buf)
+       {
+               for (mask = 0x80; mask; mask >>= 1)
+               {
+                       flag = (crc & 0x8000);
+                       crc <<= 1;
+                       crc |= ((*buf & mask) ? 1 : 0);
+                       if (flag) crc ^= 0x1021;
+               }
+       }
+       return crc;
+}
+
+/****** End *****************************************************************/
diff --git a/drivers/net/sdlamain.c b/drivers/net/sdlamain.c
new file mode 100644 (file)
index 0000000..2ff8a46
--- /dev/null
@@ -0,0 +1,587 @@
+/*****************************************************************************
+* sdlamain.c   WANPIPE(tm) Multiprotocol WAN Link Driver.  Main module.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 02, 1997 Gene Kozin      Initial version.
+*****************************************************************************/
+
+#if    !defined(__KERNEL__) || !defined(MODULE)
+#error This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/config.h>      /* OS configuration options */
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/string.h>      /* inline memset(), etc. */
+#include <linux/malloc.h>      /* kmalloc(), kfree() */
+#include <linux/kernel.h>      /* printk(), and other useful stuff */
+#include <linux/module.h>      /* support for loadable modules */
+#include <linux/ioport.h>      /* request_region(), release_region() */
+#include <linux/tqueue.h>      /* for kernel task queues */
+#include <linux/router.h>      /* WAN router definitions */
+#include <linux/wanpipe.h>     /* WANPIPE common user API definitions */
+#include <asm/segment.h>       /* kernel <-> user copy */
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef _DEBUG_
+#define        STATIC
+#else
+#define        STATIC          static
+#endif
+
+#define        DRV_VERSION     3               /* version number */
+#define        DRV_RELEASE     0               /* release (minor version) number */
+#define        MAX_CARDS       8               /* max number of adapters */
+
+#ifndef        CONFIG_WANPIPE_CARDS            /* configurable option */
+#define        CONFIG_WANPIPE_CARDS 1
+#endif
+
+#define        CMD_OK          0               /* normal firmware return code */
+#define        CMD_TIMEOUT     0xFF            /* firmware command timed out */
+#define        MAX_CMD_RETRY   10              /* max number of firmware retries */
+
+/****** Function Prototypes *************************************************/
+
+/* Module entry points */
+int init_module (void);
+void cleanup_module (void);
+
+/* WAN link driver entry points */
+static int setup    (wan_device_t* wandev, wandev_conf_t* conf);
+static int shutdown (wan_device_t* wandev);
+static int ioctl    (wan_device_t* wandev, unsigned cmd, unsigned long arg);
+
+/* IOCTL hanlers */
+static int ioctl_dump  (sdla_t* card, sdla_dump_t* u_dump);
+static int ioctl_exec  (sdla_t* card, sdla_exec_t* u_exec);
+
+/* Miscellaneous functions */
+STATIC void sdla_isr   (int irq, void* dev_id, struct pt_regs *regs);
+STATIC void sdla_poll  (void* data);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char drvname[]  = "wanpipe";
+static char fullname[] = "WANPIPE(tm) Multiprotocol Driver";
+static char copyright[]        = "(c) 1995-1996 Sangoma Technologies Inc.";
+static int ncards = CONFIG_WANPIPE_CARDS;
+static int active = 0;                 /* number of active cards */
+static sdla_t* card_array = NULL;      /* adapter data space */
+
+/* Task queue element for creating a 'thread' */
+static struct tq_struct sdla_tq =
+{
+       NULL,           /* .next */
+       0,              /* .sync */
+       &sdla_poll,     /* .routine */
+       NULL            /* .data */
+}; 
+
+/******* Kernel Loadable Module Entry Points ********************************/
+
+/*============================================================================
+ * Module 'insert' entry point.
+ * o print announcement
+ * o allocate adapter data space
+ * o initialize static data
+ * o register all cards with WAN router
+ * o calibrate SDLA shared memory access delay.
+ *
+ * Return:     0       Ok
+ *             < 0     error.
+ * Context:    process
+ */
+int init_module (void)
+{
+       int cnt, err = 0;
+
+       printk(KERN_INFO "%s v%u.%u %s\n",
+               fullname, DRV_VERSION, DRV_RELEASE, copyright)
+       ;
+
+       /* Verify number of cards and allocate adapter data space */
+       ncards = min(ncards, MAX_CARDS);
+       ncards = max(ncards, 1);
+       card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL);
+       if (card_array == NULL)
+               return -ENOMEM
+       ;
+       memset(card_array, 0, sizeof(sdla_t) * ncards);
+
+       /* Register adapters with WAN router */
+       for (cnt = 0; cnt < ncards; ++cnt)
+       {
+               sdla_t* card = &card_array[cnt];
+               wan_device_t* wandev = &card->wandev;
+
+               sprintf(card->devname, "%s%d", drvname, cnt + 1);
+               wandev->magic    = ROUTER_MAGIC;
+               wandev->name     = card->devname;
+               wandev->private  = card;
+               wandev->setup    = &setup;
+               wandev->shutdown = &shutdown;
+               wandev->ioctl    = &ioctl;
+               err = register_wandev(wandev);
+               if (err)
+               {
+                       printk(KERN_ERR
+                               "%s: %s registration failed with error %d!\n",
+                               drvname, card->devname, err)
+                       ;
+                       break;
+               }
+       }
+       if (cnt) ncards = cnt;  /* adjust actual number of cards */
+       else kfree(card_array);
+       return err;
+}
+
+/*============================================================================
+ * Module 'remove' entry point.
+ * o unregister all adapters from the WAN router
+ * o release all remaining system resources
+ */
+void cleanup_module (void)
+{
+       int i;
+
+       for (i = 0; i < ncards; ++i)
+       {
+               sdla_t* card = &card_array[i];
+               unregister_wandev(card->devname);
+       }
+       kfree(card_array);
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Setup/confugure WAN link driver.
+ * o check adapter state
+ * o make sure firmware is present in configuration
+ * o make sure I/O port and IRQ are specified
+ * o make sure I/O region is available
+ * o allocate interrupt vector
+ * o setup SDLA hardware
+ * o call appropriate routine to perform protocol-specific initialization
+ * o mark I/O region as used
+ * o if this is the first active card, then schedule background task
+ *
+ * This function is called when router handles ROUTER_SETUP IOCTL. The
+ * configuration structure is in kernel memory (including extended data, if
+ * any).
+ */
+static int setup (wan_device_t* wandev, wandev_conf_t* conf)
+{
+       sdla_t* card;
+       int err = 0;
+       int irq;
+
+       /* Sanity checks */
+       if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL))
+               return -EFAULT
+       ;
+       card = wandev->private;
+       if (wandev->state != WAN_UNCONFIGURED)
+               return -EBUSY           /* already configured */
+       ;
+       if (!conf->data_size || (conf->data == NULL))
+       {
+               printk(KERN_ERR
+                       "%s: firmware not found in configuration data!\n",
+                       wandev->name)
+               ;
+               return -EINVAL;
+       }
+       if (conf->ioport <= 0)
+       {
+               printk(KERN_ERR
+                       "%s: can't configure without I/O port address!\n",
+                       wandev->name)
+               ;
+               return -EINVAL;
+       }
+       if (conf->irq <= 0)
+       {
+               printk(KERN_ERR "%s: can't configure without IRQ!\n",
+                       wandev->name)
+               ;
+               return -EINVAL;
+       }
+
+       /* Make sure I/O port region is available */
+       if (check_region(conf->ioport, SDLA_MAXIORANGE))
+       {
+               printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n",
+                       wandev->name, conf->ioport,
+                       conf->ioport + SDLA_MAXIORANGE)
+               ;
+               return -EINVAL;
+       }
+
+       /* Allocate IRQ */
+       irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */
+       if (request_irq(irq, sdla_isr, 0, wandev->name, card))
+       {
+               printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
+                       wandev->name, irq)
+               ;
+               return -EINVAL;
+       }
+
+       /* Configure hardware, load firmware, etc. */
+       memset(&card->hw, 0, sizeof(sdlahw_t));
+       card->hw.port    = conf->ioport;
+       card->hw.irq     = (conf->irq == 9) ? 2 : conf->irq;
+       card->hw.dpmbase = conf->maddr;
+       card->hw.dpmsize = SDLA_WINDOWSIZE;
+       card->hw.type    = conf->hw_opt[0];
+       card->hw.pclk    = conf->hw_opt[1];
+       err = sdla_setup(&card->hw, conf->data, conf->data_size);
+       if (err)
+       {
+               free_irq(irq, card);
+               return err;
+       }
+
+       /* Intialize WAN device data space */
+       wandev->irq       = irq;
+       wandev->dma       = 0;
+       wandev->ioport    = card->hw.port;
+       wandev->maddr     = card->hw.dpmbase;
+       wandev->msize     = card->hw.dpmsize;
+       wandev->hw_opt[0] = card->hw.type;
+       wandev->hw_opt[1] = card->hw.pclk;
+       wandev->hw_opt[2] = card->hw.memory;
+       wandev->hw_opt[3] = card->hw.fwid;
+
+       /* Protocol-specific initialization */
+       switch (card->hw.fwid)
+       {
+#ifdef CONFIG_WANPIPE_X25
+       case SFID_X25_502:
+       case SFID_X25_508:
+               err = wpx_init(card, conf);
+               break;
+#endif
+
+#ifdef CONFIG_WANPIPE_FR
+       case SFID_FR502:
+       case SFID_FR508:
+               err = wpf_init(card, conf);
+               break;
+#endif
+
+#ifdef CONFIG_WANPIPE_PPP
+       case SFID_PPP502:
+       case SFID_PPP508:
+               err = wpp_init(card, conf);
+               break;
+#endif
+
+       default:
+               printk(KERN_ERR "%s: this firmware is not supported!\n",
+                       wandev->name)
+               ;
+               err = -EINVAL;
+       }
+       if (err)
+       {
+               sdla_down(&card->hw);
+               free_irq(irq, card);
+               return err;
+       }
+       /* Reserve I/O region and schedule background task */
+       request_region(card->hw.port, card->hw.io_range, wandev->name);
+       if (++active == 1)
+               queue_task(&sdla_tq, &tq_scheduler)
+       ;
+       wandev->critical = 0;
+       return 0;
+}
+
+/*============================================================================
+ * Shut down WAN link driver. 
+ * o shut down adapter hardware
+ * o release system resources.
+ *
+ * This function is called by the router when device is being unregistered or
+ * when it handles ROUTER_DOWN IOCTL.
+ */
+static int shutdown (wan_device_t* wandev)
+{
+       sdla_t* card;
+
+       /* sanity checks */
+       if ((wandev == NULL) || (wandev->private == NULL))
+               return -EFAULT
+       ;
+       if (wandev->state == WAN_UNCONFIGURED)
+               return 0
+       ;
+       if (set_bit(0, (void*)&wandev->critical))
+               return -EAGAIN
+       ;
+       card = wandev->private;
+       wandev->state = WAN_UNCONFIGURED;
+       if (--active == 0) schedule();  /* stop background thread */
+       sdla_down(&card->hw);
+       free_irq(wandev->irq, card);
+       release_region(card->hw.port, card->hw.io_range);
+       wandev->critical = 0;
+       return 0;
+}
+
+/*============================================================================
+ * Driver I/O control. 
+ * o verify arguments
+ * o perform requested action
+ *
+ * This function is called when router handles one of the reserved user
+ * IOCTLs.  Note that 'arg' stil points to user address space.
+ */
+static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
+{
+       int err;
+
+       /* sanity checks */
+       if ((wandev == NULL) || (wandev->private == NULL))
+               return -EFAULT
+       ;
+       if (wandev->state == WAN_UNCONFIGURED)
+               return -ENODEV
+       ;
+       if (set_bit(0, (void*)&wandev->critical))
+               return -EAGAIN
+       ;
+       switch (cmd)
+       {
+       case WANPIPE_DUMP:
+               err = ioctl_dump(wandev->private, (void*)arg);
+               break;
+
+       case WANPIPE_EXEC:
+               err = ioctl_exec(wandev->private, (void*)arg);
+               break;
+
+       default:
+               err = -EINVAL;
+       }
+       wandev->critical = 0;
+       return err;
+}
+
+/****** Driver IOCTL Hanlers ************************************************/
+
+/*============================================================================
+ * Dump adpater memory to user buffer.
+ * o verify request structure
+ * o copy request structure to kernel data space
+ * o verify length/offset
+ * o verify user buffer
+ * o copy adapter memory image to user buffer
+ *
+ * Note: when dumping memory, this routine switches curent dual-port memory
+ *      vector, so care must be taken to avoid racing conditions.
+ */
+static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
+{
+       sdla_dump_t dump;
+       unsigned winsize;
+       unsigned long oldvec;   /* DPM window vector */
+       int err = 0;
+
+       if ((u_dump == NULL) ||
+           verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t)))
+               return -EFAULT
+       ;
+       memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t));
+       if ((dump.magic != WANPIPE_MAGIC) ||
+           (dump.offset + dump.length > card->hw.memory))
+               return -EINVAL
+       ;
+       if ((dump.ptr == NULL) ||
+           verify_area(VERIFY_WRITE, dump.ptr, dump.length))
+               return -EFAULT
+       ;
+
+       winsize = card->hw.dpmsize;
+        cli();                         /* >>> critical section start <<< */
+       oldvec = card->hw.vector;
+       while (dump.length)
+       {
+               unsigned pos = dump.offset % winsize;   /* current offset */
+               unsigned long vec = dump.offset - pos;  /* current vector */
+               unsigned len = (dump.length > (winsize - pos)) ?
+                       (winsize - pos) : dump.length
+               ;
+               if (sdla_mapmem(&card->hw, vec) != 0)   /* relocate window */
+               {
+                       err = -EIO;
+                       break;
+               }
+               memcpy_tofs((void*)(dump.ptr),
+                       (void*)(card->hw.dpmbase + pos), len)
+               ;
+               dump.length     -= len;
+               dump.offset     += len;
+               (char*)dump.ptr += len;
+       }
+       sdla_mapmem(&card->hw, oldvec); /* restore DPM window position */
+       sti();                          /* >>> critical section end <<< */
+       return err;
+}
+
+/*============================================================================
+ * Execute adapter firmware command.
+ * o verify request structure
+ * o copy request structure to kernel data space
+ * o call protocol-specific 'exec' function
+ */
+static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec)
+{
+       sdla_exec_t exec;
+
+       if (card->exec == NULL)
+               return -ENODEV
+       ;
+       if ((u_exec == NULL) ||
+           verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t)))
+               return -EFAULT
+       ;
+       memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t));
+       if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
+               return -EINVAL
+       ;
+       return card->exec(card, exec.cmd, exec.data);
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * SDLA Interrupt Service Routine.
+ * o acknowledge SDLA hardware interrupt.
+ * o call protocol-specific interrupt service routine, if any.
+ */
+STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
+{
+#define        card    ((sdla_t*)dev_id)
+
+       if (!card || (card->wandev.state == WAN_UNCONFIGURED))
+               return
+       ;
+       if (card->in_isr)
+       {
+               printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
+                       card->devname, card->wandev.irq)
+               ;
+               return;
+       }
+       card->in_isr = 1;
+       sdla_intack(&card->hw);
+       if (card->isr) card->isr(card);
+       card->in_isr = 0;
+
+#undef card
+}
+
+/*============================================================================
+ * SDLA polling routine.
+ * This routine simulates kernel thread to perform various housekeeping job.
+ *
+ * o for each configured device call its poll() routine
+ * o if there is at least one active card, then reschedule itself once again
+ */
+STATIC void sdla_poll (void* data)
+{
+       int i;
+
+       for (i = 0; i < ncards; ++i)
+       {
+               sdla_t* card = &card_array[i];
+
+               if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
+                   !set_bit(0, (void*)&card->wandev.critical))
+               {
+                       card->poll(card);
+                       card->wandev.critical = 0;
+               }
+       }
+       if (active) queue_task(&sdla_tq, &tq_scheduler);
+}
+
+/*============================================================================
+ * This routine is called by the protocol-specific modules when network
+ * interface is being open.  The only reason we need this, is because we
+ * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void wanpipe_open (sdla_t* card)
+{
+       ++card->open_cnt;
+       MOD_INC_USE_COUNT;
+}
+
+/*============================================================================
+ * This routine is called by the protocol-specific modules when network
+ * interface is being closed.  The only reason we need this, is because we
+ * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void wanpipe_close (sdla_t* card)
+{
+       --card->open_cnt;
+       MOD_DEC_USE_COUNT;
+}
+
+/*============================================================================
+ * Set WAN device state.
+ */
+void wanpipe_set_state (sdla_t* card, int state)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (card->wandev.state != state)
+       {
+               switch (state)
+               {
+               case WAN_CONNECTED:
+                       printk (KERN_INFO "%s: link connected!\n",
+                               card->devname)
+                       ;
+                       break;
+
+               case WAN_CONNECTING:
+                       printk (KERN_INFO "%s: link connecting...\n",
+                               card->devname)
+                       ;
+                       break;
+
+               case WAN_DISCONNECTED:
+                       printk (KERN_INFO "%s: link disconnected!\n",
+                               card->devname)
+                       ;
+                       break;
+               }
+               card->wandev.state = state;
+       }
+       card->state_tick = jiffies;
+       restore_flags(flags);
+}
+
+/****** End *****************************************************************/
index ce2f978b9173badba8fc70ad78ed941d04ccb463..24db6171fb6e4f2062b75ca3fab4cf680629031a 100644 (file)
@@ -64,7 +64,7 @@ static unsigned int net_debug = NET_DEBUG;
 
 /* Information that need to be kept for each board. */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_driver_stats stats;
        unsigned short receive_ptr;             /* What address in packet memory do we expect a recv_pkt_header? */
        long open_time;                         /* Useless example local info. */
 };
@@ -84,7 +84,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct device *dev);
 static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void seeq8005_rx(struct device *dev);
 static int seeq8005_close(struct device *dev);
-static struct enet_statistics *seeq8005_get_stats(struct device *dev);
+static struct net_driver_stats *seeq8005_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 /* Example routines you must write ;->. */
@@ -593,8 +593,7 @@ seeq8005_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *
-seeq8005_get_stats(struct device *dev)
+static struct net_driver_stats *seeq8005_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
 
index dcea3f33f4573d974bf6690a001dd56e38d72c25..3ebd92c1497be4b2cebaa8e0b8178991a921dfd3 100644 (file)
@@ -416,7 +416,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct device *dev)
        return shaper_qframe(sh, skb);
 }
 
-static struct enet_statistics *shaper_get_stats(struct device *dev)
+static struct net_device_stats *shaper_get_stats(struct device *dev)
 {
        return NULL;
 }
index fea13bbbdcd4f9c4058c283384b9c5d2b0bdf08f..ae8b59873c9796f4645513d469cea979e5a400f0 100644 (file)
@@ -36,7 +36,7 @@ struct shaper
        int (*hard_header_cache)(struct dst_entry *dst, struct dst_entry *neigh,
                struct hh_cache *hh);
        void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char *  haddr);
-       struct enet_statistics* (*get_stats)(struct device *dev);
+       struct net_device_stats* (*get_stats)(struct device *dev);
        struct wait_queue *wait_queue;
        struct timer_list timer;
 };
index 161370f25caf271152f3512fbf5b371465a33472..a288e1e40eebe3a1a6449af56fdbb76e0f5ecb99 100644 (file)
@@ -457,7 +457,7 @@ struct priv
     int        tmdlast;  /* last sent descriptor used for error handling, etc */
     void       *rmdbufs[RMDNUM]; /* pointer to the receive buffers */
     void       *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */
-    struct enet_statistics stats; /* Device driver statistics */
+    struct net_driver_stats stats; /* Device driver statistics */
 };
 
 /* global variable declaration */
@@ -491,7 +491,7 @@ static void  SK_rxintr(struct device *dev);
 static void  SK_txintr(struct device *dev);
 static int   SK_close(struct device *dev);
 
-static struct enet_statistics *SK_get_stats(struct device *dev);
+static struct net_driver_stats *SK_get_stats(struct device *dev);
 
 unsigned int SK_rom_addr(void);
 
@@ -1681,14 +1681,14 @@ static int SK_close(struct device *dev)
  *                  It is called by sprintf_stats (dev.c).
  *
  * Parameters     : I : struct device *dev   - our device structure
- * Return Value   : struct enet_statistics * - our current statistics
+ * Return Value   : struct net_driver_stats * - our current statistics
  * Errors         : None
  * Side Effects   : None
  * Update History :
  *     YY/MM/DD  uid  Description
 -*/
 
-static struct enet_statistics *SK_get_stats(struct device *dev)
+static struct net_driver_stats *SK_get_stats(struct device *dev)
 {
 
     struct priv *p = (struct priv *) dev->priv;
index b6f1919826e6ad9498ab15840e5bb07142307b7f..115d419c973fc8e7056225e60b3eb55595f7e44e 100644 (file)
@@ -84,7 +84,7 @@ static unsigned int net_debug = NET_DEBUG;
 
 /* Information that need to be kept for each board. */
 struct net_local {
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        long open_time;                 /* Useless example local info. */
 };
 
@@ -97,19 +97,19 @@ struct net_local {
 
 extern int netcard_probe(struct device *dev);
 
-static int netcard_probe1(struct device *dev, int ioaddr);
-static int net_open(struct device *dev);
+static int     netcard_probe1(struct device *dev, int ioaddr);
+static int     net_open(struct device *dev);
 static int     net_send_packet(struct sk_buff *skb, struct device *dev);
-static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void net_rx(struct device *dev);
-static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
+static void    net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void    net_rx(struct device *dev);
+static int     net_close(struct device *dev);
+static struct  net_device_stats *net_get_stats(struct device *dev);
+static void    set_multicast_list(struct device *dev);
 
 /* Example routines you must write ;->. */
 #define tx_done(dev) 1
 extern void    hardware_send_packet(short ioaddr, char *buf, int length);
-extern void chipset_init(struct device *dev, int startp);
+extern void    chipset_init(struct device *dev, int startp);
 
 /*
  * Check for a network adaptor of this type, and return '0' iff one exists.
@@ -286,8 +286,8 @@ static int netcard_probe1(struct device *dev, int ioaddr)
 
        dev->open               = net_open;
        dev->stop               = net_close;
-       dev->hard_start_xmit = net_send_packet;
-       dev->get_stats  = net_get_stats;
+       dev->hard_start_xmit    = net_send_packet;
+       dev->get_stats          = net_get_stats;
        dev->set_multicast_list = &set_multicast_list;
 
        /* Fill in the fields of the device structure with ethernet values. */
@@ -340,8 +340,7 @@ net_open(struct device *dev)
        return 0;
 }
 
-static int
-net_send_packet(struct sk_buff *skb, struct device *dev)
+static int net_send_packet(struct sk_buff *skb, struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        int ioaddr = dev->base_addr;
@@ -361,15 +360,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
                dev->tbusy=0;
                dev->trans_start = jiffies;
        }
-       /*
-        * If some higher layer thinks we've missed an tx-done interrupt
-        * we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-        * itself.
-        */
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
+
        /*
         * Block a timer-based transmit from overlapping. This could better be
         * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
@@ -379,7 +370,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
        else {
                short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
                unsigned char *buf = skb->data;
-
+               lp->stats.tx_bytes+=skb->len;
                hardware_send_packet(ioaddr, buf, length);
                dev->trans_start = jiffies;
        }
@@ -396,8 +387,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
  * The typical workload of the driver:
  *   Handle the network interface interrupts.
  */
-static void
-net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        struct device *dev = (struct device *)(irq2dev_map[irq]);
        struct net_local *lp;
@@ -458,6 +448,8 @@ net_rx(struct device *dev)
                        /* Malloc up new buffer. */
                        struct sk_buff *skb;
 
+                       lp->stats.rx_bytes+=pkt_len;
+                       
                        skb = dev_alloc_skb(pkt_len);
                        if (skb == NULL) {
                                printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -522,8 +514,7 @@ net_close(struct device *dev)
  * Get the current statistics.
  * This may be called with the card open or closed.
  */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        short ioaddr = dev->base_addr;
index 9910cfebf0bcf186382745df7e6ab8e532afb048..8d8dcbfc1c74c6057a9c56d592e616c6e0cc1494 100644 (file)
@@ -372,6 +372,8 @@ sl_bump(struct slip *sl)
        }
 #endif  /* SL_INCLUDE_CSLIP */
 
+       sl->rx_bytes+=count;
+       
        skb = dev_alloc_skb(count);
        if (skb == NULL)  {
                printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
@@ -508,8 +510,10 @@ sl_xmit(struct sk_buff *skb, struct device *dev)
        }
 
        /* We were not busy, so we are now... :-) */
-       if (skb != NULL) {
+       if (skb != NULL) 
+       {
                sl_lock(sl);
+               sl->tx_bytes+=skb->len;
                sl_encaps(sl, skb->data, skb->len);
                dev_kfree_skb(skb, FREE_WRITE);
        }
@@ -625,8 +629,7 @@ sl_close(struct device *dev)
        return 0;
 }
 
-static int
-slip_receive_room(struct tty_struct *tty)
+static int slip_receive_room(struct tty_struct *tty)
 {
        return 65536;  /* We can handle an infinite amount of data. :-) */
 }
@@ -637,8 +640,8 @@ slip_receive_room(struct tty_struct *tty)
  * a block of SLIP data has been received, which can now be decapsulated
  * and sent on to some IP layer for further processing.
  */
-static void
-slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct slip *sl = (struct slip *) tty->disc_data;
 
@@ -752,19 +755,21 @@ slip_close(struct tty_struct *tty)
 }
 
 
-static struct enet_statistics *
+static struct net_device_stats *
 sl_get_stats(struct device *dev)
 {
-       static struct enet_statistics stats;
+       static struct net_device_stats stats;
        struct slip *sl = (struct slip*)(dev->priv);
 #ifdef SL_INCLUDE_CSLIP
        struct slcompress *comp;
 #endif
 
-       memset(&stats, 0, sizeof(struct enet_statistics));
+       memset(&stats, 0, sizeof(struct net_device_stats));
 
        stats.rx_packets     = sl->rx_packets;
        stats.tx_packets     = sl->tx_packets;
+       stats.rx_bytes       = sl->rx_bytes;
+       stats.tx_bytes       = sl->tx_bytes;
        stats.rx_dropped     = sl->rx_dropped;
        stats.tx_dropped     = sl->tx_dropped;
        stats.tx_errors      = sl->tx_errors;
@@ -828,8 +833,7 @@ slip_esc(unsigned char *s, unsigned char *d, int len)
        return (ptr - d);
 }
 
-static void
-slip_unesc(struct slip *sl, unsigned char s)
+static void slip_unesc(struct slip *sl, unsigned char s)
 {
 
        switch(s) {
index bcead1da90c0e7d2756736762cae8dc651753426..f7569fc12600730efbab820bff73c18f18ac6ebe 100644 (file)
@@ -68,6 +68,8 @@ struct slip {
   /* SLIP interface statistics. */
   unsigned long                rx_packets;     /* inbound frames counter       */
   unsigned long         tx_packets;     /* outbound frames counter      */
+  unsigned long                rx_bytes;       /* inbound byte counte          */
+  unsigned long         tx_bytes;       /* outbound byte counter       */
   unsigned long         rx_errors;      /* Parity, etc. errors          */
   unsigned long         tx_errors;      /* Planned stuff                */
   unsigned long         rx_dropped;     /* No memory for skb            */
index be393398f82441d631af4acdfcd034a5b2bcccd0..ac1833e51f6261b8f5b518a426556b964872eecb 100644 (file)
@@ -175,7 +175,7 @@ struct smc_local {
           can find out semi-useless statistics of how well the card is
           performing
        */
-       struct enet_statistics stats;
+       struct net_driver_stats stats;
 
        /*
           If I have to wait until memory is available to send
@@ -234,7 +234,7 @@ static int smc_close(struct device *dev);
  . This routine allows the proc file system to query the driver's
  . statistics.
 */
-static struct enet_statistics * smc_query_statistics( struct device *dev);
+static struct net_driver_stats * smc_query_statistics( struct device *dev);
 
 /*
  . Finally, a call to set promiscuous mode ( for TCPDUMP and related
@@ -1643,7 +1643,7 @@ static int smc_close(struct device *dev)
  . Get the current statistics.
  . This may be called with the card open or closed.
  .-------------------------------------------------------------*/
-static struct enet_statistics * smc_query_statistics(struct device *dev) {
+static struct net_driver_stats* smc_query_statistics(struct device *dev) {
        struct smc_local *lp = (struct smc_local *)dev->priv;
 
        return &lp->stats;
index 67ee76b5724ff7919c6b5c30f2fd14c52b12088e..0ddc1c1c1f7eb427e2426318e77b0fd18b09d012 100644 (file)
@@ -1,5 +1,3 @@
-#error "Doesn't run with 2.1.x"
-
 /*
  * Copyright 1996 The Board of Trustees of The Leland Stanford
  * Junior University. All Rights Reserved.
@@ -1623,20 +1621,12 @@ static unsigned char *strip_make_packet(unsigned char *ptr, struct strip *strip_
      */
     if (haddr.c[0] == 0xFF)
     {
-        /*IPaddr a;
-        a.l = strip_info->dev.pa_brdaddr;
-        printk(KERN_INFO "%s: Broadcast packet! Sending to %d.%d.%d.%d\n",
-                strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);*/
-
-        if (!arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev))
-        {
-            /*IPaddr a;
-            a.l = strip_info->dev.pa_brdaddr;
-            printk(KERN_INFO "%s: No ARP cache entry for %d.%d.%d.%d\n",
-                strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);
-            strip_info->tx_dropped++;*/
-            return(NULL);
-        }
+           memcpy(haddr.c, dev->broadcast, sizeof(haddr));
+           if (haddr.c[0] == 0xFF)
+           {
+                   strip_info->tx_dropped++;
+                   return(NULL);
+           }
     }
 
     *ptr++ = '*';
@@ -2294,12 +2284,12 @@ static int strip_set_dev_mac_address(struct device *dev, void *addr)
     return -1;        /* You cannot override a Metricom radio's address */
 }
 
-static struct enet_statistics *strip_get_stats(struct device *dev)
+static struct net_device_stats *strip_get_stats(struct device *dev)
 {
-    static struct enet_statistics stats;
+    static struct net_device_stats stats;
     struct strip *strip_info = (struct strip *)(dev->priv);
 
-    memset(&stats, 0, sizeof(struct enet_statistics));
+    memset(&stats, 0, sizeof(struct net_device_stats));
 
     stats.rx_packets     = strip_info->rx_packets;
     stats.tx_packets     = strip_info->tx_packets;
@@ -2355,12 +2345,6 @@ static int strip_open_low(struct device *dev)
     strip_info->sx_count = 0;
     strip_info->tx_left  = 0;
 
-    /*
-     * Needed because address '0' is special
-     */
-
-    if (dev->pa_addr == 0)
-        dev->pa_addr=ntohl(0xC0A80001);
     dev->tbusy  = 0;
     dev->start  = 1;
 
index c89719f1c76ed38926e28f96b2abb4d70ff6a097..dc663c30e1bbe2b5d55053bafcf4ebeb433f5d23 100644 (file)
@@ -573,7 +573,7 @@ static inline void happy_meal_stop(struct hmeal_gregs *gregs)
 static void happy_meal_get_counters(struct happy_meal *hp,
                                    struct hmeal_bigmacregs *bregs)
 {
-       struct enet_statistics *stats = &hp->enet_stats;
+       struct net_device_stats *stats = &hp->net_stats;
 
        stats->rx_crc_errors += bregs->rcrce_ctr;
        bregs->rcrce_ctr = 0;
@@ -1501,9 +1501,11 @@ static inline void happy_meal_tx(struct happy_meal *hp)
                        break;
                skb = hp->tx_skbs[elem];
                hp->tx_skbs[elem] = NULL;
+               hp->net_stats.tx_bytes+=skb->len;
+               
                dev_kfree_skb(skb, FREE_WRITE);
 
-               hp->enet_stats.tx_packets++;
+               hp->net_stats.tx_packets++;
                elem = NEXT_TX(elem);
        }
        hp->tx_old = elem;
@@ -1525,7 +1527,7 @@ static inline void sun4c_happy_meal_tx(struct happy_meal *hp)
                if(this->tx_flags & TXFLAG_OWN)
                        break;
 
-               hp->enet_stats.tx_packets++;
+               hp->net_stats.tx_packets++;
                elem = NEXT_TX(elem);
        }
        hp->tx_old = elem;
@@ -1562,17 +1564,17 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
                /* Check for errors. */
                if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
                        RXD(("ERR(%08lx)]", flags));
-                       hp->enet_stats.rx_errors++;
+                       hp->net_stats.rx_errors++;
                        if(len < ETH_ZLEN)
-                               hp->enet_stats.rx_length_errors++;
+                               hp->net_stats.rx_length_errors++;
                        if(len & (RXFLAG_OVERFLOW >> 16)) {
-                               hp->enet_stats.rx_over_errors++;
-                               hp->enet_stats.rx_fifo_errors++;
+                               hp->net_stats.rx_over_errors++;
+                               hp->net_stats.rx_fifo_errors++;
                        }
 
                        /* Return it to the Happy meal. */
        drop_it:
-                       hp->enet_stats.rx_dropped++;
+                       hp->net_stats.rx_dropped++;
                        this->rx_addr = (unsigned int) hp->rx_skbs[elem]->data;
                        this->rx_flags =
                                (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
@@ -1630,7 +1632,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
                skb->protocol = eth_type_trans(skb, dev);
                netif_rx(skb);
 
-               hp->enet_stats.rx_packets++;
+               hp->net_stats.rx_packets++;
        next:
                elem = NEXT_RX(elem);
                this = &rxbase[elem];
@@ -1662,20 +1664,20 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev
                /* Check for errors. */
                if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
                        RXD(("ERR(%08lx)]", flags));
-                       hp->enet_stats.rx_errors++;
+                       hp->net_stats.rx_errors++;
                        if(len < ETH_ZLEN)
-                               hp->enet_stats.rx_length_errors++;
+                               hp->net_stats.rx_length_errors++;
                        if(len & (RXFLAG_OVERFLOW >> 16)) {
-                               hp->enet_stats.rx_over_errors++;
-                               hp->enet_stats.rx_fifo_errors++;
+                               hp->net_stats.rx_over_errors++;
+                               hp->net_stats.rx_fifo_errors++;
                        }
 
-                       hp->enet_stats.rx_dropped++;
+                       hp->net_stats.rx_dropped++;
                } else {
                        skb = dev_alloc_skb(len + 2);
                        if(skb == 0) {
                                drops++;
-                               hp->enet_stats.rx_dropped++;
+                               hp->net_stats.rx_dropped++;
                        } else {
                                RXD(("len=%d]", len));
                                skb->dev = hp->dev;
@@ -1684,7 +1686,7 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev
                                eth_copy_and_sum(skb, (thisbuf+2), len, 0);
                                skb->protocol = eth_type_trans(skb, dev);
                                netif_rx(skb);
-                               hp->enet_stats.rx_packets++;
+                               hp->net_stats.rx_packets++;
                        }
                }
                /* Return the buffer to the Happy Meal. */
@@ -1846,7 +1848,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                        return 1;
                } else {
                        printk ("%s: transmit timed out, resetting\n", dev->name);
-                       hp->enet_stats.tx_errors++;
+                       hp->net_stats.tx_errors++;
                        happy_meal_init(hp, 0);
                        dev->tbusy = 0;
                        dev->trans_start = jiffies;
@@ -1854,12 +1856,6 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                }
        }
 
-       if(skb == NULL || skb->len <= 0) {
-               printk("%s: skb is NULL\n", dev->name);
-               dev_tint(dev);
-               return 0;
-       }
-
        if(set_bit(0, (void *) &dev->tbusy) != 0) {
                printk("happy meal: Transmitter access conflict.\n");
                return 1;
@@ -1902,7 +1898,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                        return 1;
                } else {
                        printk ("%s: transmit timed out, resetting\n", dev->name);
-                       hp->enet_stats.tx_errors++;
+                       hp->net_stats.tx_errors++;
                        happy_meal_init(hp, 0);
                        dev->tbusy = 0;
                        dev->trans_start = jiffies;
@@ -1948,12 +1944,12 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *happy_meal_get_stats(struct device *dev)
+static struct net_device_stats *happy_meal_get_stats(struct device *dev)
 {
        struct happy_meal *hp = (struct happy_meal *) dev->priv;
 
        happy_meal_get_counters(hp, hp->bigmacregs);
-       return &hp->enet_stats;
+       return &hp->net_stats;
 }
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
index a9e02312b813969c3e263c078dde53914ea2c09d..687b004ea4859e6ba7206a4ae7df86ee8be43447 100644 (file)
@@ -540,7 +540,7 @@ struct happy_meal {
        enum happy_timer_state    timer_state;    /* State of the auto-neg timer.      */
        unsigned int              timer_ticks;    /* Number of clicks at each state.   */
 
-       struct enet_statistics    enet_stats;     /* Statistical counters              */
+       struct net_device_stats  enet_stats;     /* Statistical counters              */
        struct linux_sbus_device *happy_sbus_dev; /* ;-)                               */
        struct device            *dev;            /* Backpointer                       */
        struct happy_meal        *next_module;
index 20056868338808db4285db4f2cb2b3a05f399ce7..bf40e1c1476d87655d9e86ebc888d5b2a3cdc4d1 100644 (file)
@@ -220,7 +220,7 @@ struct lance_private {
        int rx_new, tx_new;
        int rx_old, tx_old;
     
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        struct Linux_SBus_DMA *ledma; /* If set this points to ledma    */
                                      /* and arch = sun4m               */
 
@@ -786,17 +786,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
                return status;
        }
 
-       if (skb == NULL) {
-               dev_tint (dev);
-               printk ("skb is NULL\n");
-               return 0;
-       }
-
-       if (skb->len <= 0) {
-               printk ("skb len is %d\n", skb->len);
-               return 0;
-       }
-
        /* Block a timer-based transmit from overlapping. */
        if (set_bit (0, (void *) &dev->tbusy) != 0) {
                printk ("Transmitter access conflict.\n");
@@ -813,6 +802,9 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
        }
 
        len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+       
+       lp->stats.tx_bytes+=len;
+       
        entry = lp->tx_new & TX_RING_MOD_MASK;
        ib->btx_ring [entry].length = (-len) | 0xf000;
        ib->btx_ring [entry].misc = 0;
@@ -820,6 +812,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
        memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
 
        /* Clear the slack of the packet, do I need this? */
+       /* For a firewall its a good idea - AC */
        if (len != skblen)
                memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
     
@@ -845,7 +838,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
        return status;
 }
 
-static struct enet_statistics *lance_get_stats (struct device *dev)
+static struct net_device_stats *lance_get_stats (struct device *dev)
 {
        struct lance_private *lp = (struct lance_private *) dev->priv;
 
index 318855bf9cefaf27671df0ca1ce028e70f735961..c74666b78a1267089817c353565bfc7c6ea66cf3 100644 (file)
@@ -281,31 +281,31 @@ static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
 
        if(qe_status & CREG_STAT_EDEFER) {
                printk("%s: Excessive transmit defers.\n", dev->name);
-               qep->enet_stats.tx_errors++;
+               qep->net_stats.tx_errors++;
        }
 
        if(qe_status & CREG_STAT_CLOSS) {
                printk("%s: Carrier lost, link down?\n", dev->name);
-               qep->enet_stats.tx_errors++;
-               qep->enet_stats.tx_carrier_errors++;
+               qep->net_stats.tx_errors++;
+               qep->net_stats.tx_carrier_errors++;
        }
 
        if(qe_status & CREG_STAT_ERETRIES) {
                printk("%s: Excessive transmit retries (more than 16).\n", dev->name);
-               qep->enet_stats.tx_errors++;
+               qep->net_stats.tx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_LCOLL) {
                printk("%s: Late transmit collision.\n", dev->name);
-               qep->enet_stats.tx_errors++;
-               qep->enet_stats.collisions++;
+               qep->net_stats.tx_errors++;
+               qep->net_stats.collisions++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_FUFLOW) {
                printk("%s: Transmit fifo underflow, driver bug.\n", dev->name);
-               qep->enet_stats.tx_errors++;
+               qep->net_stats.tx_errors++;
                mace_hwbug_workaround = 1;
        }
 
@@ -318,104 +318,104 @@ static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
        }
 
        if(qe_status & CREG_STAT_CCOFLOW) {
-               qep->enet_stats.tx_errors += 256;
-               qep->enet_stats.collisions += 256;
+               qep->net_stats.tx_errors += 256;
+               qep->net_stats.collisions += 256;
        }
 
        if(qe_status & CREG_STAT_TXDERROR) {
                printk("%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
-               qep->enet_stats.tx_errors++;
-               qep->enet_stats.tx_aborted_errors++;
+               qep->net_stats.tx_errors++;
+               qep->net_stats.tx_aborted_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_TXLERR) {
                printk("%s: Transmit late error.\n", dev->name);
-               qep->enet_stats.tx_errors++;
+               qep->net_stats.tx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_TXPERR) {
                printk("%s: Transmit DMA parity error.\n", dev->name);
-               qep->enet_stats.tx_errors++;
-               qep->enet_stats.tx_aborted_errors++;
+               qep->net_stats.tx_errors++;
+               qep->net_stats.tx_aborted_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_TXSERR) {
                printk("%s: Transmit DMA sbus error ack.\n", dev->name);
-               qep->enet_stats.tx_errors++;
-               qep->enet_stats.tx_aborted_errors++;
+               qep->net_stats.tx_errors++;
+               qep->net_stats.tx_aborted_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_RCCOFLOW) {
-               qep->enet_stats.rx_errors += 256;
-               qep->enet_stats.collisions += 256;
+               qep->net_stats.rx_errors += 256;
+               qep->net_stats.collisions += 256;
        }
 
        if(qe_status & CREG_STAT_RUOFLOW) {
-               qep->enet_stats.rx_errors += 256;
-               qep->enet_stats.rx_over_errors += 256;
+               qep->net_stats.rx_errors += 256;
+               qep->net_stats.rx_over_errors += 256;
        }
 
        if(qe_status & CREG_STAT_MCOFLOW) {
-               qep->enet_stats.rx_errors += 256;
-               qep->enet_stats.rx_missed_errors += 256;
+               qep->net_stats.rx_errors += 256;
+               qep->net_stats.rx_missed_errors += 256;
        }
 
        if(qe_status & CREG_STAT_RXFOFLOW) {
                printk("%s: Receive fifo overflow.\n", dev->name);
-               qep->enet_stats.rx_errors++;
-               qep->enet_stats.rx_over_errors++;
+               qep->net_stats.rx_errors++;
+               qep->net_stats.rx_over_errors++;
        }
 
        if(qe_status & CREG_STAT_RLCOLL) {
                printk("%s: Late receive collision.\n", dev->name);
-               qep->enet_stats.rx_errors++;
-               qep->enet_stats.collisions++;
+               qep->net_stats.rx_errors++;
+               qep->net_stats.collisions++;
        }
 
        if(qe_status & CREG_STAT_FCOFLOW) {
-               qep->enet_stats.rx_errors += 256;
-               qep->enet_stats.rx_frame_errors += 256;
+               qep->net_stats.rx_errors += 256;
+               qep->net_stats.rx_frame_errors += 256;
        }
 
        if(qe_status & CREG_STAT_CECOFLOW) {
-               qep->enet_stats.rx_errors += 256;
-               qep->enet_stats.rx_crc_errors += 256;
+               qep->net_stats.rx_errors += 256;
+               qep->net_stats.rx_crc_errors += 256;
        }
 
        if(qe_status & CREG_STAT_RXDROP) {
                printk("%s: Receive packet dropped.\n", dev->name);
-               qep->enet_stats.rx_errors++;
-               qep->enet_stats.rx_dropped++;
-               qep->enet_stats.rx_missed_errors++;
+               qep->net_stats.rx_errors++;
+               qep->net_stats.rx_dropped++;
+               qep->net_stats.rx_missed_errors++;
        }
 
        if(qe_status & CREG_STAT_RXSMALL) {
                printk("%s: Receive buffer too small, driver bug.\n", dev->name);
-               qep->enet_stats.rx_errors++;
-               qep->enet_stats.rx_length_errors++;
+               qep->net_stats.rx_errors++;
+               qep->net_stats.rx_length_errors++;
        }
 
        if(qe_status & CREG_STAT_RXLERR) {
                printk("%s: Receive late error.\n", dev->name);
-               qep->enet_stats.rx_errors++;
+               qep->net_stats.rx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_RXPERR) {
                printk("%s: Receive DMA parity error.\n", dev->name);
-               qep->enet_stats.rx_errors++;
-               qep->enet_stats.rx_missed_errors++;
+               qep->net_stats.rx_errors++;
+               qep->net_stats.rx_missed_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_RXSERR) {
                printk("%s: Receive DMA sbus error ack.\n", dev->name);
-               qep->enet_stats.rx_errors++;
-               qep->enet_stats.rx_missed_errors++;
+               qep->net_stats.rx_errors++;
+               qep->net_stats.rx_missed_errors++;
                mace_hwbug_workaround = 1;
        }
 
@@ -439,9 +439,10 @@ static inline void qe_tx(struct sunqe *qep)
                        break;
                skb = qep->tx_skbs[elem];
                qep->tx_skbs[elem] = NULL;
+               qep->net_stats.tx_bytes+=skb->len;
                dev_kfree_skb(skb, FREE_WRITE);
 
-               qep->enet_stats.tx_packets++;
+               qep->net_stats.tx_packets++;
                elem = NEXT_TX(elem);
        }
        qep->tx_old = elem;
@@ -457,7 +458,7 @@ static inline void sun4c_qe_tx(struct sunqe *qep)
                this = &txbase[elem];
                if(this->tx_flags & TXD_OWN)
                        break;
-               qep->enet_stats.tx_packets++;
+               qep->net_stats.tx_packets++;
                elem = NEXT_TX(elem);
        }
        qep->tx_old = elem;
@@ -480,12 +481,12 @@ static inline void qe_rx(struct sunqe *qep)
 
                /* Check for errors. */
                if(len < ETH_ZLEN) {
-                       qep->enet_stats.rx_errors++;
-                       qep->enet_stats.rx_length_errors++;
+                       qep->net_stats.rx_errors++;
+                       qep->net_stats.rx_length_errors++;
 
        drop_it:
                        /* Return it to the QE. */
-                       qep->enet_stats.rx_dropped++;
+                       qep->net_stats.rx_dropped++;
                        this->rx_addr = (unsigned int) qep->rx_skbs[elem]->data;
                        this->rx_flags =
                                (RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH));
@@ -536,7 +537,7 @@ static inline void qe_rx(struct sunqe *qep)
                /* No checksums are done by this card ;-( */
                skb->protocol = eth_type_trans(skb, qep->dev);
                netif_rx(skb);
-               qep->enet_stats.rx_packets++;
+               qep->net_stats.rx_packets++;
        next:
                elem = NEXT_RX(elem);
                this = &rxbase[elem];
@@ -565,14 +566,14 @@ static inline void sun4c_qe_rx(struct sunqe *qep)
 
                /* Check for errors. */
                if(len < ETH_ZLEN) {
-                       qep->enet_stats.rx_errors++;
-                       qep->enet_stats.rx_length_errors++;
-                       qep->enet_stats.rx_dropped++;
+                       qep->net_stats.rx_errors++;
+                       qep->net_stats.rx_length_errors++;
+                       qep->net_stats.rx_dropped++;
                } else {
                        skb = dev_alloc_skb(len + 2);
                        if(skb == 0) {
                                drops++;
-                               qep->enet_stats.rx_dropped++;
+                               qep->net_stats.rx_dropped++;
                        } else {
                                skb->dev = qep->dev;
                                skb_reserve(skb, 2);
@@ -581,7 +582,7 @@ static inline void sun4c_qe_rx(struct sunqe *qep)
                                                 len, 0);
                                skb->protocol = eth_type_trans(skb, qep->dev);
                                netif_rx(skb);
-                               qep->enet_stats.rx_packets++;
+                               qep->net_stats.rx_packets++;
                        }
                }
                end_rxd->rx_addr = (unsigned int) this_qbuf;
@@ -710,12 +711,6 @@ static int qe_start_xmit(struct sk_buff *skb, struct device *dev)
        if(dev->tbusy)
                return 1;
 
-       if(skb == NULL || skb->len <= 0) {
-               printk("%s: skb is NULL\n", dev->name);
-               dev_tint(dev);
-               return 0;
-       }
-
        if(set_bit(0, (void *) &dev->tbusy) != 0) {
                printk("%s: Transmitter access conflict.\n", dev->name);
                return 1;
@@ -756,12 +751,6 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
        if(dev->tbusy)
                return 1;
 
-       if(skb == NULL || skb->len <= 0) {
-               printk("%s: skb is NULL\n", dev->name);
-               dev_tint(dev);
-               return 0;
-       }
-
        if(set_bit(0, (void *) &dev->tbusy) != 0) {
                printk("%s: Transmitter access conflict.\n", dev->name);
                return 1;
@@ -788,6 +777,8 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
        /* Get it going. */
        qep->qcregs->ctrl = CREG_CTRL_TWAKEUP;
 
+       qep->stats.tx_bytes+=skb->len;
+       
        dev_kfree_skb(skb, FREE_WRITE);
 
        if(SUN4C_TX_BUFFS_AVAIL(qep))
@@ -796,11 +787,11 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *qe_get_stats(struct device *dev)
+static struct net_device_stats *qe_get_stats(struct device *dev)
 {
        struct sunqe *qep = (struct sunqe *) dev->priv;
 
-       return &qep->enet_stats;
+       return &qep->net_stats;
 }
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
index 55ad6dd309d6e89a041adcd4239b09eeee077c04..d6b6855d0a088c87cdae5218081a63ca4be4b6aa 100644 (file)
@@ -360,7 +360,7 @@ struct sunqe {
 
        struct sunqec             *parent;
 
-       struct enet_statistics     enet_stats;   /* Statistical counters               */
+       struct net_device_stats   enet_stats;   /* Statistical counters               */
        struct linux_sbus_device  *qe_sbusdev;   /* QE's SBUS device struct            */
        struct device             *dev;          /* QE's netdevice struct              */
        int                        channel;      /* Who am I?                          */
index e8b4f30dbdbbe340dd40b95bb758d0aaffd60a38..1b7a1abad3b3d95f2d180949eb770a7774cf3543 100644 (file)
@@ -15,6 +15,9 @@
 
        Subscribe to linux-tulip@cesdis.gsfc.nasa.gov and linux-tulip-bugs@cesdis.gsfc.nasa.gov
        for late breaking news and exciting develovements.
+       
+       This has Baldur Norddahl's one liner fix for the AC/AE boards. If it
+       stops working please change TINTR_ENABLE to 0xFFFFFFFF
 */
 
 static char *version =
@@ -240,7 +243,7 @@ enum tulip_offsets {
 #define        TCMOD_AUTO                      (TCMOD_SW100TP|TCMOD_TH128|TCMOD_10TP)
 
 /* description of CSR7 interrupt mask register */
-#define        TINTR_ENABLE            0xFFFFFFFF
+#define        TINTR_ENABLE            0xFFFFBBFF
 #define        TINTR_DISABLE           0x00000000
 
 /* description of CSR11 G.P. timer (21041/21140) register */
@@ -334,7 +337,7 @@ struct tulip_private {
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
        char rx_buffs[RX_RING_SIZE][PKT_BUF_SZ];
        /* temporary Rx buffers. */
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        int setup_frame[48];    /* Pseudo-Tx frame to init address table. */
        void (*port_select)(struct device *dev);
        int (*port_fail)(struct device *dev);
@@ -371,7 +374,7 @@ static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
 static int tulip_rx(struct device *dev);
 static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
-static struct enet_statistics *tulip_get_stats(struct device *dev);
+static struct net_device_stats *tulip_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 #define        generic21140_fail       NULL
@@ -881,6 +884,7 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
        } else {
                daddr = virt_to_bus(skb->data);
                len = skb->len;
+               tp->stats.tx_bytes+=len;
        }
        tp->tx_skbuff[entry] = skb;
        tp->tx_ring[entry].length = len |
@@ -1120,8 +1124,7 @@ tulip_config(struct device *dev, struct ifmap *map)
        return(0);
 }
 
-static struct enet_statistics *
-tulip_get_stats(struct device *dev)
+static struct net_device_stats *tulip_get_stats(struct device *dev)
 {
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        /*      short ioaddr = dev->base_addr;*/
index 30cea81967e0d0eb9353d71154e5f12327e49675..b01fa7ca7759527c267baf4669e43424ae8c9bef 100644 (file)
@@ -120,13 +120,13 @@ void print_ip(struct iphdr *ip)
 
 static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
 {
-       struct enet_statistics *stats;          /* This device's statistics */
+       struct net_device_stats *stats;         /* This device's statistics */
        struct rtable *rt;                      /* Route to the other host */
        struct device *tdev;                    /* Device to other host */
        struct iphdr  *iph;                     /* Our new IP header */
        int    max_headroom;                    /* The extra header space needed */
 
-       stats = (struct enet_statistics *)dev->priv;
+       stats = (struct net_device_stats *)dev->priv;
   
        /*
         *  First things first.  Look up the destination address in the 
@@ -194,6 +194,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
        iph->id                 =       htons(ip_id_count++);   /* Race condition here? */
        ip_send_check(iph);
 
+       stats->tx_bytes+=skb->len;
+       
        ip_send(skb);
 
        /* Record statistics and return */
@@ -201,9 +203,9 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
        return 0;
 }
 
-static struct enet_statistics *tunnel_get_stats(struct device *dev)
+static struct net_device_stats *tunnel_get_stats(struct device *dev)
 {
-       return((struct enet_statistics*) dev->priv);
+       return((struct net_device_stats*) dev->priv);
 }
 
 /*
@@ -226,10 +228,10 @@ int tunnel_init(struct device *dev)
        dev->stop               = tunnel_close;
        dev->hard_start_xmit    = tunnel_xmit;
        dev->get_stats          = tunnel_get_stats;
-       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+       dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
        if (dev->priv == NULL)
                return -ENOMEM;
-       memset(dev->priv, 0, sizeof(struct enet_statistics));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
 
        /* Initialize the tunnel device structure */
        
@@ -302,7 +304,7 @@ int init_module(void)
 void cleanup_module(void)
 {
        unregister_netdev(&dev_tunnel);
-       kfree_s(dev_tunnel.priv,sizeof(struct enet_statistics));
+       kfree_s(dev_tunnel.priv,sizeof(struct net_device_stats));
        dev_tunnel.priv=NULL;
 }
 #endif /* MODULE */
index d3bf6ab2aec63f4cf32e3daab54d88afcf58fce5..bae60aeef0c4f6fd5bf300d853d7a494fd51a9aa 100644 (file)
@@ -367,7 +367,7 @@ static const char   *version        = "wavelan.c : v12 (wireless extensions) 1/12/96\n";
 
 /* Shortcuts */
 typedef struct device          device;
-typedef struct enet_statistics en_stats;
+typedef struct net_device_stats        en_stats;
 typedef struct iw_statistics   iw_stats;
 typedef struct iw_quality      iw_qual;
 typedef struct iw_freq         iw_freq;
diff --git a/drivers/net/wic.c b/drivers/net/wic.c
deleted file mode 100644 (file)
index dce1bb3..0000000
+++ /dev/null
@@ -1,1440 +0,0 @@
-/* $Id: wic.c,v 1.0 1995/02/11 10:26:05 hayes Exp $ */
-/* WIC: A parallel port "network" driver for Linux. */
-/* based on the plip network driver */
-/* Modified for Linux 1.3.x by Alan Cox <Alan.Cox@linux.org> */
-
-char *version = "NET3 WIC version 0.9 hayes@netplumbing.com";
-
-/*
-  Sources:
-       Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>
-       "parallel.asm" parallel port packet driver and from the plip.c
-       parallel networking linux driver from the 1.2.13 Linux
-       distribution.
-
-  The packet is encapsulated as if it were ethernet.
-
-*/
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/if_ether.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/lp.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_wic.h>
-
-#include <linux/tqueue.h>
-#include <linux/ioport.h>
-#include <asm/bitops.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-#include <linux/string.h>
-
-#define NET_DEBUG 1
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-unsigned int net_debug = NET_DEBUG;
-
-/* Connection time out = WIC_TRIGGER_WAIT * WIC_DELAY_UNIT usec */
-#define WIC_TRIGGER_WAIT        500
-
-/* Nibble time out = WIC_NIBBLE_WAIT * WIC_DELAY_UNIT usec */
-#define WIC_NIBBLE_WAIT        3000
-
-#define PAR_DATA(dev)          ((dev)->base_addr+0)
-#define PAR_STATUS(dev)                ((dev)->base_addr+1)
-#define PAR_CONTROL(dev)       ((dev)->base_addr+2)
-
-/* Bottom halfs */
-void wic_kick_bh(struct device *dev);
-void wic_bh(struct device *dev);
-
-/* Interrupt handler */
-void wic_interrupt(int irq, void *dev_ptr, struct pt_regs *regs);
-
-/* Functions for DEV methods */
-int wic_rebuild_header(struct sk_buff *skb);
-int wic_tx_packet(struct sk_buff *skb, struct device *dev);
-int wic_open(struct device *dev);
-int wic_close(struct device *dev);
-struct enet_statistics *wic_get_stats(struct device *dev);
-int wic_config(struct device *dev, struct ifmap *map);
-int wic_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-int send_cmd(struct device *dev, unsigned char *cmd, char len);
-int recv_cmd_resp(struct device *dev, unsigned char *cmd);
-int send_byte(struct device *dev, unsigned char c);
-int get_byte(struct device *dev, unsigned char *c);
-int ack_resp(struct device *dev);
-int check_bfr(struct device *dev);
-void wic_reset(struct device *dev);
-void wic_set_multicast_list(struct device *dev);
-
-#define LOOPCNT 30000  
-unsigned char tog = 3;
-unsigned char save = 0;
-
-enum wic_connection_state {
-       WIC_CN_NONE=0,
-       WIC_CN_RECEIVE,
-       WIC_CN_SEND,
-       WIC_CN_CLOSING,
-       WIC_CN_ERROR
-};
-
-enum wic_packet_state {
-       WIC_PK_DONE=0,
-       WIC_PK_TRIGGER,
-       WIC_PK_LENGTH_LSB,
-       WIC_PK_LENGTH_MSB,
-       WIC_PK_DATA,
-       WIC_PK_CHECKSUM
-};
-
-enum wic_nibble_state {
-       WIC_NB_BEGIN,
-       WIC_NB_1,
-       WIC_NB_2,
-};
-
-struct wic_local {
-       enum wic_packet_state state;
-       enum wic_nibble_state nibble;
-       union {
-               struct {
-#if defined(__LITTLE_ENDIAN)
-                       unsigned char lsb;
-                       unsigned char msb;
-#elif defined(__BIG_ENDIAN)
-                       unsigned char msb;
-                       unsigned char lsb;
-#else
-#error "Please fix the endianness defines in <asm/byteorder.h>"
-#endif                                         
-               } b;
-               unsigned short h;
-       } length;
-       unsigned short byte;
-       unsigned char  checksum;
-       unsigned char  data;
-       struct sk_buff *skb;
-};
-
-struct net_local {
-       struct enet_statistics enet_stats;
-       struct tq_struct immediate;
-       struct tq_struct deferred;
-       struct wic_local snd_data;
-       struct wic_local rcv_data;
-       unsigned long  trigger;
-       unsigned long  nibble;
-       enum wic_connection_state connection;
-       unsigned short timeout_count;
-       char is_deferred;
-       int (*orig_rebuild_header)(struct sk_buff *skb);
-};
-
-/* Entry point of WIC driver.
-   Probe the hardware, and register/initialize the driver. */
-
-int wic_init(struct device *dev)
-{
-       struct net_local *nl;
-       struct wicconf wc;
-       int i;
-
-       /* Check region before the probe */
-       if (check_region(PAR_DATA(dev), 3) < 0)
-               return -ENODEV;
-       
-       /* Check that there is something at base_addr. */
-       outb(0, PAR_DATA(dev));
-       udelay(1000);
-       if (inb(PAR_DATA(dev)) != 0)
-               return -ENODEV;
-
-       printk("%s\n",version);
-       printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
-       if (dev->irq) {
-               printk("using assigned IRQ %d.\n", dev->irq);
-       } else {
-               int irq = 0;
-#ifdef MODULE
-               /* dev->irq==0 means autoprobe, but we don't try to do so
-                  with module.  We can change it by ifconfig */
-#else
-               unsigned int irqs = probe_irq_on();
-
-               outb(0x00, PAR_CONTROL(dev));
-               udelay(1000);
-               udelay(1000);
-               irq = probe_irq_off(irqs);
-#endif
-               if (irq > 0) {
-                       dev->irq = irq;
-                       printk("using probed IRQ %d.\n", dev->irq);
-               } else
-                       printk("failed to detect IRQ(%d) --"
-                              " Please set IRQ by ifconfig.\n", irq);
-       }
-
-       request_region(PAR_DATA(dev), 3, dev->name);
-
-       /* Fill in the generic fields of the device structure. */
-       ether_setup(dev);
-
-       /* Then, override parts of it */
-       dev->hard_start_xmit    = wic_tx_packet;
-       dev->open               = wic_open;
-       dev->stop               = wic_close;
-       dev->get_stats          = wic_get_stats;
-       dev->set_config         = wic_config;
-       dev->do_ioctl           = wic_ioctl;
-       dev->mtu                = 1514;
-       dev->set_multicast_list = wic_set_multicast_list;
-       dev->flags              = IFF_BROADCAST | IFF_RUNNING | IFF_NOTRAILERS;
-
-       /* get the MAC address from the controller */
-       wc.len = 1;
-       wc.pcmd = WIC_GETNET;
-       check_bfr(dev);
-       send_cmd(dev, (unsigned char *)&wc, 1);
-       wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-       while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
-               wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-       
-       printk("%s:MAC address: ",dev->name);   
-       for (i=0; i < ETH_ALEN ; i++) {
-               dev->dev_addr[i] = wc.data[i];
-               printk("%2x ",dev->dev_addr[i]);
-       }
-       printk("\n");
-
-       /* Set the private structure */
-       dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
-       if (dev->priv == NULL)
-               return EAGAIN;
-       memset(dev->priv, 0, sizeof(struct net_local));
-       nl = (struct net_local *) dev->priv;
-
-       nl->orig_rebuild_header = dev->rebuild_header;
-       dev->rebuild_header     = wic_rebuild_header;
-
-       /* Initialize constants */
-       nl->trigger     = WIC_TRIGGER_WAIT;
-       nl->nibble      = WIC_NIBBLE_WAIT;
-
-       /* Initialize task queue structures */
-       nl->immediate.next = NULL;
-       nl->immediate.sync = 0;
-       nl->immediate.routine = (void *)(void *)wic_bh;
-       nl->immediate.data = dev;
-
-       nl->deferred.next = NULL;
-       nl->deferred.sync = 0;
-       nl->deferred.routine = (void *)(void *)wic_kick_bh;
-       nl->deferred.data = dev;
-
-       return 0;
-}
-
-/* Bottom half handler for the delayed request.
-   This routine is kicked by do_timer().
-   Request `wic_bh' to be invoked. */
-void wic_kick_bh(struct device *dev)
-{
-       struct net_local *nl = (struct net_local *)dev->priv;
-
-       if (nl->is_deferred) {
-               queue_task(&nl->immediate, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
-       }
-}
-
-/* Forward declarations of internal routines */
-int wic_none(struct device *, struct net_local *,
-                    struct wic_local *, struct wic_local *);
-int wic_receive_packet(struct device *, struct net_local *,
-                              struct wic_local *, struct wic_local *);
-int wic_send_packet(struct device *, struct net_local *,
-                           struct wic_local *, struct wic_local *);
-int wic_connection_close(struct device *, struct net_local *,
-                                struct wic_local *, struct wic_local *);
-int wic_error(struct device *, struct net_local *,
-                     struct wic_local *, struct wic_local *);
-int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
-                                struct wic_local *snd,
-                                struct wic_local *rcv,
-                                int error);
-
-#define OK        0
-#define TIMEOUT   1
-#define ERROR     2
-
-typedef int (*wic_func)(struct device *dev, struct net_local *nl,
-                        struct wic_local *snd, struct wic_local *rcv);
-
-wic_func connection_state_table[] =
-{
-       wic_none,
-       wic_receive_packet,
-       wic_send_packet,
-       wic_connection_close,
-       wic_error
-};
-
-void wic_set_multicast_list(struct device *dev)
-{
-       struct wicconf wc;
-       struct wic_net *wn;
-       
-       disable_irq(dev->irq);
-       save &= 0xef; /* disable */
-       outb(save, PAR_CONTROL(dev));
-       
-       wc.len = 1;
-       wc.pcmd = WIC_GETNET;
-       check_bfr(dev);
-       tog = 3;
-       send_cmd(dev, (unsigned char *)&wc, 1);
-       wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-       while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
-               wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-       wn = (struct wic_net *)&wc.data;
-       if(dev->flags&IFF_PROMISC)
-       {
-               /* promiscuous mode */
-               wn->mode |= (NET_MODE_ME | NET_MODE_BCAST | 
-                       NET_MODE_MCAST | NET_MODE_PROM);
-               printk("%s: Setting promiscuous mode\n", dev->name);
-       }
-       else if((dev->flags&IFF_ALLMULTI) || dev->mc_count)
-       {
-               wn->mode &= ~NET_MODE_PROM;
-               wn->mode |= (NET_MODE_MCAST | NET_MODE_ME | NET_MODE_BCAST);
-       }
-       else
-       {
-               wn->mode &= ~(NET_MODE_PROM | NET_MODE_MCAST);
-               wn->mode |= (NET_MODE_ME | NET_MODE_BCAST);
-       }
-       wc.len = 23;
-       wc.pcmd = WIC_SETNET;
-       check_bfr(dev);
-       tog = 3;
-       send_cmd(dev, (unsigned char *)&wc, wc.len);
-
-       save |= 0x10; /* enable */
-       outb(save, PAR_CONTROL(dev));
-       enable_irq(dev->irq);
-       return;
-}
-
-/* Bottom half handler of WIC. */
-void wic_bh(struct device *dev)
-{
-       struct net_local *nl = (struct net_local *)dev->priv;
-       struct wic_local *snd = &nl->snd_data;
-       struct wic_local *rcv = &nl->rcv_data;
-       wic_func f;
-       int r;
-
-       nl->is_deferred = 0;
-       f = connection_state_table[nl->connection];
-       if ((r = (*f)(dev, nl, snd, rcv)) != OK
-           && (r = wic_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
-               nl->is_deferred = 1;
-               queue_task(&nl->deferred, &tq_timer);
-       }
-}
-
-int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
-                     struct wic_local *snd, struct wic_local *rcv,
-                     int error)
-{
-       unsigned char c0;
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       if (nl->connection == WIC_CN_SEND) {
-
-               if (error != ERROR) { /* Timeout */
-                       nl->timeout_count++;
-                       if ((snd->state == WIC_PK_TRIGGER
-                            && nl->timeout_count <= 10)
-                           || nl->timeout_count <= 3) {
-                               restore_flags(flags);
-                               /* Try again later */
-                               return TIMEOUT;
-                       }
-                       c0 = inb(PAR_STATUS(dev));
-                       printk("%s: transmit timeout(%d,%02x)\n",
-                              dev->name, snd->state, c0);
-               }
-               nl->enet_stats.tx_errors++;
-               nl->enet_stats.tx_aborted_errors++;
-       } else if (nl->connection == WIC_CN_RECEIVE) {
-               if (rcv->state == WIC_PK_TRIGGER) {
-                       /* Transmission was interrupted. */
-                       restore_flags(flags);
-                       return OK;
-               }
-               if (error != ERROR) { /* Timeout */
-                       if (++nl->timeout_count <= 3) {
-                               restore_flags(flags);
-                               /* Try again later */
-                               return TIMEOUT;
-                       }
-                       c0 = inb(PAR_STATUS(dev));
-                       printk("%s: receive timeout(%d,%02x)\n",
-                              dev->name, rcv->state, c0);
-               }
-               nl->enet_stats.rx_dropped++;
-       }
-       rcv->state = WIC_PK_DONE;
-       if (rcv->skb) {
-               kfree_skb(rcv->skb, FREE_READ);
-               rcv->skb = NULL;
-       }
-       snd->state = WIC_PK_DONE;
-       if (snd->skb) {
-               dev_kfree_skb(snd->skb, FREE_WRITE);
-               snd->skb = NULL;
-       }
-#if (0)
-       disable_irq(dev->irq);
-       save &= 0xef; /* disable */
-       outb(save, PAR_CONTROL(dev));
-       dev->tbusy = 1;
-       outb(0x00, PAR_DATA(dev));
-#endif /* (0) */
-       nl->connection = WIC_CN_ERROR;
-       restore_flags(flags);
-
-       return TIMEOUT;
-}
-
-int wic_none(struct device *dev, struct net_local *nl,
-         struct wic_local *snd, struct wic_local *rcv)
-{
-       return OK;
-}
-
-/* WIC_RECEIVE --- receive a byte(two nibbles)
-   Returns OK on success, TIMEOUT on timeout */
-extern inline int wic_receive(unsigned short nibble_timeout, 
-       unsigned short status_addr, enum wic_nibble_state *ns_p, unsigned char *data_p)
-{
-       unsigned int cx;
-
-       cx = LOOPCNT;
-       while ((inb(status_addr) & 0x08) != ((tog<<3) & 0x08)) {
-               if (--cx == 0) {
-                       return TIMEOUT;
-               }
-       }
-       *data_p = inb(status_addr-1);
-       tog ^= 0x01;
-       outb(tog| save, status_addr+1);
-       return OK;
-}
-
-/* WIC_RECEIVE_PACKET --- receive a packet */
-
-int wic_receive_packet(struct device *dev, struct net_local *nl,
-                   struct wic_local *snd, struct wic_local *rcv)
-{
-       unsigned short status_addr = PAR_STATUS(dev);
-       unsigned short nibble_timeout = nl->nibble;
-       unsigned char *lbuf;
-       unsigned char junk;
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       switch (rcv->state) {
-       case WIC_PK_TRIGGER:
-               disable_irq(dev->irq);
-               save &= 0xef; /* disable */
-               outb(save, PAR_CONTROL(dev));
-               
-               dev->interrupt = 0;
-
-               tog &= 0xfe;
-               ack_resp(dev);
-               if (net_debug > 2)
-                       printk("%s: receive start\n", dev->name);
-               rcv->state = WIC_PK_LENGTH_LSB;
-               rcv->nibble = WIC_NB_BEGIN;
-
-       case WIC_PK_LENGTH_LSB:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_LENGTH_LSB\n", dev->name);
-               if (snd->state != WIC_PK_DONE) {
-                       if (wic_receive(nl->trigger, status_addr,
-                                        &rcv->nibble, &rcv->length.b.lsb)) {
-                               /* collision, here dev->tbusy == 1 */
-                               rcv->state = WIC_PK_DONE;
-                               nl->is_deferred = 1;
-                               nl->connection = WIC_CN_SEND;
-                               restore_flags(flags);
-                               queue_task(&nl->deferred, &tq_timer);
-                               save |= 0x10; /* enable */
-                               outb(save, PAR_CONTROL(dev));
-                               enable_irq(dev->irq);
-                               return OK;
-                       }
-               } else {
-                       if (wic_receive(nibble_timeout, status_addr,
-                                        &rcv->nibble, &rcv->length.b.lsb)) {
-                               restore_flags(flags);
-                               return TIMEOUT;
-                       }
-               }
-               rcv->state = WIC_PK_LENGTH_MSB;
-
-       case WIC_PK_LENGTH_MSB:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
-               if (wic_receive(nibble_timeout, status_addr,
-                                &rcv->nibble, &rcv->length.b.msb)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-               if (rcv->length.h > dev->mtu || rcv->length.h < 8) {
-                       printk("%s: bad packet size %d.\n", dev->name, rcv->length.h);
-                       restore_flags(flags);
-                       return ERROR;
-               }
-               /* Malloc up new buffer. */
-               rcv->skb = dev_alloc_skb(rcv->length.h);
-               if (rcv->skb == NULL) {
-                       printk("%s: Memory squeeze.\n", dev->name);
-                       restore_flags(flags);
-                       return ERROR;
-               }
-               skb_put(rcv->skb,rcv->length.h);
-               rcv->skb->dev = dev;
-               
-               rcv->state = WIC_PK_DATA;
-               rcv->byte = 0;
-               rcv->checksum = 0;
-               
-               /* sequence numbers */
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_SEQ\n", dev->name);
-               if (wic_receive(nibble_timeout, status_addr,
-                                &rcv->nibble, &junk)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-               if (wic_receive(nibble_timeout, status_addr,
-                                &rcv->nibble, &junk)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-
-       case WIC_PK_DATA:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_DATA: length %i\n", dev->name, 
-                               rcv->length.h);
-               lbuf = rcv->skb->data;
-               do {
-                       if (wic_receive(nibble_timeout, status_addr, 
-                                        &rcv->nibble, &lbuf[rcv->byte])) {
-                               restore_flags(flags);
-                               return TIMEOUT;
-                       }
-               } while (++rcv->byte < (rcv->length.h - 4));
-
-               /* receive pad byte */
-               if (rcv->length.h & 0x01)
-                       wic_receive(nibble_timeout, status_addr, 
-                                        &rcv->nibble, &lbuf[rcv->byte]);
-               
-               do {
-                       rcv->checksum += lbuf[--rcv->byte];
-               } while (rcv->byte);
-
-               rcv->state = WIC_PK_CHECKSUM;
-
-       case WIC_PK_CHECKSUM:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_CHECKSUM\n", dev->name);
-               if (wic_receive(nibble_timeout, status_addr,
-                                &rcv->nibble, &junk)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-               outb(0, PAR_DATA(dev));
-               rcv->state = WIC_PK_DONE;
-
-       case WIC_PK_DONE:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_DONE\n", dev->name);
-               /* Inform the upper layer for the arrival of a packet. */
-               netif_rx(rcv->skb);
-               nl->enet_stats.rx_packets++;
-               rcv->skb = NULL;
-               if (net_debug > 2)
-                       printk("%s: receive end\n", dev->name);
-
-               /* Close the connection. */
-               if (snd->state != WIC_PK_DONE) {
-                       nl->connection = WIC_CN_SEND;
-                       restore_flags(flags);
-                       queue_task(&nl->immediate, &tq_immediate);
-                       save |= 0x10; /* enable */
-                       outb(save, PAR_CONTROL(dev));
-                       enable_irq(dev->irq);
-                       return OK;
-               } else {
-                       nl->connection = WIC_CN_NONE;
-                       restore_flags(flags);
-                       save |= 0x10; /* enable */
-                       outb(save, PAR_CONTROL(dev));
-                       enable_irq(dev->irq);
-                       return OK;
-               }
-       }
-       restore_flags(flags);
-       return OK;
-}
-
-/* WIC_SEND --- send a byte (two nibbles) 
-   Returns OK on success, TIMEOUT when timeout    */
-extern inline int wic_send(unsigned short nibble_timeout, 
-       unsigned short data_addr, enum wic_nibble_state *ns_p, 
-       unsigned char data)
-{
-       unsigned int cx;
-
-       cx = LOOPCNT;
-       while ((inb(data_addr+1) & 0x80) == ((tog<<7) & 0x80)) {
-               if (--cx == 0) {
-                       return -TIMEOUT;
-               }
-       }
-       outb(data, data_addr);
-       outb(tog | save, data_addr+2);
-       tog ^= 0x01;
-       return OK;
-}
-
-/* WIC_SEND_PACKET --- send a packet */
-int wic_send_packet(struct device *dev, struct net_local *nl,
-                struct wic_local *snd, struct wic_local *rcv)
-{
-       unsigned short data_addr = PAR_DATA(dev);
-       unsigned short nibble_timeout = nl->nibble;
-       unsigned char *lbuf;
-       unsigned int cx;
-       unsigned int pad = 2;
-       unsigned long flags;
-
-       if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
-               printk("%s: send skb lost\n", dev->name);
-               snd->state = WIC_PK_DONE;
-               snd->skb = NULL;
-               save |= 0x10; /* enable */
-               outb(save, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-               return ERROR;
-       }
-
-       save_flags(flags);      
-       cli();
-       switch (snd->state) {
-       case WIC_PK_TRIGGER:
-       
-               if (nl->connection == WIC_CN_RECEIVE) {
-                       /* interrupted */
-                       nl->enet_stats.collisions++;
-                       restore_flags(flags);
-                       if (net_debug > 1)
-                               printk("%s: collision.\n", dev->name);
-                       save |= 0x10; /* enable */
-                       outb(save, PAR_CONTROL(dev));
-                       enable_irq(dev->irq);
-                       return OK;
-               }
-               
-               disable_irq(dev->irq);
-               save &= 0xef; /* disable */
-               outb(save, PAR_CONTROL(dev));
-               
-               /* interrupt controller */
-               tog = 3;
-               outb(0x06 | save, PAR_CONTROL(dev));
-                       
-               cx = LOOPCNT;
-               while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
-                       if (--cx == 0) {
-                               restore_flags(flags);
-                               return TIMEOUT;
-                       }
-                       if (cx == 10)
-                               outb(0x02, PAR_CONTROL(dev));
-               }
-               
-               if (net_debug > 2)
-                       printk("%s: send start\n", dev->name);
-               snd->state = WIC_PK_LENGTH_LSB;
-               snd->nibble = WIC_NB_BEGIN;
-               nl->timeout_count = 0;
-
-       case WIC_PK_LENGTH_LSB:
-               if (snd->length.h & 0x01)
-                       pad = 3;
-               else
-                       pad = 2;
-               snd->length.h += (4 + pad); /* len + seq + data + pad */
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_LENGTH_LSB: length = %i\n", 
-                               dev->name, snd->length.h);
-
-               if (wic_send(nibble_timeout, data_addr,
-                             &snd->nibble, snd->length.b.lsb)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-               snd->state = WIC_PK_LENGTH_MSB;
-
-       case WIC_PK_LENGTH_MSB:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
-               if (wic_send(nibble_timeout, data_addr,
-                             &snd->nibble, snd->length.b.msb)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-               snd->state = WIC_PK_DATA;
-               snd->byte = 0;
-               snd->checksum = 0;
-
-       case WIC_PK_DATA:
-               /* adjust length back to data only */
-               snd->length.h -= (4 + pad); /* len + seq + data + pad */
-               /* send 2 byte sequence number */
-               if (net_debug > 2)
-                       printk("%s: WIC_SEQ\n", dev->name);
-               if (wic_send(nibble_timeout, data_addr,
-                             &snd->nibble, 0)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }
-               if (wic_send(nibble_timeout, data_addr,
-                             &snd->nibble, 0)) {
-                       restore_flags(flags);
-                       return TIMEOUT;
-               }       
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_DATA\n", dev->name);
-
-               do {
-                       if (wic_send(nibble_timeout, data_addr,
-                                     &snd->nibble, lbuf[snd->byte])) {
-                               restore_flags(flags);
-                               return TIMEOUT;
-                       }
-               }
-               while (++snd->byte < snd->length.h);
-               
-               do
-                       snd->checksum += lbuf[--snd->byte];
-               while (snd->byte);
-
-               snd->state = WIC_PK_CHECKSUM;
-
-       case WIC_PK_CHECKSUM:
-               /* send pad bytes */
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_PAD: %i bytes\n", 
-                               dev->name, pad);
-               while(pad--)
-                       if (wic_send(nibble_timeout, data_addr,
-                               &snd->nibble, 0)) {
-                               restore_flags(flags);
-                               return TIMEOUT;
-                       }
-               dev_kfree_skb(snd->skb, FREE_WRITE);
-               nl->enet_stats.tx_packets++;
-               snd->state = WIC_PK_DONE;
-
-       case WIC_PK_DONE:
-               if (net_debug > 2)
-                       printk("%s: WIC_PK_DONE\n", dev->name);
-               /* Close the connection */
-               outb (0x00, PAR_DATA(dev));
-               outb(save, PAR_CONTROL(dev));
-               
-               snd->skb = NULL;
-               if (net_debug > 2)
-                       printk("%s: send end\n", dev->name);
-               nl->connection = WIC_CN_CLOSING;
-               nl->is_deferred = 1;
-               restore_flags(flags);
-               queue_task(&nl->deferred, &tq_timer);
-               save |= 0x10; /* enable */
-               outb(save, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-               return OK;
-       }
-       restore_flags(flags);
-       return OK;
-}
-
-int wic_connection_close(struct device *dev, struct net_local *nl,
-                     struct wic_local *snd, struct wic_local *rcv)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       if (nl->connection == WIC_CN_CLOSING) {
-               nl->connection = WIC_CN_NONE;
-               dev->tbusy = 0;
-               mark_bh(NET_BH);
-       }
-       restore_flags(flags);
-       return OK;
-}
-
-/* WIC_ERROR --- wait till other end settled */
-int wic_error(struct device *dev, struct net_local *nl,
-          struct wic_local *snd, struct wic_local *rcv)
-{
-       unsigned char status;
-
-       status = inb(PAR_STATUS(dev));
-       if ((status & 0xf8) == 0x80) {
-               if (net_debug > 2)
-                       printk("%s: reset interface.\n", dev->name);
-               nl->connection = WIC_CN_NONE;
-               dev->tbusy = 0;
-               dev->interrupt = 0;
-               save |= 0x10; /* enable */
-               outb(save, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-               mark_bh(NET_BH);
-       } else {
-               nl->is_deferred = 1;
-               queue_task(&nl->deferred, &tq_timer);
-       }
-
-       return OK;
-}
-
-/* Handle the parallel port interrupts. */
-void wic_interrupt(int irq, void *dev_ptr, struct pt_regs * regs)
-{
-       struct device *dev = (struct device *) irq2dev_map[irq];
-       struct net_local *nl = (struct net_local *)dev->priv;
-       struct wic_local *rcv = &nl->rcv_data;
-       unsigned long flags;
-
-       if (dev == NULL) {
-               printk ("wic_interrupt: irq %d for unknown device.\n", irq);
-               return;
-       }
-
-       if (dev->interrupt) {
-               return;
-       }
-
-       if (check_bfr(dev) < 0) {
-               return;
-       }
-       
-       dev->interrupt = 1;
-       if (net_debug > 3)
-               printk("%s: interrupt.\n", dev->name);
-
-       save_flags(flags);
-       cli();
-       switch (nl->connection) {
-       case WIC_CN_CLOSING:
-               dev->tbusy = 0;
-       case WIC_CN_NONE:
-       case WIC_CN_SEND:
-               dev->last_rx = jiffies;
-               rcv->state = WIC_PK_TRIGGER;
-               nl->connection = WIC_CN_RECEIVE;
-               nl->timeout_count = 0;
-               restore_flags(flags);
-               queue_task(&nl->immediate, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
-               break;
-
-       case WIC_CN_RECEIVE:
-               printk("%s: receive interrupt when receiving packet\n", dev->name);
-               restore_flags(flags);
-               break;
-
-       case WIC_CN_ERROR:
-               printk("%s: receive interrupt in error state\n", dev->name);
-               restore_flags(flags);
-               break;
-       }
-}
-
-int wic_rebuild_header(struct sk_buff *skb)
-{
-       struct device *dev = skb->dev;
-       struct net_local *nl = (struct net_local *)dev->priv;
-       struct ethhdr *eth = (struct ethhdr *)skb->data;
-       int i;
-
-       if ((dev->flags & IFF_NOARP)==0)
-               return nl->orig_rebuild_header(skb);
-
-       if (eth->h_proto != htons(ETH_P_IP)) {
-               printk("wic_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
-               memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-               return 0;
-       }
-
-       for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
-               eth->h_dest[i] = 0xfc;
-       memcpy(&(eth->h_dest[i]), &skb->daddr, 4);
-       return 0;
-}
-
-int wic_tx_packet(struct sk_buff *skb, struct device *dev)
-{
-       struct net_local *nl = (struct net_local *)dev->priv;
-       struct wic_local *snd = &nl->snd_data;
-       unsigned long flags;
-
-       if (dev->tbusy)
-               return 1;
-
-       /* If some higher layer thinks we've missed an tx-done interrupt
-          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-          itself. */
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
-       if (set_bit(0, (void*)&dev->tbusy) != 0) {
-               printk("%s: Transmitter access conflict.\n", dev->name);
-               return 1;
-       }
-
-       if (skb->len > dev->mtu) {
-               printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
-               dev->tbusy = 0;
-               return 0;
-       }
-
-       if (net_debug > 2)
-               printk("%s: send request\n", dev->name);
-
-       save_flags(flags);
-       cli();
-       dev->trans_start = jiffies;
-       snd->skb = skb;
-       snd->length.h = skb->len;
-       snd->state = WIC_PK_TRIGGER;
-       if (nl->connection == WIC_CN_NONE) {
-               nl->connection = WIC_CN_SEND;
-               nl->timeout_count = 0;
-       }
-       restore_flags(flags);
-       queue_task(&nl->immediate, &tq_immediate);
-       mark_bh(IMMEDIATE_BH);
-
-       return 0;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine gets exclusive access to the parallel port by allocating
-   its IRQ line.
- */
-int wic_open(struct device *dev)
-{
-       struct net_local *nl = (struct net_local *)dev->priv;
-       unsigned long flags;
-
-       if (dev->irq == 0) {
-               printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
-               return -EAGAIN;
-       }
-       save_flags(flags);
-       cli();
-       check_bfr(dev);
-       if (request_irq(dev->irq , wic_interrupt, 0, dev->name, NULL) != 0) {
-               sti();
-               printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-       irq2dev_map[dev->irq] = dev;
-       restore_flags(flags);
-
-       save |= 0x10; /* enable */
-       outb(save, PAR_CONTROL(dev));
-       /* Initialize the state machine. */
-       nl->rcv_data.state = nl->snd_data.state = WIC_PK_DONE;
-       nl->rcv_data.skb = nl->snd_data.skb = NULL;
-       nl->connection = WIC_CN_NONE;
-       nl->is_deferred = 0;
-
-       dev->interrupt = 0;
-       dev->start = 1;
-       dev->tbusy = 0;
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-
-/* The inverse routine to wic_open (). */
-int wic_close(struct device *dev)
-{
-       struct net_local *nl = (struct net_local *)dev->priv;
-       struct wic_local *snd = &nl->snd_data;
-       struct wic_local *rcv = &nl->rcv_data;
-
-       dev->tbusy = 1;
-       dev->start = 0;
-       cli();
-       free_irq(dev->irq, NULL);
-       irq2dev_map[dev->irq] = NULL;
-       nl->is_deferred = 0;
-       nl->connection = WIC_CN_NONE;
-       sti();
-       outb(0x00, PAR_DATA(dev));
-
-       snd->state = WIC_PK_DONE;
-       if (snd->skb) {
-               dev_kfree_skb(snd->skb, FREE_WRITE);
-               snd->skb = NULL;
-       }
-       rcv->state = WIC_PK_DONE;
-       if (rcv->skb) {
-               kfree_skb(rcv->skb, FREE_READ);
-               rcv->skb = NULL;
-       }
-
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-struct enet_statistics *
-wic_get_stats(struct device *dev)
-{
-       struct net_local *nl = (struct net_local *)dev->priv;
-       struct enet_statistics *r = &nl->enet_stats;
-
-       return r;
-}
-
-int
-wic_config(struct device *dev, struct ifmap *map)
-{
-       if (dev->flags & IFF_UP)
-               return -EBUSY;
-
-       if (map->base_addr != (unsigned long)-1
-           && map->base_addr != dev->base_addr)
-               printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
-
-       if (map->irq != (unsigned char)-1)
-               dev->irq = map->irq;
-       return 0;
-}
-
-int
-wic_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-{
-       struct wicconf wc;
-       int err;
-       char len = 0;
-       unsigned long flags;
-
-       err=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(struct wicconf));
-       if (err)
-               return err;
-       copy_from_user(&wc, rq->ifr_data, sizeof(struct wicconf));
-       switch(wc.pcmd) {
-               case WIC_AYT:
-                       strcpy(wc.data, version);
-                       wc.len = strlen(wc.data);
-                       copy_to_user(rq->ifr_data, &wc, sizeof(struct wicconf));
-                       /* return 0; */
-                       break;
-               case WIC_RESET:
-                       wic_reset(dev);
-                       return(0);
-                       /* break; */
-               case WIC_SETSN:
-                       len = 17;
-                       break;
-               case WIC_SETPS:
-                       len = 3;
-                       break;
-               case WIC_SETAF:
-               case WIC_SETGPF:
-                       len = 2;
-                       break;
-               case WIC_SETNET:
-                       len = 23;
-                       break;
-               case WIC_SETSYS:
-                       len = 15;
-                       break;
-               case WIC_GETVERH:
-               case WIC_GETNL:
-               case WIC_GETSN:
-               case WIC_CLRSTATS:
-               case WIC_GETSTATS:
-               case WIC_GETVERM:
-               case WIC_GETNET:
-               case WIC_GETSYS:
-                       len = 1;
-                       break;  
-               default:
-                       return -EOPNOTSUPP;
-       }
-
-       /* Wait for lock to free */
-       while (set_bit(0, (void *)&dev->tbusy) != 0); 
-       save_flags(flags);
-       cli();
-
-       disable_irq(dev->irq);
-       save &= 0xef; /* disable */
-       outb(save, PAR_CONTROL(dev));
-       err = check_bfr(dev);
-       tog = 3;
-       err = send_cmd(dev, (unsigned char *)&wc, len);
-
-       if (wc.pcmd & 0x40) {   /* response */
-               len = (char)recv_cmd_resp(dev, wc.data);
-               while ((len == 1) && (wc.data[0] == 0x7)) { /* controller int */
-                       len = (char)recv_cmd_resp(dev, wc.data);
-               }
-               save |= 0x10; /* enable */
-               outb(save, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-               wc.len = (len <0) ? 0 : len;
-               copy_to_user(rq->ifr_data, &wc, sizeof(struct wicconf));
-       } else {
-               save |= 0x10; /* enable */
-               outb(save, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-       }
-       restore_flags(flags);
-
-       outb(0, PAR_DATA(dev));
-       dev->tbusy = 0;
-       return 0;
-}
-
-int
-get_byte(struct device *dev, unsigned char *c)
-{
-unsigned int cx;
-
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0x08) != ((tog << 3)&0x08)) {
-               if (--cx == 0) {
-                       return(-TIMEOUT);
-               }
-       }
-       /* receive a byte of data */
-       *c = inb(PAR_DATA(dev));
-       tog ^= 0x01;
-       /* ack reception of data */
-       outb(tog| save, PAR_CONTROL(dev));
-       return OK;
-}
-
-int
-ack_resp(struct device *dev)
-{
-unsigned int cx;
-       
-       outb(save | 0x27, PAR_CONTROL(dev));
-
-       /* wait for controller to remove interrupt [Ack(low), Busy(low)] */
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0xc0) != 0x80) {
-               if (--cx == 0) {
-                       return -TIMEOUT;
-               }
-       }
-       
-       outb(save | 0x22, PAR_CONTROL(dev));
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0x08) == 0x08) {
-               if (--cx == 0) {
-                       return TIMEOUT;
-               }
-       }
-       tog |= 0x20;
-       tog &= 0xfe;
-       return OK;
-}
-
-void
-wic_reset(struct device *dev)
-{
-unsigned char stat;
-
-       stat = inb(PAR_CONTROL(dev));
-       outb(0, PAR_DATA(dev));
-       outb(stat | 0x08, PAR_CONTROL(dev));
-       outb(stat & 0xf7, PAR_CONTROL(dev));
-       dev->tbusy = 0;
-       dev->interrupt = 0;
-       tog = 3;
-       save = 0;
-       return;
-}
-
-int
-check_bfr(struct device *dev)
-{
-unsigned char c0, l;
-
-       if ((inb(PAR_STATUS(dev)) & 0xc8) == 0x48) {
-               save |= 0x80;
-               outb(0x23| save, PAR_CONTROL(dev));
-               ack_resp(dev);
-               get_byte(dev, &l);      /* len */
-               while (l--) {
-                       get_byte(dev, &c0);
-               }
-               get_byte(dev, &c0);
-               save &=0x7f;
-               outb(0, PAR_DATA(dev));
-               return -l;
-       } else
-       return (0);
-}
-
-
-int
-recv_cmd_resp(struct device *dev, unsigned char *buf)
-{
-unsigned char cksum = 0;
-int err;
-unsigned char c0 = 0;
-int len;
-int savelen;
-unsigned int cx;
-int i;
-
-       tog &= 0xfe;
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0xc8) != 0x48) {
-               if (--cx == 0) {
-                       /* clear Busy */
-                       outb(0, PAR_DATA(dev));
-                       printk("rcv_cmd_resp: timeout\n");
-                       return -TIMEOUT;
-               }
-       }
-       
-       /* acknowledge the interrupt */
-       i = ack_resp(dev);
-
-       /* get length */
-       err = get_byte(dev, &c0);
-       if (err < 0) {
-               printk("get_byte1: failed\n");
-               return(err);
-       }
-       len = c0;
-       savelen = len;
-
-       /* get data */
-       while(len--) {
-               err = get_byte(dev, &c0);
-               if (err < 0) {
-                       printk("get_byte2: failed\n");
-                       return(err);
-               }
-               outb(0, PAR_DATA(dev)); 
-               *buf = c0;
-               cksum += c0;
-               buf++;
-       }       
-       /* get cksum */
-       err = get_byte(dev, &c0);
-       if (err < 0) {
-               printk("get_byte3: failed\n");
-               return(err);
-       }
-       if (cksum != c0) {
-               printk("cksum failed\n");
-               return(-3);
-       }
-       /* get trailing byte, if any... */
-       get_byte(dev, &c0);
-       return(savelen);
-}      
-
-int
-send_byte(struct device *dev, unsigned char c)
-{
-unsigned int cx;
-
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog<<7) & 0x80)) {
-               if (--cx == 0) {
-                       return(-TIMEOUT);
-               }
-       }
-       outb(c, PAR_DATA(dev));
-       outb(save |tog, PAR_CONTROL(dev));
-       tog ^= 0x01;
-       return OK;
-}
-
-
-int
-send_cmd(struct device *dev, unsigned char *cmd, char len)
-{
-unsigned char cksum = 0;
-int err = 0;
-unsigned int cx;
-
-       /* interrupt controller */
-       outb(save | 0x04, PAR_CONTROL(dev));
-       /* wait for ACK */
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
-               if (--cx == 0) 
-                       return -TIMEOUT;
-               if (cx == 10)
-                       outb(0x02, PAR_CONTROL(dev));
-       }
-       /* cmd coming... */
-       outb(save | 0x02, PAR_CONTROL(dev));
-       /* send length byte */
-       err = send_byte(dev, (unsigned char)len);
-       
-       /* send data */
-       while (len--) {
-               err = send_byte(dev, *cmd);     
-               if (err < 0) {
-                       return err;
-               }
-               cksum += *cmd;
-               cmd++;
-       }
-       
-       /* send cksum byte */
-       err = send_byte(dev, cksum);    
-       if (err < 0)
-               return err;
-
-       cx = LOOPCNT;
-       while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog <<7)&0x80)) {
-               if (--cx == 0) 
-                       return -TIMEOUT;
-       }
-       save |= 0x80;
-       outb(save | 0x23, PAR_CONTROL(dev));
-       outb(0, PAR_DATA(dev));
-       return OK;      
-}
-
-#ifdef MODULE
-struct device dev_wic0 = 
-{
-       "wic0" /*"wic"*/,
-       0, 0, 0, 0,             /* memory */
-       0x3BC, 5,               /* base, irq */
-       0, 0, 0, NULL, wic_init 
-};
-
-struct device dev_wic1 = 
-{
-       "wic1" /*"wic"*/,
-       0, 0, 0, 0,             /* memory */
-       0x378, 7,               /* base, irq */
-       0, 0, 0, NULL, wic_init 
-};
-
-struct device dev_wic2 = 
-{
-       "wic2" /*"wic"*/,
-       0, 0, 0, 0,             /* memory */
-       0x278, 2,               /* base, irq */
-       0, 0, 0, NULL, wic_init 
-};
-
-int
-init_module(void)
-{
-       int devices=0;
-
-       if (register_netdev(&dev_wic0) != 0)
-               devices++;
-       if (register_netdev(&dev_wic1) != 0)
-               devices++;
-       if (register_netdev(&dev_wic2) != 0)
-               devices++;
-       if (devices == 0)
-               return -EIO;
-       return 0;
-}
-
-void
-cleanup_module(void)
-{
-       if (dev_wic0.priv) {
-               unregister_netdev(&dev_wic0);
-               release_region(PAR_DATA(&dev_wic0), 3);
-               kfree_s(dev_wic0.priv, sizeof(struct net_local));
-               dev_wic0.priv = NULL;
-       }
-       if (dev_wic1.priv) {
-               unregister_netdev(&dev_wic1);
-               release_region(PAR_DATA(&dev_wic1), 3);
-               kfree_s(dev_wic1.priv, sizeof(struct net_local));
-               dev_wic1.priv = NULL;
-       }
-       if (dev_wic2.priv) {
-               unregister_netdev(&dev_wic2);
-               release_region(PAR_DATA(&dev_wic2), 3);
-               kfree_s(dev_wic2.priv, sizeof(struct net_local));
-               dev_wic2.priv = NULL;
-       }
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c wic.c"
- * End:
- */
index a9996fd65bdad04ead9436dc34338eede095b36e..bea1771c6ff678f3cb846bba216154b4df684690 100644 (file)
@@ -121,7 +121,7 @@ static unsigned int znet_debug = ZNET_DEBUG;
 #define net_local znet_private
 struct znet_private {
        int rx_dma, tx_dma;
-       struct enet_statistics stats;
+       struct net_device_stats stats;
        /* The starting, current, and end pointers for the packet buffers. */
        ushort *rx_start, *rx_cur, *rx_end;
        ushort *tx_start, *tx_cur, *tx_end;
@@ -185,7 +185,7 @@ static int  znet_send_packet(struct sk_buff *skb, struct device *dev);
 static void    znet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void    znet_rx(struct device *dev);
 static int     znet_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 static void hardware_init(struct device *dev);
 static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
@@ -317,6 +317,7 @@ static int znet_open(struct device *dev)
 static int znet_send_packet(struct sk_buff *skb, struct device *dev)
 {
        int ioaddr = dev->base_addr;
+       struct net_local *lp = (struct net_local *)dev->priv;
 
        if (znet_debug > 4)
                printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy);
@@ -340,11 +341,6 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev)
                hardware_init(dev);
        }
 
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
        /* Check that the part hasn't reset itself, probably from suspend. */
        outb(CMD0_STAT0, ioaddr);
        if (inw(ioaddr) == 0x0010
@@ -361,6 +357,8 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev)
                unsigned char *buf = (void *)skb->data;
                ushort *tx_link = zn.tx_cur - 1;
                ushort rnd_len = (length + 1)>>1;
+               
+               lp->stats.tx_bytes+=length;
 
                {
                        short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
@@ -616,7 +614,7 @@ static int znet_close(struct device *dev)
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct enet_statistics *net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
                struct net_local *lp = (struct net_local *)dev->priv;
 
index 542b5f5ef390cff27d380877d02d230780aa334a..273ed3ea13ab7cd164c41970c59fa701e8ca03db 100644 (file)
@@ -35,7 +35,7 @@ dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) supp
     bool '  enable linked commands' CONFIG_SCSI_EATA_LINKED_COMMANDS
     int  '  maximum number of queued commands' CONFIG_SCSI_EATA_MAX_TAGS 16
   fi
-dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
+dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
 if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
        bool '   Enable NCR53c400 extensions' CONFIG_SCSI_GENERIC_NCR53C400
index 1d166c9e73fa2b31dffa5d51993d8e55a2d24607..e01cd5e2aeb0379fbce260a6f159f91aac2bf162 100644 (file)
@@ -18,7 +18,7 @@
    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
    (you can reference it, but it is incomplete and inaccurate in places)
 
-   Version 0.45 6/9/96 - kernel 1.2.0+
+   Version 0.46 1/30/97 - kernel 1.2.0+
 
    Functions as standalone, loadable, and PCMCIA driver, the latter from
    Dave Hind's PCMCIA package.
 #include "qlogicfas.h"
 #include<linux/stat.h>
 
-struct proc_dir_entry proc_scsi_qlogicfas = {
+static struct proc_dir_entry proc_scsi_qlogicfas = {
     PROC_SCSI_QLOGICFAS, 6, "qlogicfas",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
@@ -620,7 +620,7 @@ host->proc_dir =  &proc_scsi_qlogicfas;
        if( qlirq != -1 )
                hreg->irq = qlirq;
 
-       sprintf(qinfo, "Qlogicfas Driver version 0.45, chip %02X at %03X, IRQ %d, TPdma:%d",
+       sprintf(qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
            qltyp, qbase, qlirq, QL_TURBO_PDMA );
        host->name = qinfo;
 
index 324969f7dddc94075b096acd71ef3a8aea487382..861e12632c567369b85fe98bfa3bedb1606b9d9f 100644 (file)
@@ -2,6 +2,7 @@
  * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
  * Written by Erik H. Moe, ehm@cris.com
  * Copyright 1995, Erik H. Moe
+ * Copyright 1996, 1997  Michael A. Griffith <grif@acm.org> 
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * General Public License for more details.
  */
 
-/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
-
-/*
- * $Date: 1995/09/22 02:23:15 $
- * $Revision: 0.5 $
- *
- * $Log: isp1020.c,v $
- * Revision 0.5  1995/09/22  02:23:15  root
- * do auto request sense
- *
- * Revision 0.4  1995/08/07  04:44:33  root
- * supply firmware with driver.
- * numerous bug fixes/general cleanup of code.
- *
- * Revision 0.3  1995/07/16  16:15:39  root
- * added reset/abort code.
- *
- * Revision 0.2  1995/06/29  03:14:19  root
- * fixed biosparam.
- * added queue protocol.
- *
- * Revision 0.1  1995/06/25  01:55:45  root
- * Initial release.
- *
- */
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -390,7 +365,7 @@ struct Status_Entry {
 
 #define PACKB(a, b)                    (((a)<<4)|(b))
 
-const u_char mbox_param[] = {
+static const u_char mbox_param[] = {
        PACKB(1, 1),    /* MBOX_NO_OP */
        PACKB(5, 5),    /* MBOX_LOAD_RAM */
        PACKB(2, 0),    /* MBOX_EXEC_FIRMWARE */
@@ -534,7 +509,7 @@ struct isp1020_hostdata {
                                                    QLOGICISP_REQ_QUEUE_LEN)
 #define RES_QUEUE_DEPTH(in, out)       QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
 
-struct Scsi_Host *irq2host[NR_IRQS];
+static struct Scsi_Host *irq2host[NR_IRQS];
 
 static void    isp1020_enable_irqs(struct Scsi_Host *);
 static void    isp1020_disable_irqs(struct Scsi_Host *);
index 1fafc7ecbba567bc108f1c6b33a4b6eccb9d384a..0b1828ca08888f65c1532a992601c180674178be 100644 (file)
@@ -2,13 +2,13 @@
  *     Version 2.10 Initiator Firmware (16:13 Oct 18, 1995)
  */
 
-unsigned short risc_code_version = 2*1024+10;
+static const unsigned short risc_code_version = 2*1024+10;
 
-unsigned short risc_code_addr01 = 0x1000 ;
+static const unsigned short risc_code_addr01 = 0x1000 ;
 
 #if RELOAD_FIRMWARE
 
-unsigned short risc_code01[] = { 
+static const unsigned short risc_code01[] = { 
        0x0078, 0x1041, 0x0000, 0x283a, 0x0000, 0x2043, 0x4f50, 0x5952,
        0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
        0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320,
@@ -1301,4 +1301,4 @@ unsigned short risc_code01[] = {
 
 #endif /* RELOAD_FIRMWARE */
 
-unsigned short risc_code_length01 = 0x283a;
+static const unsigned short risc_code_length01 = 0x283a;
index 916ffd3a7ff8611a4b12275012644b8e91e2c829..1fb997667a36dbf7919a8f9888406f29c4245bf7 100644 (file)
@@ -238,6 +238,7 @@ static struct dev_info device_list[] =
 {"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
 {"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
 {"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
+{"HP", "C3725S", "*", BLIST_NOTQ},             /* Buggy Tagged Queuing */
 {"MICROP", "4110", "*", BLIST_NOTQ},           /* Buggy Tagged Queuing */
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
index c422f30451c36db73a81159dcfd69aa7ce978bad..070e3da08dbbecf3e93f1261d76b3eecc3886802 100644 (file)
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
@@ -215,7 +216,7 @@ typedef struct adapter {
  * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be
  * changed to pick up the IRQ level correctly.
  */
-Adapter *irq2host[16] = {NULL};        /* Possible IRQs are 0-15 */
+static Adapter *irq2host[NR_IRQS] = {NULL};
 
 /*
  * (linear) base address for ROM BIOS
index ed024f864871b866559df20828db58fbf1a70a72..5db96a434c46437aa81948f9a3983a66461b472d 100644 (file)
@@ -18,6 +18,7 @@ EXPORT_SYMBOL(proc_unregister);
 EXPORT_SYMBOL(proc_root);
 EXPORT_SYMBOL(proc_get_inode);
 EXPORT_SYMBOL(in_group_p);
+EXPORT_SYMBOL(proc_dir_inode_operations);
 EXPORT_SYMBOL(proc_net_inode_operations);
 EXPORT_SYMBOL(proc_net);
 
index 9ce52c0e0ae119865f23bb9aaa9576e8a448da61..9f77a034afba09298541466cbb0646198f8ff2d8 100644 (file)
@@ -511,7 +511,7 @@ static struct proc_dir_entry proc_root_mounts = {
        S_IFREG | S_IRUGO, 1, 0, 0,
 };
 static struct proc_dir_entry proc_root_swaps = {
-       PROC_MTAB, 5, "swaps",
+       PROC_SWAP, 5, "swaps",
        S_IFREG | S_IRUGO, 1, 0, 0,
 };
 static struct proc_dir_entry proc_root_profile = {
index 0780be55df700b3b5ac262094e37a885253ca8af..a9c822aa45b3a86d0abcda6542c9931802b687cb 100644 (file)
@@ -240,6 +240,10 @@ smb_send_raw(struct socket *sock, unsigned char *source, int length)
                               (void *) (source + already_sent),
                               length - already_sent, 0, 0);
 
+               if (result == 0)
+               {
+                       return -EIO;
+               }
                if (result < 0)
                {
                        DPRINTK("smb_send_raw: sendto error = %d\n",
index 72ba38307bf1fcbef2cad1f4656d4c2e50506d70..bec632323a2928995efa58749b5d18fe6cf16466 100644 (file)
@@ -17,20 +17,39 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
 
 /*
  * the same as csum_partial, but copies from src while it
- * checksums
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
 
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+unsigned int csum_partial_copy_from_user( int * err, const char *src, 
+                                               char *dst, int len, int sum);
+
+/*
+ * I hope GCC will optimize 'dummy' away ...
+ */
+
+unsigned int csum_partial_copy_nocheck_generic( int * err, const char *src, char *dst,
+                                                int len, int sum);
 
+extern __inline__ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+                                                        int len, int sum)
+{
+        int dummy;
+
+        return csum_partial_copy_nocheck_generic ( &dummy, src, dst, len, sum);
+}
 
 /*
- * the same as csum_partial, but copies from user space (but on the x86
- * we have just one address space, so this is identical to the above)
+ * These are the 'old' way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
+ *
+ * these functions should go away after some time.
  */
+
 #define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
 
 /*
  *     This is a version of ip_compute_csum() optimized for IP headers,
index 8a660d6bf218075f163251151d327d0e655fea81..587e3356c0bf025837e50bc1226ae3651704da71 100644 (file)
@@ -6,7 +6,24 @@
 #define lock_kernel()          do { } while(0)
 #define unlock_kernel()                do { } while(0)
 
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED
+
+#define spin_lock_init(lock)   do { } while(0)
+#define spin_lock(lock)                do { } while(0)
+#define spin_trylock(lock)     do { } while(0)
+#define spin_unlock(lock)      do { } while(0)
+
+#define spin_lock_cli(lock)            \
+({     unsigned long flags;            \
+       save_flags(flags); cli();       \
+       return flags;                   \
+})
+
+#define spin_unlock_restore(lock, flags)       restore_flags(flags)
+
 #else
+#include <asm/pgtable.h>
 
 /* Locking the kernel */
 extern __inline__ void lock_kernel(void)
@@ -45,6 +62,92 @@ extern __inline__ void unlock_kernel(void)
        : "ax", "memory");
 }
 
+/* Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ *
+ *     NOT YET TESTED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+typedef unsigned char spinlock_t;
+
+/* Arse backwards is faster for us on Intel (trylock is a clock faster) */
+
+#define SPIN_LOCK_UNLOCKED     1
+
+extern __inline__ void __spinlock_waitfor(spinlock_t *lock)
+{
+       int cpu=smp_processor_id();
+       do
+       {
+               /* Spin reading and let the MESI cache do the right stuff
+                  without us thrashing the bus */
+               while(lock)
+               {
+                       /*
+                        *      Not a race, the interrupt will pick up
+                        *      the exiting case that looks suspicious.
+                        *      (The test_bit is not locked so won't
+                        *       thrash the bus either).
+                        */
+                       if(test_bit(cpu,&smp_invalidate_needed))
+                       {
+                               local_flush_tlb();
+                               clear_bit(cpu,&smp_invalidate_needed);
+                       }
+               }
+       }
+       while(clear_bit(0,lock));
+}
+
+extern __inline__ void spin_lock_init(spinlock_t *lock)
+{
+       *lock = 1;      /* We assume init does not need to be itself SMP safe */
+}
+
+extern __inline__ void spin_lock(spinlock_t *lock)
+{
+       /* Returns the old value. If we get 1 then we got the lock */
+       if(clear_bit(0,lock))
+       {
+               __spinlock_waitfor(lock);
+       }
+}
+
+extern __inline__ int spin_trylock(spinlock_t *lock)
+{
+       return clear_bit(0,lock);
+}
+
+extern __inline__ void spin_unlock(spinlock_t *lock)
+{
+       set_bit(0,lock);
+}
+
+/* These variants clear interrupts and return save_flags() style flags
+ * to the caller when acquiring a lock.  To release the lock you must
+ * pass the lock pointer as well as the flags returned from the acquisition
+ * routine when releasing the lock.
+ */
+extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock)
+{
+       unsigned long flags;
+       save_flags(flags);
+       cli();
+       if(clear_bit(0,lock))
+               __spinlock_waitfor(lock);
+       return flags;
+}
+
+extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags)
+{
+       set_bit(0,lock);        /* Locked operation to keep it serialized with
+                                  the popfl */
+       restore_flags(flags);
+}
+
+
 #endif /* __SMP__ */
 
 #endif /* __I386_SMPLOCK_H */
index 8f255da82f116acb1c80855016c8720e7737b43c..41c00d960787c9681cd3db3e068e3b72833e3d05 100644 (file)
@@ -6,7 +6,6 @@
 #ifndef        AX25_KERNEL_H
 #define        AX25_KERNEL_H
 
-#define PF_AX25                AF_AX25
 #define AX25_MTU       256
 #define AX25_MAX_DIGIS 6       /* This is wrong, should be 8 */
 
index 96181d08b75381579546af2bf7ba2db62dfdd87d..5f18a049afced030cd52fcc54fd640220bf25237 100644 (file)
@@ -57,6 +57,7 @@
 #define ARPHRD_FDDI    774             /* Fiber Distributed Data Interface */
 #define ARPHRD_BIF      775             /* AP1000 BIF                   */
 #define ARPHRD_SIT     776             /* sit0 device - IPv6-in-IPv4   */
+#define ARPHRD_IPDDP   777             /* IP over DDP tunneller        */
 
 /* ARP protocol opcodes. */
 #define        ARPOP_REQUEST   1               /* ARP request                  */
index dd09d83529d4565f48fd7344271b1a9e5e9de2ba..213251b23003c116ccc88f8eea64d62e71c19048 100644 (file)
@@ -85,35 +85,11 @@ struct ethhdr
 };
 
 /*
- *     Ethernet statistics collection data. 
+ *     We Have changed the ethernet statistics collection data. This
+ *     is just for partial compatibility for now.
  */
  
-struct enet_statistics
-{
-       int     rx_packets;             /* total packets received       */
-       int     tx_packets;             /* total packets transmitted    */
-       int     rx_errors;              /* bad packets received         */
-       int     tx_errors;              /* packet transmit problems     */
-       int     rx_dropped;             /* no space in linux buffers    */
-       int     tx_dropped;             /* no space available in linux  */
-       int     multicast;              /* multicast packets received   */
-       int     collisions;
-
-       /* detailed rx_errors: */
-       int     rx_length_errors;
-       int     rx_over_errors;         /* receiver ring buff overflow  */
-       int     rx_crc_errors;          /* recved pkt with crc error    */
-       int     rx_frame_errors;        /* recv'd frame alignment error */
-       int     rx_fifo_errors;         /* recv'r fifo overrun          */
-       int     rx_missed_errors;       /* receiver missed packet       */
-
-       /* detailed tx_errors */
-       int     tx_aborted_errors;
-       int     tx_carrier_errors;
-       int     tx_fifo_errors;
-       int     tx_heartbeat_errors;
-       int     tx_window_errors;
-};
-
+#define enet_statistics net_device_stats
 
 #endif /* _LINUX_IF_ETHER_H */
diff --git a/include/linux/if_ltalk.h b/include/linux/if_ltalk.h
new file mode 100644 (file)
index 0000000..d7b17d3
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __LINUX_LTALK_H
+#define __LINUX_LTALK_H
+
+#define LTALK_HLEN             1
+#define LTALK_MTU              600
+#define LTALK_ALEN             1
+
+#ifdef __KERNEL__
+extern void ltalk_setup(struct device *);
+#endif
+
+#endif
index 1efdf1393a4f1225ea1aad5b91fac257cd725b85..3318c2ae8039342ceef42a0473bfc84e7d2ca378 100644 (file)
@@ -95,6 +95,42 @@ struct hh_cache
        unsigned long   hh_data[16/sizeof(unsigned long)];
 };
 
+/*
+ *     Network device statistics. Akin to the 2.0 ether stats but
+ *     with byte counters.
+ */
+struct net_device_stats
+{
+       unsigned long   rx_packets;             /* total packets received       */
+       unsigned long   tx_packets;             /* total packets transmitted    */
+       unsigned long   rx_bytes;               /* total bytes received         */
+       unsigned long   tx_bytes;               /* total bytes transmitted      */
+       unsigned long   rx_errors;              /* bad packets received         */
+       unsigned long   tx_errors;              /* packet transmit problems     */
+       unsigned long   rx_dropped;             /* no space in linux buffers    */
+       unsigned long   tx_dropped;             /* no space available in linux  */
+       unsigned long   multicast;              /* multicast packets received   */
+       unsigned long   collisions;
+
+       /* detailed rx_errors: */
+       unsigned long   rx_length_errors;
+       unsigned long   rx_over_errors;         /* receiver ring buff overflow  */
+       unsigned long   rx_crc_errors;          /* recved pkt with crc error    */
+       unsigned long   rx_frame_errors;        /* recv'd frame alignment error */
+       unsigned long   rx_fifo_errors;         /* recv'r fifo overrun          */
+       unsigned long   rx_missed_errors;       /* receiver missed packet       */
+
+       /* detailed tx_errors */
+       unsigned long   tx_aborted_errors;
+       unsigned long   tx_carrier_errors;
+       unsigned long   tx_fifo_errors;
+       unsigned long   tx_heartbeat_errors;
+       unsigned long   tx_window_errors;
+       
+};
+
+
 /*
  *     The DEVICE structure.
  *     Actually, this whole structure is a big mistake.  It mixes I/O
@@ -155,7 +191,7 @@ struct device
         *      should change this.
         */
         
-       struct enet_statistics* (*get_stats)(struct device *dev);
+       struct net_device_stats* (*get_stats)(struct device *dev);
        struct iw_statistics*   (*get_wireless_stats)(struct device *dev);
 
        /*
index cd69214c347f83e331cd2507a53afc3c6c61d343..c38788c7e17ff187b94e3f646bac21a16ebd4556 100644 (file)
@@ -10,7 +10,6 @@
 #define PF_ROSE                AF_ROSE
 #define ROSE_MTU       128
 
-#define ROSE_T0                1
 #define ROSE_T1                2
 #define        ROSE_T2         3
 #define        ROSE_T3         4
diff --git a/include/linux/sdla_fr.h b/include/linux/sdla_fr.h
new file mode 100644 (file)
index 0000000..bcca8d5
--- /dev/null
@@ -0,0 +1,416 @@
+/*****************************************************************************
+* sdla_fr.h    Sangoma frame relay firmware API definitions.
+*
+* Author:      Gene Kozin      <74604.152@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 23, 1996 Gene Kozin      v2.0
+* Apr 29, 1996 Gene Kozin      v1.0 (merged version S502 & S508 definitions).
+* Sep 26, 1995 Gene Kozin      Initial version.
+*****************************************************************************/
+#ifndef        _SDLA_FR_H
+#define        _SDLA_FR_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.  To ensure
+ *    portability of this code between different platforms and compilers, one
+ *    of the following defines must be defined before including this file:
+ *
+ *     Compiler        Platform        Define          Use option
+ *     --------        --------        ------          ----------
+ *     GNU C           Linux           _GNUC_          -
+ *     Microsoft C     DOS/Windows     _MSC_           -
+ */
+
+#ifdef         _GNUC_
+#  ifndef      PACKED
+#    define    PACKED  __attribute__((packed))
+#  endif       /* PACKED */
+#else
+#  define      PACKED
+#endif
+#ifdef         _MSC_
+#  pragma      pack(1)
+#endif
+
+/* Adapter memory layout */
+#define        FR_MB_VECTOR    0xE000  /* mailbox window vector */
+#define        FR502_RX_VECTOR 0xA000  /* S502 direct receive window vector */
+#define        FR502_MBOX_OFFS 0xF60   /* S502 mailbox offset */
+#define        FR508_MBOX_OFFS 0       /* S508 mailbox offset */
+#define        FR502_FLAG_OFFS 0x1FF0  /* S502 status flags offset */
+#define        FR508_FLAG_OFFS 0x1000  /* S508 status flags offset */
+#define        FR502_RXMB_OFFS 0x900   /* S502 direct receive mailbox offset */
+#define        FR508_TXBC_OFFS 0x1100  /* S508 Tx buffer info offset */
+#define        FR508_RXBC_OFFS 0x1120  /* S508 Rx buffer info offset */
+
+/* Important constants */
+#define FR502_MAX_DATA 4096    /* maximum data buffer length */
+#define FR508_MAX_DATA 4080    /* maximum data buffer length */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * Frame relay command block.
+ */
+typedef struct fr_cmd
+{
+       unsigned char  command  PACKED; /* command code */
+       unsigned short length   PACKED; /* length of data buffer */
+       unsigned char  result   PACKED; /* return code */
+       unsigned short dlci     PACKED; /* DLCI number */
+       unsigned char  attr     PACKED; /* FECN, BECN, DE and C/R bits */
+       unsigned short rxlost1  PACKED; /* frames discarded at int. level */
+       unsigned long  rxlost2  PACKED; /* frames discarded at app. level */
+       unsigned char  rsrv[2]  PACKED; /* reserved for future use */
+} fr_cmd_t;
+
+/* 'command' field defines */
+#define        FR_WRITE                0x01
+#define        FR_READ                 0x02
+#define        FR_ISSUE_IS_FRAME       0x03
+#define FR_SET_CONFIG          0x10
+#define FR_READ_CONFIG         0x11
+#define FR_COMM_DISABLE                0x12
+#define FR_COMM_ENABLE         0x13
+#define FR_READ_STATUS         0x14
+#define FR_READ_STATISTICS     0x15
+#define FR_FLUSH_STATISTICS    0x16
+#define        FR_LIST_ACTIVE_DLCI     0x17
+#define FR_FLUSH_DATA_BUFFERS  0x18
+#define        FR_ADD_DLCI             0x20
+#define        FR_DELETE_DLCI          0x21
+#define        FR_ACTIVATE_DLCI        0x22
+#define        FR_DEACTIVATE_DLCI      0x22
+#define FR_READ_MODEM_STATUS   0x30
+#define FR_SET_MODEM_STATUS    0x31
+#define FR_READ_ERROR_STATS    0x32
+#define FR_FLUSH_ERROR_STATS   0x33
+#define FR_READ_CODE_VERSION   0x40
+#define        FR_SET_INTR_MODE        0x50
+#define        FR_READ_INTR_MODE       0x51
+
+/* 'result' field defines */
+#define FRRES_OK               0x00    /* command executed successfully */
+#define        FRRES_DISABLED          0x01    /* communications not enabled */
+#define        FRRES_INOPERATIVE       0x02    /* channel inoperative */
+#define        FRRES_DLCI_INACTIVE     0x03    /* DLCI is inactive */
+#define        FRRES_DLCI_INVALID      0x04    /* DLCI is not configured */
+#define        FRRES_TOO_LONG          0x04
+#define        FRRES_TOO_MANY          0x05
+#define        FRRES_CIR_OVERFLOW      0x07    /* Tx throughput has exceeded CIR */
+#define        FRRES_BUFFER_OVERFLOW   0x08
+#define        FRRES_MODEM_FAILURE     0x10    /* DCD and/or CTS dropped */
+#define        FRRES_CHANNEL_DOWN      0x11    /* channel became inoperative */
+#define        FRRES_CHANNEL_UP        0x12    /* channel became operative */
+#define        FRRES_DLCI_CHANGE       0x13    /* DLCI status (or number) changed */
+#define        FRRES_DLCI_MISMATCH     0x14
+#define        FRRES_INVALID_CMD       0x1F    /* invalid command */
+
+/* 'attr' field defines */
+#define        FRATTR_
+
+/*----------------------------------------------------------------------------
+ * Frame relay mailbox.
+ *     This structure is located at offset FR50?_MBOX_OFFS into FR_MB_VECTOR.
+ *     For S502 it is also located at offset FR502_RXMB_OFFS into
+ *     FR502_RX_VECTOR.
+ */
+typedef struct fr_mbox
+{
+       unsigned char opflag    PACKED; /* 00h: execution flag */
+       fr_cmd_t cmd            PACKED; /* 01h: command block */
+       unsigned char data[1]   PACKED; /* 10h: variable length data buffer */
+} fr_mbox_t;
+
+/*----------------------------------------------------------------------------
+ * S502 frame relay status flags.
+ *     This structure is located at offset FR502_FLAG_OFFS into FR_MB_VECTOR.
+ */
+typedef struct fr502_flags
+{      
+       unsigned char rsrv1[1]  PACKED; /* 00h: */
+       unsigned char tx_ready  PACKED; /* 01h: Tx buffer available */
+       unsigned char rx_ready  PACKED; /* 02h: Rx frame available */
+       unsigned char event     PACKED; /* 03h: asynchronous event */
+       unsigned char mstatus   PACKED; /* 04h: modem status */
+       unsigned char rsrv2[8]  PACKED; /* 05h: */
+       unsigned char iflag     PACKED; /* 0Dh: interrupt flag */
+       unsigned char imask     PACKED; /* 0Eh: interrupt mask */
+} fr502_flags_t;
+
+/*----------------------------------------------------------------------------
+ * S508 frame relay status flags.
+ *     This structure is located at offset FR508_FLAG_OFFS into FR_MB_VECTOR.
+ */
+typedef struct fr508_flags
+{
+       unsigned char rsrv1[3]  PACKED; /* 00h: reserved */
+       unsigned char event     PACKED; /* 03h: asynchronous event */
+       unsigned char mstatus   PACKED; /* 04h: modem status */
+       unsigned char rsrv2[11] PACKED; /* 05h: reserved */
+       unsigned char iflag     PACKED; /* 10h: interrupt flag */
+       unsigned char imask     PACKED; /* 11h: interrupt mask */
+       unsigned long tse_offs  PACKED; /* 12h: Tx status element */
+} fr508_flags_t;
+
+/* 'event' field defines */
+#define        FR_EVENT_STATUS         0x01    /* channel status change ??? */
+#define        FR_EVENT_DLC_STATUS     0x02    /* DLC status change */
+#define        FR_EVENT_BAD_DLCI       0x04    /* FSR included wrong DLCI */
+#define        FR_EVENT_LINK_DOWN      0x40    /* DCD or CTS low */
+
+/* 'mstatus' field defines */
+#define        FR_MDM_DCD              0x08    /* mdm_status: DCD */
+#define        FR_MDM_CTS              0x20    /* mdm_status: CTS */
+
+/* 'iflag' & 'imask' fields defines */
+#define        FR_INTR_RXRDY           0x01    /* Rx ready */
+#define        FR_INTR_TXRDY           0x02    /* Tx ready */
+#define        FR_INTR_MODEM           0x04    /* modem status change (DCD, CTS) */
+#define        FR_INTR_READY           0x08    /* interface command completed */
+#define        FR_INTR_DLC             0x10    /* DLC status change */
+#define        FR_INTR_TIMER           0x20    /* millisecond timer */
+
+/*----------------------------------------------------------------------------
+ * Receive Buffer Configuration Info. S508 only!
+ *     This structure is located at offset FR508_RXBC_OFFS into FR_MB_VECTOR.
+ */
+typedef struct fr_buf_info
+{
+       unsigned short rse_num  PACKED; /* 00h: number of status elements */
+       unsigned long rse_base  PACKED; /* 02h: receive status array base */
+       unsigned long rse_next  PACKED; /* 06h: next status element */
+       unsigned long buf_base  PACKED; /* 0Ah: rotational buffer base */
+       unsigned short reserved PACKED; /* 0Eh:  */
+       unsigned long buf_top   PACKED; /* 10h: rotational buffer top */
+} fr_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * Buffer Status Element. S508 only!
+ *     Array of structures of this type is located at offset defined by the
+ *     'rse_base' field of the frBufInfo_t structure into absolute adapter
+ *     memory address space.
+ */
+typedef struct fr_buf_ctl
+{
+       unsigned char flag      PACKED; /* 00h: ready flag */
+       unsigned short length   PACKED; /* 01h: frame length */
+       unsigned short dlci     PACKED; /* 03h: DLCI */
+       unsigned char attr      PACKED; /* 05h: FECN/BECN/DE/CR */
+       unsigned short tmstamp  PACKED; /* 06h: time stamp */
+       unsigned short rsrv[2]  PACKED; /* 08h:  */
+       unsigned long offset    PACKED; /* 0Ch: buffer absolute address */
+} fr_buf_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * Global Configuration Block. Passed to FR_SET_CONFIG command when dlci == 0.
+ */
+typedef struct fr_conf
+{
+       unsigned short station  PACKED; /* 00h: CPE/Node */
+       unsigned short options  PACKED; /* 02h: configuration options */
+       unsigned short kbps     PACKED; /* 04h: baud rate in kbps */
+       unsigned short port     PACKED; /* 06h: RS-232/V.35 */
+       unsigned short mtu      PACKED; /* 08h: max. transmit length */
+       unsigned short t391     PACKED; /* 0Ah:  */
+       unsigned short t392     PACKED; /* 0Ch:  */
+       unsigned short n391     PACKED; /* 0Eh:  */
+       unsigned short n392     PACKED; /* 10h:  */
+       unsigned short n393     PACKED; /* 12h:  */
+       unsigned short cir_fwd  PACKED; /* 14h:  */
+       unsigned short bc_fwd   PACKED; /* 16h:  */
+       unsigned short be_fwd   PACKED; /* 18h:  */
+       unsigned short cir_bwd  PACKED; /* 1Ah:  */
+       unsigned short bc_bwd   PACKED; /* 1Ch:  */
+       unsigned short be_bwd   PACKED; /* 1Eh:  */
+       unsigned short dlci[0]  PACKED; /* 20h:  */
+} fr_conf_t;
+
+/* 'station_type' defines */
+#define        FRCFG_STATION_CPE       0
+#define        FRCFG_STATION_NODE      1
+
+/* 'conf_flags' defines */
+#define        FRCFG_IGNORE_TX_CIR     0x0001
+#define        FRCFG_IGNORE_RX_CIR     0x0002
+#define        FRCFG_DONT_RETRANSMIT   0x0004
+#define        FRCFG_IGNORE_CBS        0x0008
+#define        FRCFG_THROUGHPUT        0x0010  /* enable throughput calculation */
+#define        FRCFG_DIRECT_RX         0x0080  /* enable direct receive buffer */
+#define        FRCFG_AUTO_CONFIG       0x8000  /* enable  auto DLCI configuration */
+
+/* 'baud_rate' defines */
+#define        FRCFG_BAUD_1200         12
+#define        FRCFG_BAUD_2400         24
+#define        FRCFG_BAUD_4800         48
+#define        FRCFG_BAUD_9600         96
+#define        FRCFG_BAUD_19200        19
+#define        FRCFG_BAUD_38400        38
+#define        FRCFG_BAUD_56000        56
+#define        FRCFG_BAUD_64000        64
+#define        FRCFG_BAUD_128000       128
+
+/* 'port_mode' defines */
+#define        FRCFG_MODE_EXT_CLK      0x0000
+#define        FRCFG_MODE_INT_CLK      0x0001
+#define        FRCFG_MODE_V35          0x0000  /* S508 only */
+#define        FRCFG_MODE_RS232        0x0002  /* S508 only */
+
+/*----------------------------------------------------------------------------
+ * Channel configuration.
+ *     This structure is passed to the FR_SET_CONFIG command when dlci != 0.
+ */
+typedef struct fr_dlc_conf
+{
+       unsigned short conf_flags       PACKED; /* 00h: configuration bits */
+       unsigned short cir_fwd          PACKED; /* 02h:  */
+       unsigned short bc_fwd           PACKED; /* 04h:  */
+       unsigned short be_fwd           PACKED; /* 06h:  */
+       unsigned short cir_bwd          PACKED; /* 08h:  */
+       unsigned short bc_bwd           PACKED; /* 0Ah:  */
+       unsigned short be_bwd           PACKED; /* 0Ch:  */
+} fr_dlc_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S502 Interrupt mode control block.
+ *     This structure is passed to the FR_SET_INTR_FLAGS and returned by the
+ *     FR_READ_INTR_FLAGS commands.
+ */
+typedef struct fr502_intr_ctl
+{
+       unsigned char mode      PACKED; /* 00h: interrupt enable flags */
+       unsigned short tx_len   PACKED; /* 01h: required Tx buffer size */
+} fr502_intr_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Interrupt mode control block.
+ *     This structure is passed to the FR_SET_INTR_FLAGS and returned by the
+ *     FR_READ_INTR_FLAGS commands.
+ */
+typedef struct fr508_intr_ctl
+{
+       unsigned char mode      PACKED; /* 00h: interrupt enable flags */
+       unsigned short tx_len   PACKED; /* 01h: required Tx buffer size */
+       unsigned char irq       PACKED; /* 03h: IRQ level to activate */
+       unsigned char flags     PACKED; /* 04h: ?? */
+       unsigned short timeout  PACKED; /* 05h: ms, for timer interrupt */
+} fr508_intr_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * Channel Status.
+ *     This structure is returned by the FR_READ_STATUS command.
+ */
+typedef struct frDLCStatus
+{
+       unsigned char status            PACKED; /* 00h: link/DLCI status */
+       struct
+       {
+               unsigned short dlci     PACKED; /* 01h: DLCI number */
+               unsigned char status    PACKED; /* 03h: DLCI status */
+       } circuit[1]                    PACKED;
+} frDLCStatus_t;
+
+/* 'status' defines */
+#define        FR_LINK_INOPER  0x00            /* for global status (DLCI == 0) */
+#define        FR_LINK_OPER    0x01
+#define        FR_DLCI_DELETED 0x01            /* for circuit status (DLCI != 0) */
+#define        FR_DLCI_ACTIVE  0x02
+#define        FR_DLCI_WAITING 0x04
+#define        FR_DLCI_NEW     0x08
+#define        FR_DLCI_REPORT  0x40
+
+/*----------------------------------------------------------------------------
+ * Global Statistics Block.
+ *     This structure is returned by the FR_READ_STATISTICS command when
+ *     dcli == 0.
+ */
+typedef struct frLinkStat
+{
+       unsigned short rx_too_long      PACKED; /* 00h:  */
+       unsigned short rx_dropped       PACKED; /* 02h:  */
+       unsigned short rx_dropped2      PACKED; /* 04h:  */
+       unsigned short rx_bad_dlci      PACKED; /* 06h:  */
+       unsigned short rx_bad_format    PACKED; /* 08h:  */
+       unsigned short retransmitted    PACKED; /* 0Ah:  */
+       unsigned short cpe_tx_FSE       PACKED; /* 0Ch:  */
+       unsigned short cpe_tx_LIV       PACKED; /* 0Eh:  */
+       unsigned short cpe_rx_FSR       PACKED; /* 10h:  */
+       unsigned short cpe_rx_LIV       PACKED; /* 12h:  */
+       unsigned short node_rx_FSE      PACKED; /* 14h:  */
+       unsigned short node_rx_LIV      PACKED; /* 16h:  */
+       unsigned short node_tx_FSR      PACKED; /* 18h:  */
+       unsigned short node_tx_LIV      PACKED; /* 1Ah:  */
+       unsigned short rx_ISF_err       PACKED; /* 1Ch:  */
+       unsigned short rx_unsolicited   PACKED; /* 1Eh:  */
+       unsigned short rx_SSN_err       PACKED; /* 20h:  */
+       unsigned short rx_RSN_err       PACKED; /* 22h:  */
+       unsigned short T391_timeouts    PACKED; /* 24h:  */
+       unsigned short T392_timeouts    PACKED; /* 26h:  */
+       unsigned short N392_reached     PACKED; /* 28h:  */
+       unsigned short cpe_SSN_RSN      PACKED; /* 2Ah:  */
+       unsigned short current_SSN      PACKED; /* 2Ch:  */
+       unsigned short current_RSN      PACKED; /* 2Eh:  */
+       unsigned short curreny_T391     PACKED; /* 30h:  */
+       unsigned short current_T392     PACKED; /* 32h:  */
+       unsigned short current_N392     PACKED; /* 34h:  */
+       unsigned short current_N393     PACKED; /* 36h:  */
+} frLinkStat_t;
+
+/*----------------------------------------------------------------------------
+ * DLCI Statistics.
+ *     This structure is returned by the FR_READ_STATISTICS command when
+ *     dlci != 0.
+ */
+typedef struct frDLCIStat
+{
+       unsigned long tx_frames         PACKED; /* 00h:  */
+       unsigned long tx_bytes          PACKED; /* 04h:  */
+       unsigned long rx_frames         PACKED; /* 08h:  */
+       unsigned long rx_bytes          PACKED; /* 0Ch:  */
+       unsigned long rx_dropped        PACKED; /* 10h:  */
+       unsigned long rx_inactive       PACKED; /* 14h:  */
+       unsigned long rx_exceed_CIR     PACKED; /* 18h:  */
+       unsigned long rx_DE_set         PACKED; /* 1Ch:  */
+       unsigned long tx_throughput     PACKED; /* 20h:  */
+       unsigned long tx_calc_timer     PACKED; /* 24h:  */
+       unsigned long rx_throughput     PACKED; /* 28h:  */
+       unsigned long rx_calc_timer     PACKED; /* 2Ch:  */
+} frDLCIStat_t;
+
+/*----------------------------------------------------------------------------
+ * Communications Error Statistics.
+ *     This structure is returned by the FR_READ_ERROR_STATS command.
+ */
+typedef struct frCommStat
+{
+       unsigned char rx_overruns       PACKED; /* 00h:  */
+       unsigned char rx_bad_crc        PACKED; /* 01h:  */
+       unsigned char rx_aborts         PACKED; /* 02h:  */
+       unsigned char rx_too_long       PACKED; /* 03h:  */
+       unsigned char tx_aborts         PACKED; /* 04h:  */
+       unsigned char tx_underruns      PACKED; /* 05h:  */
+       unsigned char tx_missed_undr    PACKED; /* 06h:  */
+       unsigned char dcd_dropped       PACKED; /* 07h:  */
+       unsigned char cts_dropped       PACKED; /* 08h:  */
+} frCommStat_t;
+
+/*----------------------------------------------------------------------------
+ * Defines for the FR_ISSUE_IS_FRAME command.
+ */
+#define        FR_ISF_LVE      2               /* issue Link Verification Enquiry */
+#define        FR_ISF_FSE      3               /* issue Full Status Enquiry */
+
+#ifdef         _MSC_
+#  pragma      pack()
+#endif
+#endif /* _SDLA_FR_H */
+
diff --git a/include/linux/sdla_ppp.h b/include/linux/sdla_ppp.h
new file mode 100644 (file)
index 0000000..2679868
--- /dev/null
@@ -0,0 +1,536 @@
+/*****************************************************************************
+* sdla_ppp.h   Sangoma PPP firmware API definitions.
+*
+* Author:      Gene Kozin      <74604.152@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 06, 1997 Gene Kozin      v2.0
+* Apr 11, 1996 Gene Kozin      Initial version.
+*****************************************************************************/
+#ifndef        _SDLA_PPP_H
+#define        _SDLA_PPP_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.  To ensure
+ *    portability of this code between different platforms and compilers, one
+ *    of the following defines must be defined before including this file:
+ *
+ *     Compiler        Platform        Define          Use option
+ *     --------        --------        ------          ----------
+ *     GNU C           Linux           _GNUC_          -
+ *     Microsoft C     DOS/Windows     _MSC_           -
+ */
+
+#ifdef         _GNUC_
+#  ifndef      PACKED
+#    define    PACKED  __attribute__((packed))
+#  endif       /* PACKED */
+#else
+#  define      PACKED
+#endif
+#ifdef         _MSC_
+#  pragma      pack(1)
+#endif
+
+/* Adapter memory layout and important constants */
+
+#define        PPP502_MB_VECT  0xA000  /* mailbox window vector */
+#define        PPP502_MB_OFFS  0x1C00  /* mailbox offset */
+#define        PPP502_FLG_OFFS 0       /* status flags offset */
+#define        PPP502_BUF_OFFS 0x0010  /* buffer info block offset */
+
+#define        PPP508_MB_VECT  0xE000  /* mailbox window vector */
+#define        PPP508_MB_OFFS  0       /* mailbox offset */
+#define        PPP508_FLG_OFFS 0x1000  /* status flags offset */
+#define        PPP508_BUF_OFFS 0x1100  /* buffer info block offset */
+
+#define PPP_MAX_DATA   1008    /* command block data buffer length */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * PPP Command Block.
+ */
+typedef struct ppp_cmd
+{
+       unsigned char  command  PACKED; /* command code */
+       unsigned short length   PACKED; /* length of data buffer */
+       unsigned char  result   PACKED; /* return code */
+       unsigned char  rsrv[11] PACKED; /* reserved for future use */
+} ppp_cmd_t;
+
+/* 'command' field defines */
+#define PPP_READ_CODE_VERSION  0x10    /* configuration commands */
+#define PPP_SET_CONFIG         0x05
+#define PPP_READ_CONFIG                0x06
+#define        PPP_SET_INTR_FLAGS      0x20
+#define        PPP_READ_INTR_FLAGS     0x21
+#define        PPP_SET_INBOUND_AUTH    0x30
+#define        PPP_SET_OUTBOUND_AUTH   0x31
+#define        PPP_GET_CONNECTION_INFO 0x32
+
+#define PPP_COMM_ENABLE                0x03    /* operational commands */
+#define PPP_COMM_DISABLE       0x04
+#define        PPP_SEND_SIGN_FRAME     0x23
+#define        PPP_READ_SIGN_RESPONSE  0x24
+#define        PPP_DATALINE_MONITOR    0x33
+
+#define PPP_READ_STATISTICS    0x07    /* statistics commands */
+#define PPP_FLUSH_STATISTICS   0x08
+#define PPP_READ_ERROR_STATS   0x09
+#define PPP_FLUSH_ERROR_STATS  0x0A
+#define PPP_READ_PACKET_STATS  0x12
+#define PPP_FLUSH_PACKET_STATS 0x13
+#define PPP_READ_LCP_STATS     0x14
+#define PPP_FLUSH_LCP_STATS    0x15
+#define PPP_READ_LPBK_STATS    0x16
+#define PPP_FLUSH_LPBK_STATS   0x17
+#define PPP_READ_IPCP_STATS    0x18
+#define PPP_FLUSH_IPCP_STATS   0x19
+#define PPP_READ_IPXCP_STATS   0x1A
+#define PPP_FLUSH_IPXCP_STATS  0x1B
+#define PPP_READ_PAP_STATS     0x1C
+#define PPP_FLUSH_PAP_STATS    0x1D
+#define PPP_READ_CHAP_STATS    0x1E
+#define PPP_FLUSH_CHAP_STATS   0x1F
+
+/* 'result' field defines */
+#define PPPRES_OK              0x00    /* command executed successfully */
+#define        PPPRES_INVALID_STATE    0x09    /* invalid command in this context */
+
+/*----------------------------------------------------------------------------
+ * PPP Mailbox.
+ *     This structure is located at offset PPP???_MB_OFFS into PPP???_MB_VECT
+ */
+typedef struct ppp_mbox
+{
+       unsigned char flag      PACKED; /* 00h: command execution flag */
+       ppp_cmd_t     cmd       PACKED; /* 01h: command block */
+       unsigned char data[1]   PACKED; /* 10h: variable length data buffer */
+} ppp_mbox_t;
+
+/*----------------------------------------------------------------------------
+ * PPP Status Flags.
+ *     This structure is located at offset PPP???_FLG_OFFS into
+ *     PPP???_MB_VECT.
+ */
+typedef struct ppp_flags
+{
+       unsigned char iflag             PACKED; /* 00: interrupt flag */
+       unsigned char imask             PACKED; /* 01: interrupt mask */
+       unsigned char resrv             PACKED;
+       unsigned char mstatus           PACKED; /* 03: modem status */
+       unsigned char lcp_state         PACKED; /* 04: LCP state */
+       unsigned char ppp_phase         PACKED; /* 05: PPP phase */
+       unsigned char ip_state          PACKED; /* 06: IPCP state */
+       unsigned char ipx_state         PACKED; /* 07: IPXCP state */
+       unsigned char pap_state         PACKED; /* 08: PAP state */
+       unsigned char chap_state        PACKED; /* 09: CHAP state */
+       unsigned short disc_cause       PACKED; /* 0A: disconnection cause */
+} ppp_flags_t;
+
+/* 'iflag' defines */
+#define        PPP_INTR_RXRDY          0x01    /* Rx ready */
+#define        PPP_INTR_TXRDY          0x02    /* Tx ready */
+#define        PPP_INTR_MODEM          0x04    /* modem status change (DCD, CTS) */
+#define        PPP_INTR_CMD            0x08    /* interface command completed */
+#define        PPP_INTR_DISC           0x10    /* data link disconnected */
+#define        PPP_INTR_OPEN           0x20    /* data link open */
+#define        PPP_INTR_DROP_DTR       0x40    /* DTR drop timeout expired */
+
+/* 'mstatus' defines */
+#define        PPP_MDM_DCD             0x08    /* mdm_status: DCD */
+#define        PPP_MDM_CTS             0x20    /* mdm_status: CTS */
+
+/*----------------------------------------------------------------------------
+ * PPP Buffer Info.
+ *     This structure is located at offset PPP502_BUF_OFFS into
+ *     PPP502_MB_VECT.
+ */
+typedef struct ppp502_buf_info
+{
+       unsigned short txb_num  PACKED; /* 00: number of transmit buffers */
+       unsigned short txb_offs PACKED; /* 02: offset of the buffer ctl. */
+       unsigned char  rsrv1[4] PACKED;
+       unsigned short rxb_num  PACKED; /* 08: number of receive buffers */
+       unsigned short rxb_offs PACKED; /* 0A: offset of the buffer ctl. */
+       unsigned char  rsrv2[2] PACKED;
+       unsigned short rxb_next PACKED; /* 0E: index of the next buffer */
+} ppp502_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * PPP Buffer Info.
+ *     This structure is located at offset PPP508_BUF_OFFS into
+ *     PPP508_MB_VECT.
+ */
+typedef struct ppp508_buf_info
+{
+       unsigned short txb_num  PACKED; /* 00: number of transmit buffers */
+       unsigned long  txb_ptr  PACKED; /* 02: pointer to the buffer ctl. */
+       unsigned char  rsrv1[26] PACKED;
+       unsigned short rxb_num  PACKED; /* 20: number of receive buffers */
+       unsigned long  rxb_ptr  PACKED; /* 22: pointer to the buffer ctl. */
+       unsigned long  rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */
+       unsigned long  rxb_base PACKED; /* 2A: pointer to the buffer base */
+       unsigned char  rsrv2[2] PACKED;
+       unsigned long  rxb_end  PACKED; /* 30: pointer to the buffer end */
+} ppp508_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * Transmit/Receive Buffer Control Block.
+ */
+typedef struct ppp_buf_ctl
+{
+       unsigned char  flag             PACKED; /* 00: 'buffer ready' flag */
+       unsigned short length           PACKED; /* 01: length of data */
+       unsigned char  reserved1[1]     PACKED; /* 03: */
+       unsigned char  proto            PACKED; /* 04: protocol */
+       unsigned short timestamp        PACKED; /* 05: time stamp (Rx only) */
+       unsigned char  reserved2[5]     PACKED; /* 07: */
+       union
+       {
+               unsigned short o_p[2];  /* 1C: buffer offset & page (S502) */
+               unsigned long  ptr;     /* 1C: buffer pointer (S508) */
+       } buf                           PACKED;
+} ppp_buf_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * S502 Adapter Configuration Block (passed to the PPP_SET_CONFIG command).
+ */
+typedef struct ppp502_conf
+{
+       unsigned char  line_speed       PACKED; /* 00: 0 - external clk. */
+       unsigned short txbuf_num        PACKED; /* 01: number of Tx buffers */
+       unsigned short conf_flags       PACKED; /* 03: configuration bits */
+       unsigned short mtu_local        PACKED; /* 05: local MTU */
+       unsigned short mtu_remote       PACKED; /* 07: remote MTU */
+       unsigned short restart_tmr      PACKED; /* 09: restart timer */
+       unsigned short auth_rsrt_tmr    PACKED; /* 0B: authentication timer */
+       unsigned short auth_wait_tmr    PACKED; /* 0D: authentication timer */
+       unsigned short mdm_fail_tmr     PACKED; /* 0F: modem failure timer */
+       unsigned short dtr_drop_tmr     PACKED; /* 11: DTR drop timer */
+       unsigned short connect_tmout    PACKED; /* 13: connection timeout */
+       unsigned short conf_retry       PACKED; /* 15: max. retry */
+       unsigned short term_retry       PACKED; /* 17: max. retry */
+       unsigned short fail_retry       PACKED; /* 19: max. retry */
+       unsigned short auth_retry       PACKED; /* 1B: max. retry */
+       unsigned char  auth_options     PACKED; /* 1D: authentication opt. */
+       unsigned char  ip_options       PACKED; /* 1E: IP options */
+       unsigned char  ip_local[4]      PACKED; /* 1F: local IP address */
+       unsigned char  ip_remote[4]     PACKED; /* 23: remote IP address */
+       unsigned char  ipx_options      PACKED; /* 27: IPX options */
+       unsigned char  ipx_netno[4]     PACKED; /* 28: IPX net number */
+       unsigned char  ipx_local[6]     PACKED; /* 2C: local IPX node number*/
+       unsigned char  ipx_remote[6]    PACKED; /* 32: remote IPX node num.*/
+       unsigned char  ipx_router[48]   PACKED; /* 38: IPX router name*/
+} ppp502_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Configuration Block (passed to the PPP_SET_CONFIG command).
+ */
+typedef struct ppp508_conf
+{
+       unsigned long  line_speed       PACKED; /* 00: baud rate, bps */
+       unsigned short txbuf_percent    PACKED; /* 04: % of Tx buffer */
+       unsigned short conf_flags       PACKED; /* 06: configuration bits */
+       unsigned short mtu_local        PACKED; /* 08: local MTU */
+       unsigned short mtu_remote       PACKED; /* 0A: remote MTU */
+       unsigned short restart_tmr      PACKED; /* 0C: restart timer */
+       unsigned short auth_rsrt_tmr    PACKED; /* 0E: authentication timer */
+       unsigned short auth_wait_tmr    PACKED; /* 10: authentication timer */
+       unsigned short mdm_fail_tmr     PACKED; /* 12: modem failure timer */
+       unsigned short dtr_drop_tmr     PACKED; /* 14: DTR drop timer */
+       unsigned short connect_tmout    PACKED; /* 16: connection timeout */
+       unsigned short conf_retry       PACKED; /* 18: max. retry */
+       unsigned short term_retry       PACKED; /* 1A: max. retry */
+       unsigned short fail_retry       PACKED; /* 1C: max. retry */
+       unsigned short auth_retry       PACKED; /* 1E: max. retry */
+       unsigned char  auth_options     PACKED; /* 20: authentication opt. */
+       unsigned char  ip_options       PACKED; /* 21: IP options */
+       unsigned char  ip_local[4]      PACKED; /* 22: local IP address */
+       unsigned char  ip_remote[4]     PACKED; /* 26: remote IP address */
+       unsigned char  ipx_options      PACKED; /* 2A: IPX options */
+       unsigned char  ipx_netno[4]     PACKED; /* 2B: IPX net number */
+       unsigned char  ipx_local[6]     PACKED; /* 2F: local IPX node number*/
+       unsigned char  ipx_remote[6]    PACKED; /* 35: remote IPX node num.*/
+       unsigned char  ipx_router[48]   PACKED; /* 3B: IPX router name*/
+       unsigned long  alt_cpu_clock    PACKED; /* 6B:  */
+} ppp508_conf_t;
+
+/* 'line_speed' field */
+#define        PPP_BITRATE_1200        0x01
+#define        PPP_BITRATE_2400        0x02
+#define        PPP_BITRATE_4800        0x03
+#define        PPP_BITRATE_9600        0x04
+#define        PPP_BITRATE_19200       0x05
+#define        PPP_BITRATE_38400       0x06
+#define        PPP_BITRATE_45000       0x07
+#define        PPP_BITRATE_56000       0x08
+#define        PPP_BITRATE_64000       0x09
+#define        PPP_BITRATE_74000       0x0A
+#define        PPP_BITRATE_112000      0x0B
+#define        PPP_BITRATE_128000      0x0C
+#define        PPP_BITRATE_156000      0x0D
+
+/* Defines for the 'conf_flags' field */
+#define        PPP_IGNORE_TX_ABORT     0x01    /* don't re-transmit aborted frames */
+#define        PPP_ENABLE_TX_STATS     0x02    /* enable Tx statistics */
+#define        PPP_ENABLE_RX_STATS     0x04    /* enable Rx statistics */
+#define        PPP_ENABLE_TIMESTAMP    0x08    /* enable timestamp */
+
+/* 'ip_options' defines */
+#define        PPP_LOCAL_IP_LOCAL      0x01
+#define        PPP_LOCAL_IP_REMOTE     0x02
+#define        PPP_REMOTE_IP_LOCAL     0x04
+#define        PPP_REMOTE_IP_REMOTE    0x08
+
+/* 'ipx_options' defines */
+#define        PPP_REMOTE_IPX_NETNO    0x01
+#define        PPP_REMOTE_IPX_LOCAL    0x02
+#define        PPP_REMOTE_IPX_REMOTE   0x04
+#define        PPP_IPX_ROUTE_RIP_SAP   0x08
+#define        PPP_IPX_ROUTE_NLSP      0x10
+#define        PPP_IPX_ROUTE_DEFAULT   0x20
+#define        PPP_IPX_CONF_COMPLETE   0x40
+#define        PPP_IPX_ENABLE          0x80
+
+/*----------------------------------------------------------------------------
+ * S502 Adapter Configuration Block (returned by the PPP_READ_CONFIG command).
+ */
+typedef struct ppp502_get_conf
+{
+       ppp502_conf_t  conf     PACKED; /* 00: requested config. */
+       unsigned short txb_num  PACKED; /* 68: number of Tx buffers */
+       unsigned short rxb_num  PACKED; /* 6A: number of Rx buffers */
+} ppp502_get_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Configuration Block (returned by the PPP_READ_CONFIG command).
+ */
+typedef struct ppp508_get_conf
+{
+       unsigned long  bps      PACKED; /* 00: baud rate, bps */
+       ppp508_conf_t  conf     PACKED; /* 04: requested config. */
+       unsigned short txb_num  PACKED; /* 6F: number of Tx buffers */
+       unsigned short rxb_num  PACKED; /* 71: number of Rx buffers */
+} ppp508_get_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S502 Operational Statistics (returned by the PPP_READ_STATISTIC command).
+ */
+typedef struct ppp502_Stats
+{
+       unsigned short rx_lost_intr     PACKED; /* 00: */
+       unsigned short rx_lost_buff     PACKED; /* 02: */
+       unsigned short tx_abort PACKED; /* 04: */
+       unsigned long  tx_frames        PACKED; /* 06: */
+       unsigned long  tx_bytes PACKED; /* 0A: */
+       unsigned long  rx_frames        PACKED; /* 0E: */
+       unsigned long  rx_bytes PACKED; /* 12: */
+} ppp502_Stats_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Operational Statistics (returned by the PPP_READ_STATISTIC command).
+ */
+typedef struct ppp508_stats
+{
+       unsigned short reserved1        PACKED; /* 00: */
+       unsigned short rx_bad_len       PACKED; /* 02: */
+       unsigned short reserved2        PACKED; /* 04: */
+       unsigned long  tx_frames        PACKED; /* 06: */
+       unsigned long  tx_bytes PACKED; /* 0A: */
+       unsigned long  rx_frames        PACKED; /* 0E: */
+       unsigned long  rx_bytes PACKED; /* 12: */
+} ppp508_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Adapter Error Statistics (returned by the PPP_READ_ERROR_STATS command).
+ */
+typedef struct ppp_err_stats
+{
+       unsigned char    rx_overrun     PACKED; /* 00: Rx overrun errors */
+       unsigned char    rx_bad_crc     PACKED; /* 01: Rx CRC errors */
+       unsigned char    rx_abort       PACKED; /* 02: Rx aborted frames */
+       unsigned char    rx_lost        PACKED; /* 03: Rx frames lost */
+       unsigned char    tx_abort       PACKED; /* 04: Tx aborted frames */
+       unsigned char    tx_underrun    PACKED; /* 05: Tx underrun errors */
+       unsigned char    tx_missed_intr PACKED; /* 06: Tx underruns missed */
+       unsigned char    reserved       PACKED; /* 07: Tx underruns missed */
+       unsigned char    dcd_trans      PACKED; /* 08: DCD transitions */
+       unsigned char    cts_trans      PACKED; /* 09: CTS transitions */
+} ppp_err_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Packet Statistics (returned by the PPP_READ_PACKET_STATS command).
+ */
+typedef struct ppp_pkt_stats
+{
+       unsigned short rx_bad_header    PACKED; /* 00: */
+       unsigned short rx_prot_unknwn   PACKED; /* 02: */
+       unsigned short rx_too_large     PACKED; /* 04: */
+       unsigned short rx_lcp           PACKED; /* 06: */
+       unsigned short tx_lcp           PACKED; /* 08: */
+       unsigned short rx_ipcp          PACKED; /* 0A: */
+       unsigned short tx_ipcp          PACKED; /* 0C: */
+       unsigned short rx_ipxcp         PACKED; /* 0E: */
+       unsigned short tx_ipxcp         PACKED; /* 10: */
+       unsigned short rx_pap           PACKED; /* 12: */
+       unsigned short tx_pap           PACKED; /* 14: */
+       unsigned short rx_chap          PACKED; /* 16: */
+       unsigned short tx_chap          PACKED; /* 18: */
+       unsigned short rx_lqr           PACKED; /* 1A: */
+       unsigned short tx_lqr           PACKED; /* 1C: */
+       unsigned short rx_ip            PACKED; /* 1E: */
+       unsigned short tx_ip            PACKED; /* 20: */
+       unsigned short rx_ipx           PACKED; /* 22: */
+       unsigned short tx_ipx           PACKED; /* 24: */
+} ppp_pkt_stats_t;
+
+/*----------------------------------------------------------------------------
+ * LCP Statistics (returned by the PPP_READ_LCP_STATS command).
+ */
+typedef struct ppp_lcp_stats
+{
+       unsigned short rx_unknown       PACKED; /* 00: unknown LCP type */
+       unsigned short rx_conf_rqst     PACKED; /* 02: Configure-Request */
+       unsigned short rx_conf_ack      PACKED; /* 04: Configure-Ack */
+       unsigned short rx_conf_nak      PACKED; /* 06: Configure-Nak */
+       unsigned short rx_conf_rej      PACKED; /* 08: Configure-Reject */
+       unsigned short rx_term_rqst     PACKED; /* 0A: Terminate-Request */
+       unsigned short rx_term_ack      PACKED; /* 0C: Terminate-Ack */
+       unsigned short rx_code_rej      PACKED; /* 0E: Code-Reject */
+       unsigned short rx_proto_rej     PACKED; /* 10: Protocol-Reject */
+       unsigned short rx_echo_rqst     PACKED; /* 12: Echo-Request */
+       unsigned short rx_echo_reply    PACKED; /* 14: Echo-Reply */
+       unsigned short rx_disc_rqst     PACKED; /* 16: Discard-Request */
+       unsigned short tx_conf_rqst     PACKED; /* 18: Configure-Request */
+       unsigned short tx_conf_ack      PACKED; /* 1A: Configure-Ack */
+       unsigned short tx_conf_nak      PACKED; /* 1C: Configure-Nak */
+       unsigned short tx_conf_rej      PACKED; /* 1E: Configure-Reject */
+       unsigned short tx_term_rqst     PACKED; /* 20: Terminate-Request */
+       unsigned short tx_term_ack      PACKED; /* 22: Terminate-Ack */
+       unsigned short tx_code_rej      PACKED; /* 24: Code-Reject */
+       unsigned short tx_proto_rej     PACKED; /* 26: Protocol-Reject */
+       unsigned short tx_echo_rqst     PACKED; /* 28: Echo-Request */
+       unsigned short tx_echo_reply    PACKED; /* 2A: Echo-Reply */
+       unsigned short tx_disc_rqst     PACKED; /* 2E: Discard-Request */
+       unsigned short rx_too_large     PACKED; /* 30: packets too large */
+       unsigned short rx_ack_inval     PACKED; /* 32: invalid Conf-Ack */
+       unsigned short rx_rej_inval     PACKED; /* 34: invalid Conf-Reject */
+       unsigned short rx_rej_badid     PACKED; /* 36: Conf-Reject w/bad ID */
+} ppp_lcp_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Loopback Error Statistics (returned by the PPP_READ_LPBK_STATS command).
+ */
+typedef struct ppp_lpbk_stats
+{
+       unsigned short conf_magic       PACKED; /* 00:  */
+       unsigned short loc_echo_rqst    PACKED; /* 02:  */
+       unsigned short rem_echo_rqst    PACKED; /* 04:  */
+       unsigned short loc_echo_reply   PACKED; /* 06:  */
+       unsigned short rem_echo_reply   PACKED; /* 08:  */
+       unsigned short loc_disc_rqst    PACKED; /* 0A:  */
+       unsigned short rem_disc_rqst    PACKED; /* 0C:  */
+       unsigned short echo_tx_collsn   PACKED; /* 0E:  */
+       unsigned short echo_rx_collsn   PACKED; /* 10:  */
+} ppp_lpbk_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Protocol Statistics (returned by the PPP_READ_IPCP_STATS and
+ * PPP_READ_IPXCP_STATS commands).
+ */
+typedef struct ppp_prot_stats
+{
+       unsigned short rx_unknown       PACKED; /* 00: unknown type */
+       unsigned short rx_conf_rqst     PACKED; /* 02: Configure-Request */
+       unsigned short rx_conf_ack      PACKED; /* 04: Configure-Ack */
+       unsigned short rx_conf_nak      PACKED; /* 06: Configure-Nak */
+       unsigned short rx_conf_rej      PACKED; /* 08: Configure-Reject */
+       unsigned short rx_term_rqst     PACKED; /* 0A: Terminate-Request */
+       unsigned short rx_term_ack      PACKED; /* 0C: Terminate-Ack */
+       unsigned short rx_code_rej      PACKED; /* 0E: Code-Reject */
+       unsigned short reserved         PACKED; /* 10: */
+       unsigned short tx_conf_rqst     PACKED; /* 12: Configure-Request */
+       unsigned short tx_conf_ack      PACKED; /* 14: Configure-Ack */
+       unsigned short tx_conf_nak      PACKED; /* 16: Configure-Nak */
+       unsigned short tx_conf_rej      PACKED; /* 18: Configure-Reject */
+       unsigned short tx_term_rqst     PACKED; /* 1A: Terminate-Request */
+       unsigned short tx_term_ack      PACKED; /* 1C: Terminate-Ack */
+       unsigned short tx_code_rej      PACKED; /* 1E: Code-Reject */
+       unsigned short rx_too_large     PACKED; /* 20: packets too large */
+       unsigned short rx_ack_inval     PACKED; /* 22: invalid Conf-Ack */
+       unsigned short rx_rej_inval     PACKED; /* 24: invalid Conf-Reject */
+       unsigned short rx_rej_badid     PACKED; /* 26: Conf-Reject w/bad ID */
+} ppp_prot_stats_t;
+
+/*----------------------------------------------------------------------------
+ * PAP Statistics (returned by the PPP_READ_PAP_STATS command).
+ */
+typedef struct ppp_pap_stats
+{
+       unsigned short rx_unknown       PACKED; /* 00: unknown type */
+       unsigned short rx_auth_rqst     PACKED; /* 02: Authenticate-Request */
+       unsigned short rx_auth_ack      PACKED; /* 04: Authenticate-Ack */
+       unsigned short rx_auth_nak      PACKED; /* 06: Authenticate-Nak */
+       unsigned short reserved         PACKED; /* 08: */
+       unsigned short tx_auth_rqst     PACKED; /* 0A: Authenticate-Request */
+       unsigned short tx_auth_ack      PACKED; /* 0C: Authenticate-Ack */
+       unsigned short tx_auth_nak      PACKED; /* 0E: Authenticate-Nak */
+       unsigned short rx_too_large     PACKED; /* 10: packets too large */
+       unsigned short rx_bad_peerid    PACKED; /* 12: invalid peer ID */
+       unsigned short rx_bad_passwd    PACKED; /* 14: invalid password */
+} ppp_pap_stats_t;
+
+/*----------------------------------------------------------------------------
+ * CHAP Statistics (returned by the PPP_READ_CHAP_STATS command).
+ */
+typedef struct ppp_chap_stats
+{
+       unsigned short rx_unknown       PACKED; /* 00: unknown type */
+       unsigned short rx_challenge     PACKED; /* 02: Authenticate-Request */
+       unsigned short rx_response      PACKED; /* 04: Authenticate-Ack */
+       unsigned short rx_success       PACKED; /* 06: Authenticate-Nak */
+       unsigned short rx_failure       PACKED; /* 08: Authenticate-Nak */
+       unsigned short reserved         PACKED; /* 0A: */
+       unsigned short tx_challenge     PACKED; /* 0C: Authenticate-Request */
+       unsigned short tx_response      PACKED; /* 0E: Authenticate-Ack */
+       unsigned short tx_success       PACKED; /* 10: Authenticate-Nak */
+       unsigned short tx_failure       PACKED; /* 12: Authenticate-Nak */
+       unsigned short rx_too_large     PACKED; /* 14: packets too large */
+       unsigned short rx_bad_peerid    PACKED; /* 16: invalid peer ID */
+       unsigned short rx_bad_passwd    PACKED; /* 18: invalid password */
+       unsigned short rx_bad_md5       PACKED; /* 1A: invalid MD5 format */
+       unsigned short rx_bad_resp      PACKED; /* 1C: invalid response */
+} ppp_chap_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Connection Information (returned by the PPP_GET_CONNECTION_INFO command).
+ */
+typedef struct ppp_conn_info
+{
+       unsigned short remote_mru       PACKED; /* 00:  */
+       unsigned char  ip_options       PACKED; /* 02:  */
+       unsigned char  ip_local[4]      PACKED; /* 03:  */
+       unsigned char  ip_remote[4]     PACKED; /* 07:  */
+       unsigned char  ipx_options      PACKED; /* 0B:  */
+       unsigned char  ipx_network[4]   PACKED; /* 0C:  */
+       unsigned char  ipx_local[6]     PACKED; /* 10:  */
+       unsigned char  ipx_remote[6]    PACKED; /* 16:  */
+       unsigned char  ipx_router[48]   PACKED; /* 1C:  */
+       unsigned char  auth_status      PACKED; /* 4C:  */
+       unsigned char  peer_id[0]       PACKED; /* 4D:  */
+} ppp_conn_info_t;
+
+#ifdef         _MSC_
+#  pragma      pack()
+#endif
+#endif /* _SDLA_PPP_H */
diff --git a/include/linux/sdla_x25.h b/include/linux/sdla_x25.h
new file mode 100644 (file)
index 0000000..424e9fe
--- /dev/null
@@ -0,0 +1,624 @@
+/*****************************************************************************
+* sdla_x25.h   Sangoma X.25 firmware API definitions.
+*
+* Author:      Gene Kozin      <74604.152@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 13, 1996 Gene Kozin      Initial version
+*****************************************************************************/
+#ifndef        _SDLA_X25_H
+#define        _SDLA_X25_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.  To ensure
+ *    portability of this code between different platforms and compilers, one
+ *    of the following defines must be defined before including this file:
+ *
+ *     Compiler        Platform        Define          Use option
+ *     --------        --------        ------          ----------
+ *     GNU C           Linux           _GNUC_          -
+ *     Microsoft C     DOS/Windows     _MSC_           -
+ *
+ */
+
+#ifdef         _GNUC_
+#  ifndef      PACKED
+#    define    PACKED  __attribute__((packed))
+#  endif       /* PACKED */
+#else
+#  define      PACKED
+#endif
+#ifdef         _MSC_
+#  pragma      pack(1)
+#endif
+
+/******        CONSTANTS DEFINITIONS ***********************************************/
+
+#define        X25_MAX_CHAN    255     /* max number of open X.25 circuits */
+#define        X25_MAX_DATA    1024    /* max length of X.25 data buffer */
+
+/*
+ * X.25 shared memory layout.
+ */
+#define        X25_MBOX_OFFS   0x16B0  /* general mailbox block */
+#define        X25_RXMBOX_OFFS 0x1AD0  /* receive mailbox */
+#define        X25_STATUS_OFFS 0x1EF0  /* X.25 status structure */
+
+/****** DATA STRUCTURES *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * X.25 Command Block.
+ */
+typedef struct X25Cmd
+{
+       unsigned char command   PACKED; /* command code */
+       unsigned short length   PACKED; /* transfer data length */
+       unsigned char result    PACKED; /* return code */
+       unsigned char pf        PACKED; /* P/F bit */
+       unsigned short lcn      PACKED; /* logical channel */
+       unsigned char qdm       PACKED; /* Q/D/M bits */
+       unsigned char cause     PACKED; /* cause field */
+       unsigned char diagn     PACKED; /* diagnostics */
+       unsigned char pktType   PACKED; /* packet type */
+       unsigned char resrv[4]  PACKED; /* reserved */
+} TX25Cmd;
+
+/*
+ * Defines for the 'command' field.
+ */
+/*----- General commands --------------*/
+#define X25_SET_GLOBAL_VARS    0x0B    /* set global variables */ 
+#define X25_READ_MODEM_STATUS  0x0C    /* read modem status */
+#define X25_READ_CODE_VERSION  0x15    /* read firmware version number */
+#define X25_TRACE_CONFIGURE    0x14    /* configure trace facility */
+#define X25_READ_TRACE_DATA    0x16    /* read trace data */
+#define        X25_SET_INTERRUPT_MODE  0x17    /* set interrupt generation mode */
+#define        X25_READ_INTERRUPT_MODE 0x18    /* read interrupt generation mode */
+/*----- HDLC-level commands -----------*/
+#define X25_HDLC_LINK_CONFIGURE        0x01    /* configure HDLC link level */   
+#define X25_HDLC_LINK_OPEN     0x02    /* open HDLC link */            
+#define X25_HDLC_LINK_CLOSE    0x03    /* close HDLC link */
+#define X25_HDLC_LINK_SETUP    0x04    /* set up HDLC link */ 
+#define X25_HDLC_LINK_DISC     0x05    /* disconnect DHLC link */
+#define X25_HDLC_LINK_STATUS   0x06    /* read DHLC link status */
+#define X25_HDLC_READ_STATS    0x07    /* read operational statistics */
+#define X25_HDLC_FLUSH_STATS   0x08    /* flush operational statistics */
+#define X25_HDLC_READ_COMM_ERR 0x09    /* read error statistics */
+#define X25_HDLC_FLUSH_COMM_ERR        0x0A    /* flush error statistics */
+#define X25_HDLC_FLUSH_BUFFERS 0x0D    /* flush HDLC-level data buffers */
+#define X25_HDLC_SPRVS_CNT_STAT 0x0F   /* read surervisory count status */
+#define X25_HDLC_SEND_UI_FRAME 0x10    /* send unnumbered information frame */
+#define X25_HDLC_WRITE         0x11    /* send HDLC information frame */
+#define X25_HDLC_READ          0x21    /* read HDLC information frame */
+#define X25_HDLC_READ_CONFIG   0x12    /* read HDLC configuration */
+#define X25_HDLC_SET_CONFIG    0x13    /* set HDLC configuration */
+/*----- X.25-level commands -----------*/
+#define X25_READ               0x22    /* read X.25 packet */
+#define X25_WRITE              0x23    /* send X.25 packet */
+#define X25_PLACE_CALL         0x30    /* place a call on SVC */
+#define X25_ACCEPT_CALL                0x31    /* accept incomming call */
+#define X25_CLEAR_CALL         0x32    /* clear call */
+#define X25_CLEAR_CONFRM       0x33    /* send clear confirmation packet */
+#define X25_RESET              0x34    /* send reset request packet */
+#define X25_RESET_CONFRM       0x35    /* send reset confirmation packet */
+#define X25_RESTART            0x36    /* send restart request packet */
+#define X25_RESTART_CONFRM     0x37    /* send restart confirmation packet */
+#define X25_INTERRUPT          0x38    /* send interrupt request packet */
+#define X25_INTERRUPT_CONFRM   0x39    /* send interrupt confirmation pkt */
+#define X25_REGISTRATION_RQST  0x3A    /* send registration request packet */
+#define X25_REGISTRATION_CONFRM        0x3B    /* send registration confirmation */
+#define X25_IS_DATA_AVAILABLE  0x40    /* querry receive queue */
+#define X25_INCOMMING_CALL_CTL 0x41    /* select incomming call options */
+#define X25_CONFIGURE_PVC      0x42    /* configure PVC */
+#define X25_GET_ACTIVE_CHANNELS        0x43    /* get a list of active circuits */
+#define X25_READ_CHANNEL_CONFIG        0x44    /* read virt. circuit configuration */
+#define X25_FLUSH_DATA_BUFFERS 0x45    /* flush X.25-level data buffers */
+#define X25_READ_HISTORY_TABLE 0x46    /* read asynchronous event log */
+#define X25_HISTORY_TABLE_CTL  0x47    /* control asynchronous event log */
+#define        X25_GET_TX_D_BIT_STATUS 0x48    /* is packet with D-bit acknowleged */
+#define        X25_READ_STATISTICS     0x49    /* read X.25-level statistics */
+#define        X25_FLUSH_STATISTICS    0x4A    /* flush X.25-level statistics */
+#define        X25_READ_CONFIGURATION  0x50    /* read HDLC & X.25 configuration */
+#define        X25_SET_CONFIGURATION   0x51    /* set HDLC & X.25 configuration */
+
+/*
+ * Defines for the 'result' field.
+ */
+/*----- General results ---------------*/
+#define X25RES_OK              0x00
+#define X25RES_ERROR           0x01
+#define X25RES_LINK_NOT_IN_ABM 0x02    /* link is not in ABM mode */
+#define X25RES_LINK_CLOSED     0x03
+#define X25RES_INVAL_LENGTH    0x04
+#define X25RES_INVAL_CMD       0x05
+#define X25RES_UNNUMBERED_FRAME        0x06    /* unnunbered frame received */
+#define X25RES_FRM_REJECT_MODE 0x07    /* link is in Frame Reject mode */
+#define X25RES_MODEM_FAILURE   0x08    /* DCD and/or CTS dropped */
+#define X25RES_N2_RETRY_LIMIT  0x09    /* N2 retry limit has been exceeded */
+#define X25RES_INVAL_LCN       0x30    /* invalid logical channel number */
+#define X25RES_INVAL_STATE     0x31    /* channel is not in data xfer mode */
+#define X25RES_INVAL_DATA_LEN  0x32    /* invalid data length */
+#define X25RES_NOT_READY       0x33    /* no data available / buffers full */
+#define X25RES_NETWORK_DOWN    0x34
+#define X25RES_CHANNEL_IN_USE  0x35    /* there is data queued on this LCN */
+#define X25RES_REGST_NOT_SUPPRT        0x36    /* registration not supported */
+#define X25RES_INVAL_FORMAT    0x37    /* invalid packet format */
+#define X25RES_D_BIT_NOT_SUPPRT        0x38    /* D-bit pragmatics not supported */
+#define X25RES_FACIL_NOT_SUPPRT        0x39    /* Call facility not supported */
+#define X25RES_INVAL_CALL_ARG  0x3A    /* errorneous call arguments */
+#define X25RES_INVAL_CALL_DATA 0x3B    /* errorneous call user data */
+#define X25RES_ASYNC_PACKET    0x40    /* asynchronous packet received */
+#define X25RES_PROTO_VIOLATION 0x41    /* protocol violation occured */
+#define X25RES_PKT_TIMEOUT     0x42    /* X.25 packet time out */
+#define X25RES_PKT_RETRY_LIMIT 0x43    /* X.25 packet retry limit exceeded */
+/*----- Command-dependant results -----*/
+#define X25RES_LINK_DISC       0x00    /* HDLC_LINK_STATUS */
+#define X25RES_LINK_IN_ABM     0x01    /* HDLC_LINK_STATUS */
+#define X25RES_NO_DATA         0x01    /* HDLC_READ/READ_TRACE_DATA*/
+#define X25RES_TRACE_INACTIVE  0x02    /* READ_TRACE_DATA */
+#define X25RES_LINK_IS_OPEN    0x01    /* HDLC_LINK_OPEN */
+#define X25RES_LINK_IS_DISC    0x02    /* HDLC_LINK_DISC */
+#define X25RES_LINK_IS_CLOSED  0x03    /* HDLC_LINK_CLOSE */
+#define X25RES_INVAL_PARAM     0x31    /* INCOMMING_CALL_CTL */
+#define X25RES_INVAL_CONFIG    0x35    /* REGISTR_RQST/CONFRM */
+
+/*
+ * Defines for the 'qdm_bits' field.
+ */
+#define X25CMD_Q_BIT_MASK      0x04
+#define X25CMD_D_BIT_MASK      0x02
+#define X25CMD_M_BIT_MASK      0x01
+
+/*
+ * Defines for the 'pkt_type' field.
+ */
+/*----- Asynchronous events ------*/
+#define ASE_CLEAR_RQST         0x02
+#define ASE_RESET_RQST         0x04
+#define ASE_RESTART_RQST       0x08
+#define ASE_INTERRUPT          0x10
+#define ASE_DTE_REGISTR_RQST   0x20
+#define ASE_CALL_RQST          0x30
+#define ASE_CALL_ACCEPTED      0x31
+#define ASE_CLEAR_CONFRM       0x32
+#define ASE_RESET_CONFRM       0x33
+#define ASE_RESTART_CONFRM     0x34
+#define ASE_INTERRUPT_CONFRM   0x35
+#define ASE_DCE_REGISTR_CONFRM 0x36
+#define ASE_DIAGNOSTIC         0x37
+#define ASE_CALL_AUTO_CLEAR    0x38
+#define AUTO_RESPONSE_FLAG     0x80
+/*----- Time-Out events ----------*/
+#define TOE_RESTART_RQST       0x03
+#define TOE_CALL_RQST          0x05
+#define TOE_CLEAR_RQST         0x08
+#define TOE_RESET_RQST         0x0A
+/*----- Protocol Violation events */
+#define PVE_CLEAR_RQST         0x32
+#define PVE_RESET_RQST         0x33
+#define PVE_RESTART_RQST       0x34
+#define PVE_DIAGNOSTIC         0x37
+
+/*----------------------------------------------------------------------------
+ * X.25 Mailbox.
+ *     This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS
+ *     into shared memory window.
+ */
+typedef struct X25Mbox
+{
+       unsigned char opflag    PACKED; /* 00h: execution flag */
+       TX25Cmd cmd             PACKED; /* 01h: command block */
+       unsigned char data[1]   PACKED; /* 10h: data buffer */
+} TX25Mbox;
+
+/*----------------------------------------------------------------------------
+ * X.25 Time Stamp Structure.
+ */
+typedef struct X25TimeStamp
+{
+       unsigned char month     PACKED;
+       unsigned char date      PACKED;
+       unsigned char sec       PACKED;
+       unsigned char min       PACKED;
+       unsigned char hour      PACKED;
+} TX25TimeStamp;
+
+/*----------------------------------------------------------------------------
+ * X.25 Status Block.
+ *     This structure is located at offset X25_STATUS_OFF into shared memory
+ *     window.
+ */
+typedef struct X25Status
+{
+       unsigned short pvc_map  PACKED; /* 00h: PVC map */
+       unsigned short icc_map  PACKED; /* 02h: Incomming Chan. map */
+       unsigned short twc_map  PACKED; /* 04h: Two-way Cnan. map */
+       unsigned short ogc_map  PACKED; /* 06h: Outgoing Chan. map */
+       TX25TimeStamp tstamp    PACKED; /* 08h: timestamp (BCD) */
+       unsigned char iflags    PACKED; /* 0Dh: interrupt flags */
+       unsigned char resrv[2]  PACKED; /* 0Eh: */
+       unsigned char gflags    PACKED; /* 10h: misc. HDLC/X25 flags */
+       unsigned char cflags[X25_MAX_CHAN] PACKED; /* channel status bytes */
+} TX25Status;
+
+/*
+ * Bitmasks for the 'iflags' field.
+ */
+#define X25_RX_INTR    0x01    /* receive interrupt */
+#define X25_TX_INTR    0x02    /* transmit interrupt */
+#define X25_MODEM_INTR 0x04    /* modem status interrupt (CTS/DCD) */
+#define X25_EVENT_INTR 0x10    /* asyncronous event encountered */
+#define X25_CMD_INTR   0x08    /* interface command complete */
+
+/*
+ * Bitmasks for the 'gflags' field.
+ */
+#define X25_HDLC_ABM   0x01    /* HDLC is in ABM mode */
+#define X25_RX_READY   0x02    /* X.25 data available */
+#define X25_TRACE_READY        0x08    /* trace data available */
+#define X25_EVENT_IND  0x20    /* asynchronous event indicator */
+#define X25_TX_READY   0x40    /* space is available in Tx buf.*/
+
+/*
+ * Bitmasks for the 'cflags' field.
+ */
+#define X25_XFER_MODE  0x80    /* channel is in data transfer mode */
+#define X25_TXWIN_OPEN 0x40    /* transmit window open */
+#define X25_RXBUF_MASK 0x3F    /* number of data buffers available */
+
+/*****************************************************************************
+ * Following definitions structurize contents of the TX25Mbox.data field for
+ * different X.25 interface commands.
+ ****************************************************************************/
+
+/* ---------------------------------------------------------------------------
+ * X25_SET_GLOBAL_VARS Command.
+ */
+typedef struct X25GlobalVars
+{
+       unsigned char resrv     PACKED; /* 00h: reserved */
+       unsigned char dtrCtl    PACKED; /* 01h: DTR control code */
+       unsigned char resErr    PACKED; /* 01h: '1' - reset modem error */
+} TX25GlobalVars;
+
+/*
+ * Defines for the 'dtrCtl' field.
+ */
+#define X25_RAISE_DTR  0x01
+#define X25_DROP_DTR   0x02
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_MODEM_STATUS Command.
+ */
+typedef struct X25ModemStatus
+{
+       unsigned char   status  PACKED;         /* 00h: modem status */
+} TX25ModemStatus;
+
+/*
+ * Defines for the 'status' field.
+ */
+#define X25_CTS_MASK   0x20
+#define X25_DCD_MASK   0x08
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_LINK_STATUS Command.
+ */
+typedef struct X25LinkStatus
+{
+       unsigned char txQueued  PACKED; /* 00h: queued Tx I-frames*/
+       unsigned char rxQueued  PACKED; /* 01h: queued Rx I-frames*/
+       unsigned char station   PACKED; /* 02h: DTE/DCE config. */
+       unsigned char reserved  PACKED; /* 03h: reserved */
+       unsigned char sfTally   PACKED; /* 04h: supervisory frame tally */
+} TX25LinkStatus;
+
+/*
+ * Defines for the 'station' field.
+ */
+#define        X25_STATION_DTE 0x01    /* station configured as DTE */
+#define X25_STATION_DCE        0x02    /* station configured as DCE */
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_READ_STATS Command.
+ */
+typedef struct HdlcStats
+{                                              /*      a number of ... */
+       unsigned short rxIFrames        PACKED; /* 00h: ready Rx I-frames */
+       unsigned short rxNoseq          PACKED; /* 02h: frms out-of-sequence */
+       unsigned short rxNodata         PACKED; /* 04h: I-frms without data */
+       unsigned short rxDiscarded      PACKED; /* 06h: discarded frames */
+       unsigned short rxTooLong        PACKED; /* 08h: frames too long */
+       unsigned short rxBadAddr        PACKED; /* 0Ah: frms with inval.addr*/
+       unsigned short txAcked          PACKED; /* 0Ch: acknowledged I-frms */
+       unsigned short txRetransm       PACKED; /* 0Eh: re-transmit. I-frms */
+       unsigned short t1Timeout        PACKED; /* 10h: T1 timeouts */
+       unsigned short rxSABM           PACKED; /* 12h: received SABM frames */
+       unsigned short rxDISC           PACKED; /* 14h: received DISC frames */
+       unsigned short rxDM             PACKED; /* 16h: received DM frames */
+       unsigned short rxFRMR           PACKED; /* 18h: FRMR frames received */
+       unsigned short txSABM           PACKED; /* 1Ah: transm. SABM frames*/
+       unsigned short txDISC           PACKED; /* 1Ch: transm. DISC frames*/
+       unsigned short txDM             PACKED; /* 1Eh: transm. DM frames */
+       unsigned short txFRMR           PACKED; /* 20h: transm. FRMR frames*/
+} THdlcStats;
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_READ_COMM_ERR Command.
+ */
+typedef struct HdlcCommErr
+{                                              /*      a number of ... */
+       unsigned char rxOverrun         PACKED; /* 00h: Rx overrun errors */
+       unsigned char rxBadCrc          PACKED; /* 01h: Rx CRC errors */
+       unsigned char rxAborted         PACKED; /* 02h: Rx aborted frames */
+       unsigned char rxDropped         PACKED; /* 03h: frames lost */
+       unsigned char txAborted         PACKED; /* 04h: Tx aborted frames */
+       unsigned char txUnderrun        PACKED; /* 05h: Tx underrun errors */
+       unsigned char txMissIntr        PACKED; /* 06h: missed underrun ints */
+       unsigned char reserved          PACKED; /* 07h: reserved */
+       unsigned char droppedDCD        PACKED; /* 08h: times DCD dropped */
+       unsigned char droppedCTS        PACKED; /* 09h: times CTS dropped */
+} THdlcCommErr;
+
+/* ---------------------------------------------------------------------------
+ * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands.
+ */
+typedef struct X25Config
+{
+       unsigned char baudRate          PACKED; /* 00h:  */
+       unsigned char t1                PACKED; /* 01h:  */
+       unsigned char t2                PACKED; /* 02h:  */
+       unsigned char n2                PACKED; /* 03h:  */
+       unsigned short hdlcMTU          PACKED; /* 04h:  */
+       unsigned char hdlcWindow        PACKED; /* 06h:  */
+       unsigned char t4                PACKED; /* 07h:  */
+       unsigned char autoModem         PACKED; /* 08h:  */
+       unsigned char autoHdlc          PACKED; /* 09h:  */
+       unsigned char hdlcOptions       PACKED; /* 0Ah:  */
+       unsigned char station           PACKED; /* 0Bh:  */
+       unsigned char pktWindow         PACKED; /* 0Ch:  */
+       unsigned short defPktSize       PACKED; /* 0Dh:  */
+       unsigned short pktMTU           PACKED; /* 0Fh:  */
+       unsigned short loPVC            PACKED; /* 11h:  */
+       unsigned short hiPVC            PACKED; /* 13h:  */
+       unsigned short loIncommingSVC   PACKED; /* 15h:  */
+       unsigned short hiIncommingSVC   PACKED; /* 17h:  */
+       unsigned short loTwoWaySVC      PACKED; /* 19h:  */
+       unsigned short hiTwoWaySVC      PACKED; /* 1Bh:  */
+       unsigned short loOutgoingSVC    PACKED; /* 1Dh:  */
+       unsigned short hiOutgoingSVC    PACKED; /* 1Fh:  */
+       unsigned short options          PACKED; /* 21h:  */
+       unsigned char responseOpt       PACKED; /* 23h:  */
+       unsigned short facil1           PACKED; /* 24h:  */
+       unsigned short facil2           PACKED; /* 26h:  */
+       unsigned short ccittFacil       PACKED; /* 28h:  */
+       unsigned short otherFacil       PACKED; /* 2Ah:  */
+       unsigned short ccittCompat      PACKED; /* 2Ch:  */
+       unsigned char t10t20            PACKED; /* 2Eh:  */
+       unsigned char t11t21            PACKED; /* 2Fh:  */
+       unsigned char t12t22            PACKED; /* 30h:  */
+       unsigned char t13t23            PACKED; /* 31h:  */
+       unsigned char t16t26            PACKED; /* 32H:  */
+       unsigned char t28               PACKED; /* 33h:  */
+       unsigned char r10r20            PACKED; /* 34h:  */
+       unsigned char r12r22            PACKED; /* 35h:  */
+       unsigned char r13r23            PACKED; /* 36h:  */
+} TX25Config;
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_CHANNEL_CONFIG Command.
+ */
+typedef struct X25ChanAlloc                    /*----- Channel allocation -*/
+{
+       unsigned short loPVC            PACKED; /* 00h: lowest PVC number */
+       unsigned short hiPVC            PACKED; /* 02h: highest PVC number */
+       unsigned short loIncommingSVC   PACKED; /* 04h: lowest incoming SVC */
+       unsigned short hiIncommingSVC   PACKED; /* 06h: highest incoming SVC */
+       unsigned short loTwoWaySVC      PACKED; /* 08h: lowest two-way SVC */
+       unsigned short hiTwoWaySVC      PACKED; /* 0Ah: highest two-way SVC */
+       unsigned short loOutgoingSVC    PACKED; /* 0Ch: lowest outgoing SVC */
+       unsigned short hiOutgoingSVC    PACKED; /* 0Eh: highest outgoing SVC */
+} TX25ChanAlloc;
+
+typedef struct X25ChanCfg              /*------ Channel configuration -----*/
+{
+       unsigned char type      PACKED; /* 00h: channel type */
+       unsigned char txConf    PACKED; /* 01h: Tx packet and window sizes */
+       unsigned char rxConf    PACKED; /* 01h: Rx packet and window sizes */
+} TX25ChanCfg;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define        X25_PVC         0x01    /* PVC */
+#define        X25_SVC_IN      0x03    /* Incoming SVC */
+#define        X25_SVC_TWOWAY  0x07    /* Two-way SVC */
+#define        X25_SVC_OUT     0x0B    /* Outgoing SVC */
+
+/*----------------------------------------------------------------------------
+ * X25_READ_STATISTICS Command.
+ */
+typedef struct X25Stats
+{                                              /* number of packets Tx/Rx'ed */
+       unsigned short txRestartRqst    PACKED; /* 00h: Restart Request */
+       unsigned short rxRestartRqst    PACKED; /* 02h: Restart Request */
+       unsigned short txRestartConf    PACKED; /* 04h: Restart Confirmation */
+       unsigned short rxRestartConf    PACKED; /* 06h: Restart Confirmation */
+       unsigned short txResetRqst      PACKED; /* 08h: Reset Request */
+       unsigned short rxResetRqst      PACKED; /* 0Ah: Reset Request */
+       unsigned short txResetConf      PACKED; /* 0Ch: Reset Confirmation */
+       unsigned short rxResetConf      PACKED; /* 0Eh: Reset Confirmation */
+       unsigned short txCallRequest    PACKED; /* 10h: Call Request */
+       unsigned short rxCallRequest    PACKED; /* 12h: Call Request */
+       unsigned short txCallAccept     PACKED; /* 14h: Call Accept */
+       unsigned short rxCallAccept     PACKED; /* 16h: Call Accept */
+       unsigned short txClearRqst      PACKED; /* 18h: Clear Request */
+       unsigned short rxClearRqst      PACKED; /* 1Ah: Clear Request */
+       unsigned short txClearConf      PACKED; /* 1Ch: Clear Confirmation */
+       unsigned short rxClearConf      PACKED; /* 1Eh: Clear Confirmation */
+       unsigned short txDiagnostic     PACKED; /* 20h: Diagnostic */
+       unsigned short rxDiagnostic     PACKED; /* 22h: Diagnostic */
+       unsigned short txRegRqst        PACKED; /* 24h: Registration Request */
+       unsigned short rxRegRqst        PACKED; /* 26h: Registration Request */
+       unsigned short txRegConf        PACKED; /* 28h: Registration Confirm.*/
+       unsigned short rxRegConf        PACKED; /* 2Ah: Registration Confirm.*/
+       unsigned short txInterrupt      PACKED; /* 2Ch: Interrupt */
+       unsigned short rxInterrupt      PACKED; /* 2Eh: Interrupt */
+       unsigned short txIntrConf       PACKED; /* 30h: Interrupt Confirm. */
+       unsigned short rxIntrConf       PACKED; /* 32h: Interrupt Confirm. */
+       unsigned short txData           PACKED; /* 34h: Data */
+       unsigned short rxData           PACKED; /* 36h: Data */
+       unsigned short txRR             PACKED; /* 38h: RR */
+       unsigned short rxRR             PACKED; /* 3Ah: RR */
+       unsigned short txRNR            PACKED; /* 3Ch: RNR */
+       unsigned short rxRNR            PACKED; /* 3Eh: RNR */
+} X25Stats;
+
+/*----------------------------------------------------------------------------
+ * X25_READ_HISTORY_TABLE Command.
+ */
+typedef struct X25EventLog
+{
+       unsigned char   type    PACKED; /* 00h: transaction type */
+       unsigned short  lcn     PACKED; /* 01h: logical channel num */
+       unsigned char   packet  PACKED; /* 03h: async packet type */
+       unsigned char   cause   PACKED; /* 04h: X.25 cause field */
+       unsigned char   diag    PACKED; /* 05h: X.25 diag field */
+       TX25TimeStamp   ts      PACKED; /* 06h: time stamp */
+} TX25EventLog;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25LOG_INCOMMING       0x00
+#define X25LOG_APPLICATION     0x01
+#define X25LOG_AUTOMATIC       0x02
+#define X25LOG_ERROR           0x04
+#define X25LOG_TIMEOUT         0x08
+#define X25LOG_RECOVERY                0x10
+
+/*
+ * Defines for the 'packet' field.
+ */
+#define X25LOG_CALL_RQST       0x0B
+#define X25LOG_CALL_ACCEPTED   0x0F
+#define X25LOG_CLEAR_RQST      0x13
+#define X25LOG_CLEAR_CONFRM    0x17
+#define X25LOG_RESET_RQST      0x1B
+#define X25LOG_RESET_CONFRM    0x1F
+#define X25LOG_RESTART_RQST    0xFB
+#define X25LOG_RESTART_COMFRM  0xFF
+#define X25LOG_DIAGNOSTIC      0xF1
+#define X25LOG_DTE_REG_RQST    0xF3
+#define X25LOG_DTE_REG_COMFRM  0xF7
+
+/* ---------------------------------------------------------------------------
+ * X25_TRACE_CONFIGURE Command.
+ */
+typedef struct X25TraceCfg
+{
+       unsigned char flags     PACKED; /* 00h: trace configuration flags */
+       unsigned char timeout   PACKED; /* 01h: timeout for trace delay mode*/
+} TX25TraceCfg;
+
+/*
+ * Defines for the 'flags' field.
+ */
+#define X25_TRC_ENABLE         0x01    /* bit0: '1' - trace enabled */
+#define X25_TRC_TIMESTAMP      0x02    /* bit1: '1' - time stamping enabled*/
+#define X25_TRC_DELAY          0x04    /* bit2: '1' - trace delay enabled */
+#define X25_TRC_DATA           0x08    /* bit3: '1' - trace data packets */
+#define X25_TRC_SUPERVISORY    0x10    /* bit4: '1' - trace suprvisory pkts*/
+#define X25_TRC_ASYNCHRONOUS   0x20    /* bit5: '1' - trace asynch. packets*/
+#define X25_TRC_HDLC           0x40    /* bit6: '1' - trace all packets */
+#define X25_TRC_READ           0x80    /* bit7: '1' - get current config. */
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_TRACE_DATA Command.
+ */
+typedef struct X25Trace                        /*----- Trace data structure -------*/
+{
+       unsigned short length   PACKED; /* 00h: trace data length */
+       unsigned char type      PACKED; /* 02h: trace type */
+       unsigned char lost_cnt  PACKED; /* 03h: N of traces lost */
+       TX25TimeStamp tstamp    PACKED; /* 04h: mon/date/sec/min/hour */
+       unsigned short millisec PACKED; /* 09h: ms time stamp */
+       unsigned char data[0]   PACKED; /* 0Bh: traced frame */
+} TX25Trace;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25_TRC_TYPE_MASK      0x0F    /* bits 0..3: trace type */
+#define X25_TRC_TYPE_RX_FRAME  0x00    /* received frame trace */
+#define X25_TRC_TYPE_TX_FRAME  0x01    /* transmitted frame */
+#define X25_TRC_TYPE_ERR_FRAME 0x02    /* error frame */
+
+#define X25_TRC_ERROR_MASK     0xF0    /* bits 4..7: error code */
+#define X25_TRCERR_RX_ABORT    0x10    /* receive abort error */
+#define X25_TRCERR_RX_BADCRC   0x20    /* receive CRC error */
+#define X25_TRCERR_RX_OVERRUN  0x30    /* receiver overrun error */
+#define X25_TRCERR_RX_TOO_LONG 0x40    /* excessive frame length error */
+#define X25_TRCERR_TX_ABORT    0x70    /* aborted frame transmittion error */
+#define X25_TRCERR_TX_UNDERRUN 0x80    /* transmit underrun error */
+
+/*****************************************************************************
+ * Following definitions describe HDLC frame and X.25 packet formats.
+ ****************************************************************************/
+
+typedef struct HDLCFrame               /*----- DHLC Frame Format ----------*/
+{
+       unsigned char addr      PACKED; /* address field */
+       unsigned char cntl      PACKED; /* control field */
+       unsigned char data[0]   PACKED;
+} THDLCFrame;
+
+typedef struct X25Pkt                  /*----- X.25 Paket Format ----------*/
+{
+       unsigned char lcn_hi    PACKED; /* 4 MSB of Logical Channel Number */
+       unsigned char lcn_lo    PACKED; /* 8 LSB of Logical Channel Number */
+       unsigned char type      PACKED;
+       unsigned char data[0]   PACKED;
+} TX25Pkt;
+
+/*
+ * Defines for the 'lcn_hi' field.
+ */
+#define        X25_Q_BIT_MASK          0x80    /* Data Qualifier Bit mask */
+#define        X25_D_BIT_MASK          0x40    /* Delivery Confirmation Bit mask */
+#define        X25_M_BITS_MASK         0x30    /* Modulo Bits mask */
+#define        X25_LCN_MSB_MASK        0x0F    /* LCN most significant bits mask */
+
+/*
+ * Defines for the 'type' field.
+ */
+#define        X25PKT_DATA             0x01    /* Data packet mask */
+#define        X25PKT_SUPERVISORY      0x02    /* Supervisory packet mask */
+#define        X25PKT_CALL_RQST        0x0B    /* Call Request/Incoming */
+#define        X25PKT_CALL_ACCEPTED    0x0F    /* Call Accepted/Connected */
+#define        X25PKT_CLEAR_RQST       0x13    /* Clear Request/Indication */
+#define        X25PKT_CLEAR_CONFRM     0x17    /* Clear Confirmation */
+#define        X25PKT_RESET_RQST       0x1B    /* Reset Request/Indication */
+#define        X25PKT_RESET_CONFRM     0x1F    /* Reset Confirmation */
+#define        X25PKT_RESTART_RQST     0xFB    /* Restart Request/Indication */
+#define        X25PKT_RESTART_CONFRM   0xFF    /* Restart Confirmation */
+#define        X25PKT_INTERRUPT        0x23    /* Interrupt */
+#define        X25PKT_INTERRUPT_CONFRM 0x27    /* Interrupt Confirmation */
+#define        X25PKT_DIAGNOSTIC       0xF1    /* Diagnostic */
+#define        X25PKT_REGISTR_RQST     0xF3    /* Registration Request */
+#define        X25PKT_REGISTR_CONFRM   0xF7    /* Registration Confirmation */
+#define        X25PKT_RR_MASKED        0x01    /* Receive Ready packet after masking */
+#define        X25PKT_RNR_MASKED       0x05    /* Receive Not Ready after masking  */
+
+#ifdef         _MSC_
+#  pragma      pack()
+#endif
+#endif /* _SDLA_X25_H */
diff --git a/include/linux/sdladrv.h b/include/linux/sdladrv.h
new file mode 100644 (file)
index 0000000..af18e4b
--- /dev/null
@@ -0,0 +1,61 @@
+/*****************************************************************************
+* sdladrv.h    SDLA Support Module.  Kernel API Definitions.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 11, 1996 Gene Kozin      Complete overhaul.
+* Oct 17, 1996 Gene Kozin      Minor bug fixes.
+* Jun 12, 1996 Gene Kozin      Added support for S503 card.
+* Dec 06, 1995 Gene Kozin      Initial version.
+*****************************************************************************/
+#ifndef        _SDLADRV_H
+#define        _SDLADRV_H
+
+#define        SDLA_MAXIORANGE 4       /* maximum I/O port range */
+#define        SDLA_WINDOWSIZE 0x2000  /* default dual-port memory window size */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * Adapter hardware configuration. Pointer to this structure is passed to all
+ * APIs.
+ */
+typedef struct sdlahw
+{
+       unsigned type;                  /* adapter type */
+       unsigned fwid;                  /* firmware ID */
+       unsigned port;                  /* adapter I/O port base */
+       int irq;                        /* interrupt request level */
+       unsigned long dpmbase;          /* dual-port memory base */
+       unsigned dpmsize;               /* dual-port memory size */
+       unsigned pclk;                  /* CPU clock rate, kHz */
+       unsigned long memory;           /* memory size */
+       unsigned long vector;           /* local offset of the DPM window */
+       unsigned io_range;              /* I/O port range */
+       unsigned char regs[SDLA_MAXIORANGE]; /* was written to registers */
+       unsigned reserved[5];
+} sdlahw_t;
+
+/****** Function Prototypes *************************************************/
+
+extern int sdla_setup  (sdlahw_t* hw, void* sfm, unsigned len);
+extern int sdla_down   (sdlahw_t* hw);
+extern int sdla_inten  (sdlahw_t* hw);
+extern int sdla_intde  (sdlahw_t* hw);
+extern int sdla_intack (sdlahw_t* hw);
+extern int sdla_intr   (sdlahw_t* hw);
+extern int sdla_mapmem (sdlahw_t* hw, unsigned long addr);
+extern int sdla_peek   (sdlahw_t* hw, unsigned long addr, void* buf,
+                        unsigned len);
+extern int sdla_poke   (sdlahw_t* hw, unsigned long addr, void* buf,
+                        unsigned len);
+extern int sdla_exec   (void* opflag);
+
+#endif /* _SDLADRV_H */
diff --git a/include/linux/sdlasfm.h b/include/linux/sdlasfm.h
new file mode 100644 (file)
index 0000000..65e7f30
--- /dev/null
@@ -0,0 +1,92 @@
+/*****************************************************************************
+* sdlasfm.h    WANPIPE(tm) Multiprotocol WAN Link Driver.
+*              Definitions for the SDLA Firmware Module (SFM).
+*
+* Author:      Gene Kozin      <74604.152@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 11, 1996 Gene Kozin      Cosmetic changes
+* Apr 16, 1996 Gene Kozin      Changed adapter & firmware IDs. Version 2
+* Dec 15, 1995 Gene Kozin      Structures chaned
+* Nov 09, 1995 Gene Kozin      Initial version.
+*****************************************************************************/
+#ifndef        _SDLASFM_H
+#define        _SDLASFM_H
+
+/****** Defines *************************************************************/
+
+#define        SFM_VERSION     2
+#define        SFM_SIGNATURE   "SFM - Sangoma SDLA Firmware Module"
+
+/* min/max */
+#define        SFM_IMAGE_SIZE  0x8000  /* max size of SDLA code image file */
+#define        SFM_DESCR_LEN   256     /* max length of description string */
+#define        SFM_MAX_SDLA    16      /* max number of compatible adapters */
+
+/* Adapter types */
+#define SDLA_S502A     5020
+#define SDLA_S502E     5021
+#define SDLA_S503      5030
+#define SDLA_S508      5080
+#define SDLA_S507      5070
+#define SDLA_S509      5090
+
+/* Firmware identification numbers:
+ *    0  ..  999       Test & Diagnostics
+ *  1000 .. 1999       Streaming HDLC
+ *  2000 .. 2999       Bisync
+ *  3000 .. 3999       SDLC
+ *  4000 .. 4999       HDLC
+ *  5000 .. 5999       X.25
+ *  6000 .. 6999       Frame Relay
+ *  7000 .. 7999       PPP
+ */
+#define        SFID_CALIB502    200
+#define        SFID_STRM502    1200
+#define        SFID_STRM508    1800
+#define        SFID_BSC502     2200
+#define        SFID_SDLC502    3200
+#define        SFID_HDLC502    4200
+#define        SFID_X25_502    5200
+#define        SFID_X25_508    5800
+#define        SFID_FR502      6200
+#define        SFID_FR508      6800
+#define        SFID_PPP502     7200
+#define        SFID_PPP508     7800
+
+/****** Data Types **********************************************************/
+
+typedef struct sfm_info                /* firmware module information */
+{
+       unsigned short  codeid;         /* firmware ID */
+       unsigned short  version;        /* firmaware version number */
+       unsigned short  adapter[SFM_MAX_SDLA]; /* compatible adapter types */
+       unsigned long   memsize;        /* minimum memory size */
+       unsigned short  reserved[2];    /* reserved */
+       unsigned short  startoffs;      /* entry point offset */
+       unsigned short  winoffs;        /* dual-port memory window offset */
+       unsigned short  codeoffs;       /* code load offset */
+       unsigned short  codesize;       /* code size */
+       unsigned short  dataoffs;       /* configuration data load offset */
+       unsigned short  datasize;       /* configuration data size */
+} sfm_info_t;
+
+typedef struct sfm                     /* SDLA firmware file structire */
+{
+       char            signature[80];  /* SFM file signature */
+       unsigned short  version;        /* file format version */
+       unsigned short  checksum;       /* info + image */
+       unsigned short  reserved[6];    /* reserved */
+       char            descr[SFM_DESCR_LEN]; /* description string */
+       sfm_info_t      info;           /* firmware module info */
+       unsigned char   image[1];       /* code image (variable size) */
+} sfm_t;
+
+#endif /* _SDLASFM_H */
+
index 3e594a90bc7b7e8eec32b2ec8f4635e55ef721d6..b048acb871fd9004f900b0bffba13900b250ad21 100644 (file)
@@ -74,7 +74,22 @@ struct cmsghdr {
                                 (struct cmsghdr *)(msg)->msg_control : \
                                 (struct cmsghdr *)NULL)
 
-extern __inline__ struct cmsghdr * cmsg_nxthdr(struct msghdr *mhdr,
+/*
+ *     This mess will go away with glibc
+ */
+#ifdef __KERNEL__
+#define KINLINE extern __inline__
+#else
+#define KINLINE static
+#endif
+
+
+/*
+ *     Get the next cmsg header
+ */
+KINLINE struct cmsghdr * cmsg_nxthdr(struct msghdr *mhdr,
                                               struct cmsghdr *cmsg)
 {
        unsigned char * ptr;
index 37f6f0b0ac71c5d6861c8ef69cce94819230fe35..cd5fbb93395864ac4b6761bd479a47c00a2a33f7 100644 (file)
@@ -138,7 +138,6 @@ enum {
        NET_NETROM_TRANSPORT_BUSY_DELAY,
        NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,
        NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,
-       NET_NETROM_TRANSPORT_PACKET_LENGTH,
        NET_NETROM_ROUTING_CONTROL,
        NET_NETROM_LINK_FAILS_COUNT
 };
@@ -154,7 +153,8 @@ enum {
        NET_ROSE_CLEAR_REQUEST_TIMEOUT,
        NET_ROSE_NO_ACTIVITY_TIMEOUT,
        NET_ROSE_ACK_HOLD_BACK_TIMEOUT,
-       NET_ROSE_ROUTING_CONTROL
+       NET_ROSE_ROUTING_CONTROL,
+       NET_ROSE_LINK_FAIL_TIMEOUT
 };
 
 /* /proc/sys/net/x25 */
index 8d69c54619538440358cce6453e1e35d156f1228..1a875fbdaa5f477c3c16d6c8b14bcf758185f14a 100644 (file)
  *     This function notifies the line discpline that a change has
  *     been made to the termios stucture.
  * 
- * int (*select)(struct tty_struct * tty, struct inode * inode,
- *               struct file * file, int sel_type,
- *               struct select_table_struct *wait);
+ * int (*poll)(struct tty_struct * tty, struct file * file,
+ *               poll_table *wait);
  *
- *     This function is called when a user attempts to select on a
+ *     This function is called when a user attempts to select/poll on a
  *     tty device.  It is solely the responsibility of the line
- *     discipline to handle select requests.
+ *     discipline to handle poll requests.
  *
  * void        (*receive_buf)(struct tty_struct *, const unsigned char *cp,
  *                    char *fp, int count);
diff --git a/include/linux/wanpipe.h b/include/linux/wanpipe.h
new file mode 100644 (file)
index 0000000..f366421
--- /dev/null
@@ -0,0 +1,131 @@
+/*****************************************************************************
+* wanpipe.h    WANPIPE(tm) Multiprotocol WAN Link Driver.
+*              User-level API definitions.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 02, 1997 Gene Kozin      Version 3.0.0
+*****************************************************************************/
+#ifndef        _WANPIPE_H
+#define        _WANPIPE_H
+
+#include <linux/wanrouter.h>
+
+/* Defines */
+#define        WANPIPE_MAGIC   0x414C4453L     /* signatire: 'SDLA' reversed */
+
+/* IOCTL numbers (up to 16) */
+#define        WANPIPE_DUMP    (ROUTER_USER+0) /* dump adapter's memory */
+#define        WANPIPE_EXEC    (ROUTER_USER+1) /* execute firmware command */
+
+/*
+ * Data structures for IOCTL calls.
+ */
+
+typedef struct sdla_dump       /* WANPIPE_DUMP */
+{
+       unsigned long magic;    /* for verification */
+       unsigned long offset;   /* absolute adapter memory address */
+       unsigned long length;   /* block length */
+       void* ptr;              /* -> buffer */
+} sdla_dump_t;
+
+typedef struct sdla_exec       /* WANPIPE_EXEC */
+{
+       unsigned long magic;    /* for verification */
+       void* cmd;              /* -> command structure */
+       void* data;             /* -> data buffer */
+} sdla_exec_t;
+
+#ifdef __KERNEL__
+/****** Kernel Interface ****************************************************/
+
+#include <linux/sdladrv.h>     /* SDLA support module API definitions */
+#include <linux/sdlasfm.h>     /* SDLA firmware module definitions */
+
+#ifndef        min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef        max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define        is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0)
+#define        is_alpha(ch) ((((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'z')||\
+                 ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'Z'))?1:0)
+#define        is_hex_digit(ch) ((((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')||\
+                 ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\
+                 ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0)
+
+/****** Data Structures *****************************************************/
+
+/* Adapter Data Space.
+ * This structure is needed because we handle multiple cards, otherwise
+ * static data would do it.
+ */
+typedef struct sdla
+{
+       char devname[WAN_DRVNAME_SZ+1]; /* card name */
+       sdlahw_t hw;                    /* hardware configuration */
+       wan_device_t wandev;            /* WAN device data space */
+       unsigned open_cnt;              /* number of open interfaces */
+       unsigned long state_tick;       /* link state timestamp */
+       char in_isr;                    /* interrupt-in-service flag */
+       void* mbox;                     /* -> mailbox */
+       void* rxmb;                     /* -> receive mailbox */
+       void* flags;                    /* -> adapter status flags */
+       void (*isr)(struct sdla* card); /* interrupt service routine */
+       void (*poll)(struct sdla* card); /* polling routine */
+       int (*exec)(struct sdla* card, void* u_cmd, void* u_data);
+       union
+       {
+               struct
+               {                       /****** X.25 specific data **********/
+                       unsigned lo_pvc;
+                       unsigned hi_pvc;
+                       unsigned lo_svc;
+                       unsigned hi_svc;
+               } x;
+               struct
+               {                       /****** frame relay specific data ***/
+                       void* rxmb_base;        /* -> first Rx buffer */
+                       void* rxmb_last;        /* -> last Rx buffer */
+                       unsigned rx_base;       /* S508 receive buffer base */
+                       unsigned rx_top;        /* S508 receive buffer end */
+                       unsigned short node_dlci;
+                       unsigned short dlci_num;
+               } f;
+               struct                  /****** PPP-specific data ***********/
+               {
+                       char if_name[WAN_IFNAME_SZ+1];  /* interface name */
+                       void* txbuf;            /* -> current Tx buffer */
+                       void* txbuf_base;       /* -> first Tx buffer */
+                       void* txbuf_last;       /* -> last Tx buffer */
+                       void* rxbuf_base;       /* -> first Rx buffer */
+                       void* rxbuf_last;       /* -> last Rx buffer */
+                       unsigned rx_base;       /* S508 receive buffer base */
+                       unsigned rx_top;        /* S508 receive buffer end */
+               } p;
+       } u;
+} sdla_t;
+
+/****** Public Functions ****************************************************/
+
+void wanpipe_open      (sdla_t* card);                 /* wpmain.c */
+void wanpipe_close     (sdla_t* card);                 /* wpmain.c */
+void wanpipe_set_state (sdla_t* card, int state);      /* wpmain.c */
+
+int wpx_init (sdla_t* card, wandev_conf_t* conf);      /* wpx.c */
+int wpf_init (sdla_t* card, wandev_conf_t* conf);      /* wpf.c */
+int wpp_init (sdla_t* card, wandev_conf_t* conf);      /* wpp.c */
+
+#endif /* __KERNEL__ */
+#endif /* _WANPIPE_H */
+
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h
new file mode 100644 (file)
index 0000000..444608a
--- /dev/null
@@ -0,0 +1,332 @@
+/*****************************************************************************
+* wanrouter.h  Definitions for the WAN Multiprotocol Router Module.
+*              This module provides API and common services for WAN Link
+*              Drivers and is completely hardware-independent.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1997 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 02, 1997 Gene Kozin      Initial version (based on wanpipe.h).
+*****************************************************************************/
+#ifndef        _ROUTER_H
+#define        _ROUTER_H
+
+#define        ROUTER_NAME     "wanrouter"     /* in case we ever change it */
+#define        ROUTER_VERSION  1               /* version number */
+#define        ROUTER_RELEASE  0               /* release (minor version) number */
+#define        ROUTER_IOCTL    'W'             /* for IOCTL calls */
+#define        ROUTER_MAGIC    0x524D4157L     /* signature: 'WANR' reversed */
+
+/* IOCTL codes for /proc/router/<device> entries (up to 255) */
+enum router_ioctls
+{
+       ROUTER_SETUP    = ROUTER_IOCTL<<8,      /* configure device */
+       ROUTER_DOWN,                            /* shut down device */
+       ROUTER_STAT,                            /* get device status */
+       ROUTER_IFNEW,                           /* add interface */
+       ROUTER_IFDEL,                           /* delete interface */
+       ROUTER_IFSTAT,                          /* get interface status */
+       ROUTER_USER     = (ROUTER_IOCTL<<8)+16, /* driver-specific calls */
+       ROUTER_USER_MAX = (ROUTER_IOCTL<<8)+31
+};
+
+/* NLPID for packet encapsulation (ISO/IEC TR 9577) */
+#define        NLPID_IP        0xCC    /* Internet Protocol Datagram */
+#define        NLPID_SNAP      0x80    /* IEEE Subnetwork Access Protocol */
+#define        NLPID_CLNP      0x81    /* ISO/IEC 8473 */
+#define        NLPID_ESIS      0x82    /* ISO/IEC 9542 */
+#define        NLPID_ISIS      0x83    /* ISO/IEC ISIS */
+#define        NLPID_Q933      0x08    /* CCITT Q.933 */
+
+/* Miscellaneous */
+#define        WAN_IFNAME_SZ   15      /* max length of the interface name */
+#define        WAN_DRVNAME_SZ  15      /* max length of the link driver name */
+#define        WAN_ADDRESS_SZ  31      /* max length of the WAN media address */
+
+/****** Data Types **********************************************************/
+
+/*----------------------------------------------------------------------------
+ * X.25-specific link-level configuration.
+ */
+typedef struct wan_x25_conf
+{
+       unsigned lo_pvc;        /* lowest permanent circuit number */
+       unsigned hi_pvc;        /* highest permanent circuit number */
+       unsigned lo_svc;        /* lowest switched circuit number */
+       unsigned hi_svc;        /* highest switched circuit number */
+       unsigned hdlc_window;   /* HDLC window size (1..7) */
+       unsigned pkt_window;    /* X.25 packet window size (1..7) */
+       unsigned t1;            /* HDLC timer T1, sec (1..30) */
+       unsigned t2;            /* HDLC timer T2, sec (0..29) */
+       unsigned t4;            /* HDLC supervisory frame timer = T4 * T1 */
+       unsigned n2;            /* HDLC retransmission limit (1..30) */
+       unsigned t10_t20;       /* X.25 RESTART timeout, sec (1..255) */
+       unsigned t11_t21;       /* X.25 CALL timeout, sec (1..255) */
+       unsigned t12_t22;       /* X.25 RESET timeout, sec (1..255) */
+       unsigned t13_t23;       /* X.25 CLEAR timeout, sec (1..255) */
+       unsigned t16_t26;       /* X.25 INTERRUPT timeout, sec (1..255) */
+       unsigned t28;           /* X.25 REGISTRATION timeout, sec (1..255) */
+       unsigned r10_r20;       /* RESTART retransmission limit (0..250) */
+       unsigned r12_r22;       /* RESET retransmission limit (0..250) */
+       unsigned r13_r23;       /* CLEAR retransmission limit (0..250) */
+       unsigned ccitt_compat;  /* compatibility mode: 1988/1984/1980 */
+} wan_x25_conf_t;
+
+/*----------------------------------------------------------------------------
+ * Frame relay specific link-level configuration.
+ */
+typedef struct wan_fr_conf
+{
+       unsigned cir;           /* committed information rate */
+       unsigned signalling;    /* local in-channel signalling type */
+       unsigned t391;          /* link integrity verification timer */
+       unsigned t392;          /* polling verification timer */
+       unsigned n391;          /* full status polling cycle counter */
+       unsigned n392;          /* error threshold counter */
+       unsigned n393;          /* monitored events counter */
+       unsigned dlci;          /* first DLC number (access node) */
+       unsigned dlci_num;      /* number of DLCs (access node) */
+} wan_fr_conf_t;
+
+/*----------------------------------------------------------------------------
+ * PPP-specific link-level configuration.
+ */
+typedef struct wan_ppp_conf
+{
+       unsigned restart_tmr;   /* restart timer */
+       unsigned auth_rsrt_tmr; /* authentication timer */
+       unsigned auth_wait_tmr; /* authentication timer */
+       unsigned mdm_fail_tmr;  /* modem failure timer */
+       unsigned dtr_drop_tmr;  /* DTR drop timer */
+       unsigned connect_tmout; /* connection timeout */
+       unsigned conf_retry;    /* max. retry */
+       unsigned term_retry;    /* max. retry */
+       unsigned fail_retry;    /* max. retry */
+       unsigned auth_retry;    /* max. retry */
+       unsigned auth_options;  /* authentication opt. */
+       unsigned ip_options;    /* IP options */
+} wan_ppp_conf_t;
+
+/*----------------------------------------------------------------------------
+ * WAN device configuration. Passed to ROUTER_SETUP IOCTL.
+ */
+typedef struct wandev_conf
+{
+       unsigned magic;         /* magic number (for verification) */
+       unsigned config_id;     /* configuration structure identifier */
+                               /****** hardware configuration ******/
+       unsigned ioport;        /* adapter I/O port base */
+       unsigned long maddr;    /* dual-port memory address */
+       unsigned msize;         /* dual-port memory size */
+       int irq;                /* interrupt request level */
+       int dma;                /* DMA request level */
+       unsigned bps;           /* data transfer rate */
+       unsigned mtu;           /* maximum transmit unit size */
+       char interface;         /* RS-232/V.35, etc. */
+       char clocking;          /* external/internal */
+       char line_coding;       /* NRZ/NRZI/FM0/FM1, etc. */
+       char station;           /* DTE/DCE, primary/secondary, etc. */
+       char connection;        /* permanent/switched/on-demand */
+       unsigned hw_opt[4];     /* other hardware options */
+       unsigned reserved[4];
+                               /****** arbitrary data ***************/
+       unsigned data_size;     /* data buffer size */
+       void* data;             /* data buffer, e.g. firmware */
+       union                   /****** protocol-specific ************/
+       {
+               wan_x25_conf_t x25;     /* X.25 configuration */
+               wan_ppp_conf_t ppp;     /* PPP configuration */
+               wan_fr_conf_t fr;       /* frame relay configuration */
+       } u;
+} wandev_conf_t;
+
+/* 'config_id' definitions */
+#define        WANCONFIG_X25   101     /* X.25 link */
+#define        WANCONFIG_FR    102     /* frame relay link */
+#define        WANCONFIG_PPP   103     /* synchronous PPP link */
+
+/*
+ * Configuration options defines.
+ */
+/* general options */
+#define        WANOPT_OFF      0
+#define        WANOPT_ON       1
+#define        WANOPT_NO       0
+#define        WANOPT_YES      1
+
+/* intercace options */
+#define        WANOPT_RS232    0
+#define        WANOPT_V35      1
+
+/* data encoding options */
+#define        WANOPT_NRZ      0
+#define        WANOPT_NRZI     1
+#define        WANOPT_FM0      2
+#define        WANOPT_FM1      3
+
+/* link type options */
+#define        WANOPT_POINTTOPOINT     0       /* RTS always active */
+#define        WANOPT_MULTIDROP        1       /* RTS is active when transmitting */
+
+/* clocking options */
+#define        WANOPT_EXTERNAL 0
+#define        WANOPT_INTERNAL 1
+
+/* station options */
+#define        WANOPT_DTE              0
+#define        WANOPT_DCE              1
+#define        WANOPT_CPE              0
+#define        WANOPT_NODE             1
+#define        WANOPT_SECONDARY        0
+#define        WANOPT_PRIMARY          1
+
+/* connection options */
+#define        WANOPT_PERMANENT        0       /* DTR always active */
+#define        WANOPT_SWITCHED         1       /* use DTR to setup link (dial-up) */
+#define        WANOPT_ONDEMAND         2       /* activate DTR only before sending */
+
+/* frame relay in-channel signalling */
+#define        WANOPT_FR_ANSI          0       /* ANSI T1.617 Annex D */
+#define        WANOPT_FR_Q933          1       /* ITU Q.933A */
+#define        WANOPT_FR_LMI           2       /* LMI */
+
+/*----------------------------------------------------------------------------
+ * WAN Link Status Info (for ROUTER_STAT IOCTL).
+ */
+typedef struct wandev_stat
+{
+       unsigned state;         /* link state */
+       unsigned ndev;          /* number of configured interfaces */
+
+       /* link/interface configuration */
+       unsigned connection;    /* permanent/switched/on-demand */
+       unsigned media_type;    /* Frame relay/PPP/X.25/SDLC, etc. */
+       unsigned mtu;           /* max. transmit unit for this device */
+
+       /* physical level statistics */
+       unsigned modem_status;  /* modem status */
+       unsigned rx_frames;     /* received frames count */
+       unsigned rx_overruns;   /* receiver overrun error count */
+       unsigned rx_crc_err;    /* receive CRC error count */
+       unsigned rx_aborts;     /* received aborted frames count */
+       unsigned rx_bad_length; /* unexpetedly long/short frames count */
+       unsigned rx_dropped;    /* frames discarded at device level */
+       unsigned tx_frames;     /* transmitted frames count */
+       unsigned tx_underruns;  /* aborted transmissions (underruns) count */
+       unsigned tx_timeouts;   /* transmission timeouts */
+       unsigned tx_rejects;    /* other transmit errors */
+
+       /* media level statistics */
+       unsigned rx_bad_format; /* frames with invalid format */
+       unsigned rx_bad_addr;   /* frames with invalid media address */
+       unsigned tx_retries;    /* frames re-transmitted */
+       unsigned reserved[16];  /* reserved for future use */
+} wandev_stat_t;
+
+/* 'state' defines */
+enum wan_states
+{
+       WAN_UNCONFIGURED,       /* link/channel is not configured */
+       WAN_DISCONNECTED,       /* link/channel is disconnected */
+       WAN_CONNECTING,         /* connection is in progress */
+       WAN_CONNECTED,          /* link/channel is operational */
+       WAN_LIMIT               /* for verification only */
+};
+
+/* 'modem_status' masks */
+#define        WAN_MODEM_CTS   0x0001  /* CTS line active */
+#define        WAN_MODEM_DCD   0x0002  /* DCD line active */
+#define        WAN_MODEM_DTR   0x0010  /* DTR line active */
+#define        WAN_MODEM_RTS   0x0020  /* RTS line active */
+
+/*----------------------------------------------------------------------------
+ * WAN interface (logical channel) configuration (for ROUTER_IFNEW IOCTL).
+ */
+typedef struct wanif_conf
+{
+       unsigned magic;                 /* magic number */
+       unsigned config_id;             /* configuration identifier */
+       char name[WAN_IFNAME_SZ+1];     /* interface name, ASCIIZ */
+       char addr[WAN_ADDRESS_SZ+1];    /* media address, ASCIIZ */
+       unsigned idle_timeout;          /* sec, before disconnecting */
+       unsigned hold_timeout;          /* sec, before re-connecting */
+       int reserved[8];                /* reserved for future extensions */
+} wanif_conf_t;
+
+#ifdef __KERNEL__
+/****** Kernel Interface ****************************************************/
+
+#include <linux/fs.h>          /* support for device drivers */
+#include <linux/proc_fs.h>     /* proc filesystem pragmatics */
+#include <linux/inet.h>                /* in_aton(), in_ntoa() prototypes */
+#include <linux/netdevice.h>   /* support for network drivers */
+
+/*----------------------------------------------------------------------------
+ * WAN device data space.
+ */
+typedef struct wan_device
+{
+       unsigned magic;                 /* magic number */
+       char* name;                     /* -> WAN device name (ASCIIZ) */
+       void* private;                  /* -> driver private data */
+                                       /****** hardware configuration ******/
+       unsigned ioport;                /* adapter I/O port base #1 */
+       unsigned long maddr;            /* dual-port memory address */
+       unsigned msize;                 /* dual-port memory size */
+       int irq;                        /* interrupt request level */
+       int dma;                        /* DMA request level */
+       unsigned bps;                   /* data transfer rate */
+       unsigned mtu;                   /* max physical transmit unit size */
+       char interface;                 /* RS-232/V.35, etc. */
+       char clocking;                  /* external/internal */
+       char line_coding;               /* NRZ/NRZI/FM0/FM1, etc. */
+       char station;                   /* DTE/DCE, primary/secondary, etc. */
+       char connection;                /* permanent/switched/on-demand */
+       unsigned hw_opt[4];             /* other hardware options */
+                                       /****** status and statistics *******/
+       char state;                     /* device state */
+       unsigned modem_status;          /* modem status */
+       struct enet_statistics stats;   /* interface statistics */
+       unsigned reserved[16];          /* reserved for future use */
+       unsigned critical;              /* critical section flag */
+                                       /****** device management methods ***/
+       int (*setup) (struct wan_device* wandev, wandev_conf_t* conf);
+       int (*shutdown) (struct wan_device* wandev);
+       int (*update) (struct wan_device* wandev);
+       int (*ioctl) (struct wan_device* wandev, unsigned cmd,
+               unsigned long arg);
+       int (*new_if) (struct wan_device* wandev, struct device* dev,
+               wanif_conf_t* conf);
+       int (*del_if) (struct wan_device* wandev, struct device* dev);
+                                       /****** maintained by the router ****/
+       struct wan_device* next;        /* -> next device */
+       struct device* dev;             /* list of network interfaces */
+       unsigned ndev;                  /* number of interfaces */
+       struct proc_dir_entry dent;     /* proc filesystem entry */
+} wan_device_t;
+
+/* Init Point */
+extern void wanrouter_init(void);
+
+/* Public functions available for device drivers */
+extern int register_wan_device (wan_device_t* wandev);
+extern int unregister_wan_device (char* name);
+unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev);
+int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev);
+
+/* Proc interface functions. These must not be called by the drivers! */
+extern int wanrouter_proc_init (void);
+extern void wanrouter_proc_cleanup (void);
+extern int wanrouter_proc_add (wan_device_t* wandev);
+extern int wanrouter_proc_delete (wan_device_t* wandev);
+extern int wanrouter_ioctl(struct inode* inode, struct file* file,
+       unsigned int cmd, unsigned long arg);
+
+#endif /* __KERNEL__ */
+#endif /* _ROUTER_H */
index 7b1ddd50fda4e38046dcf6945d69a958659f7144..b6fc7c4b0ca4f5fea683108cc94b858e3078d0aa 100644 (file)
 #define        AX25_VALUES_IPDEFMODE   0       /* 0=DG 1=VC */
 #define        AX25_VALUES_AXDEFMODE   1       /* 0=Normal 1=Extended Seq Nos */
 #define        AX25_VALUES_TEXT        2       /* Allow PID=Text - 0=No 1=Yes */
-#define        AX25_VALUES_BACKOFF     3       /* 0=Linear 1=Exponential */
+#define        AX25_VALUES_BACKOFF     3       /* 0=None 1=Linear 2=Exponential */
 #define        AX25_VALUES_CONMODE     4       /* Allow connected modes - 0=No 1=Yes */
 #define        AX25_VALUES_WINDOW      5       /* Default window size for standard AX.25 */
 #define        AX25_VALUES_EWINDOW     6       /* Default window size for extended AX.25 */
 #define        AX25_DEF_IPDEFMODE      0                       /* Datagram */
 #define        AX25_DEF_AXDEFMODE      0                       /* Normal */
 #define        AX25_DEF_TEXT           1                       /* PID=Text allowed */
-#define        AX25_DEF_BACKOFF        1                       /* Exponential backoff */
+#define        AX25_DEF_BACKOFF        1                       /* Linear backoff */
 #define        AX25_DEF_CONMODE        1                       /* Connected mode allowed */
 #define        AX25_DEF_WINDOW         2                       /* Window=2 */
 #define        AX25_DEF_EWINDOW        32                      /* Module-128 Window=32 */
@@ -197,7 +197,7 @@ extern ax25_address null_ax25_address;
 extern char *ax2asc(ax25_address *);
 extern ax25_address *asc2ax(char *);
 extern int  ax25cmp(ax25_address *, ax25_address *);
-extern int  ax25_send_frame(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *, struct device *);
+extern int  ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *);
 extern int  ax25_link_up(ax25_address *, ax25_address *, struct device *);
 extern void ax25_destroy_socket(ax25_cb *);
 extern struct device *ax25rtr_get_dev(ax25_address *);
@@ -216,7 +216,7 @@ extern int  ax25_dev_is_dama_slave(struct device *);        /* dl1bke 951121 */
 extern int  ax25_process_rx_frame(ax25_cb *, struct sk_buff *, int, int);
 
 /* ax25_out.c */
-extern void ax25_output(ax25_cb *, struct sk_buff *);
+extern void ax25_output(ax25_cb *, int, struct sk_buff *);
 extern void ax25_kick(ax25_cb *);
 extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
 extern void ax25_nr_error_recovery(ax25_cb *);
index baa94d6007dd249dc94c1f20a0b3bbcd272f63a0..b198a341040b520c39e5d98d21d01a7bf29fbec8 100644 (file)
@@ -10,9 +10,6 @@
 
 #define        NR_SLOWHZ                       10      /* Run timing at 1/10 second */
 
-#define        NR_T1CLAMPLO                    (1 * NR_SLOWHZ)         /* If defined, clamp at 1 second **/
-#define        NR_T1CLAMPHI                    (300 * NR_SLOWHZ)       /* If defined, clamp at 30 seconds **/
-
 #define        NR_NETWORK_LEN                  15
 #define        NR_TRANSPORT_LEN                5
 
 #define        NR_DEFAULT_OBS                  6                       /* Default Obsolescence Count - 6 */
 #define        NR_DEFAULT_QUAL                 10                      /* Default Neighbour Quality - 10 */
 #define        NR_DEFAULT_TTL                  16                      /* Default Time To Live - 16 */
-#define NR_MODULUS                     256
-#define NR_MAX_WINDOW_SIZE             127                     /* Maximum Window Allowable - 127 */
-#define        NR_DEFAULT_PACLEN               236                     /* Default Packet Length - 236 */
 #define        NR_DEFAULT_ROUTING              1                       /* Is routing enabled ? */
 #define        NR_DEFAULT_FAILS                2                       /* Link fails until route fails */
 
+#define NR_MODULUS                     256
+#define NR_MAX_WINDOW_SIZE             127                     /* Maximum Window Allowable - 127 */
+#define        NR_MAX_PACKET_SIZE              236                     /* Maximum Packet Length - 236 */
+
 typedef struct {
        ax25_address            user_addr, source_addr, dest_addr;
        struct device           *device;
@@ -65,9 +63,9 @@ typedef struct {
        unsigned char           state, condition, bpqext, hdrincl, window;
        unsigned short          vs, vr, va, vl;
        unsigned char           n2, n2count;
-       unsigned short          t1, t2, t4, idle, rtt;
+       unsigned short          t1, t2, t4, idle;
        unsigned short          t1timer, t2timer, t4timer, idletimer;
-       unsigned short          fraglen, paclen;
+       unsigned short          fraglen;
        struct sk_buff_head     ack_queue;
        struct sk_buff_head     reseq_queue;
        struct sk_buff_head     frag_queue;
@@ -95,7 +93,7 @@ struct nr_route {
 struct nr_node {
        struct nr_node  *next;
        ax25_address    callsign;
-       char mnemonic[7];
+       char            mnemonic[7];
        unsigned char   which;
        unsigned char   count;
        struct nr_route routes[3];
@@ -111,7 +109,6 @@ extern int  sysctl_netrom_transport_acknowledge_delay;
 extern int  sysctl_netrom_transport_busy_delay;
 extern int  sysctl_netrom_transport_requested_window_size;
 extern int  sysctl_netrom_transport_no_activity_timeout;
-extern int  sysctl_netrom_transport_packet_length;
 extern int  sysctl_netrom_routing_control;
 extern int  sysctl_netrom_link_fails_count;
 extern int  nr_rx_frame(struct sk_buff *, struct device *);
@@ -154,8 +151,6 @@ extern int  nr_validate_nr(struct sock *, unsigned short);
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
 extern void nr_transmit_dm(struct sk_buff *);
-extern unsigned short nr_calculate_t1(struct sock *);
-extern void nr_calculate_rtt(struct sock *);
 
 /* nr_timer.c */
 extern void nr_set_timer(struct sock *);
index 03b92d652f2431bb19ff48ecf1b1004a9863a0a5..d64c98b2f79ce91cdce94e85d6e1d005eafbd797 100644 (file)
 #define        ROSE_DEFAULT_T3                 (180 * ROSE_SLOWHZ)     /* Default T13 T23 value */
 #define        ROSE_DEFAULT_HB                 (5 * ROSE_SLOWHZ)       /* Default Holdback value */
 #define        ROSE_DEFAULT_IDLE               (20 * 60 * ROSE_SLOWHZ) /* Default No Activity value */
-#define        ROSE_DEFAULT_WINDOW             2                       /* Default Window Size  */
+#define        ROSE_DEFAULT_ROUTING            1                       /* Default routing flag */
+#define        ROSE_DEFAULT_FAIL_TIMEOUT       (120 * ROSE_SLOWHZ)     /* Time until link considered usable */
+
 #define ROSE_MODULUS                   8
-#define ROSE_MAX_WINDOW_SIZE           7                       /* Maximum Window Allowable */
-#define        ROSE_PACLEN                     128                     /* Default Packet Length */
+#define ROSE_MAX_WINDOW_SIZE           2                       /* Maximum Window Allowable */
+#define        ROSE_MAX_PACKET_SIZE            128                     /* Maximum Packet Length */
 
 #define        ROSE_COND_ACK_PENDING           0x01
 #define        ROSE_COND_PEER_RX_BUSY          0x02
@@ -81,7 +83,7 @@ struct rose_neigh {
        unsigned int      number;
        int               restarted;
        struct sk_buff_head queue;
-       unsigned short    t0, t0timer;
+       unsigned short    t0timer, ftimer;
        struct timer_list timer;
 };
 
@@ -89,7 +91,6 @@ struct rose_node {
        struct rose_node  *next;
        rose_address      address;
        unsigned short    mask;
-       unsigned char     which;
        unsigned char     count;
        struct rose_neigh *neighbour[3];
 };
@@ -127,6 +128,7 @@ extern int  sysctl_rose_clear_request_timeout;
 extern int  sysctl_rose_no_activity_timeout;
 extern int  sysctl_rose_ack_hold_back_timeout;
 extern int  sysctl_rose_routing_control;
+extern int  sysctl_rose_link_fail_timeout;
 extern int  rosecmp(rose_address *, rose_address *);
 extern int  rosecmpm(rose_address *, rose_address *, unsigned short);
 extern char *rose2asc(rose_address *);
@@ -145,6 +147,7 @@ extern int  rose_init(struct device *);
 extern int  rose_process_rx_frame(struct sock *, struct sk_buff *);
 
 /* rose_link.c */
+extern void rose_link_set_timer(struct rose_neigh *);
 extern void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *, unsigned short);
 extern void rose_transmit_restart_request(struct rose_neigh *);
 extern void rose_transmit_restart_confirmation(struct rose_neigh *);
index aeeffdc6967d433e755fbe1ceec72535555be368..389877ad9875417375d0ebe46ad2768cc1fd50b6 100644 (file)
@@ -710,6 +710,7 @@ static void parse_options(char *line)
                }
                if (checksetup(line))
                        continue;
+               
                /*
                 * Then check if it's an environment variable or
                 * an option.
index fd2b74ac72948c1f89655ca445a1f5d837bd8d9e..de9e25e33b141a4bf3aa5aeec3466199e06f22a8 100644 (file)
@@ -583,7 +583,7 @@ qm_symbols(struct module *mod, char *buf, size_t bufsize, size_t *ret)
 
 calc_space_needed:
        for (; i < mod->nsyms; ++i, ++s)
-               space += strlen((++s)->name)+1;
+               space += strlen(s->name)+1;
 
        if (put_user(space, ret))
                return -EFAULT;
index 0d5afe80cf1878c69268cf2d4a5205757e6e2ba8..c4d2726647a74ef631c8d8e7581dab5aa8d17222 100644 (file)
@@ -1262,64 +1262,81 @@ asmlinkage unsigned int sys_alarm(unsigned int seconds)
  * The Alpha uses getxpid, getxuid, and getxgid instead.  Maybe this
  * should be moved into arch/i386 instead?
  */
 asmlinkage int sys_getpid(void)
 {
-       int ret;
-
-       lock_kernel();
-       ret = current->pid;
-       unlock_kernel();
-       return ret;
+       /* This is SMP safe - current->pid doesnt change */
+       return current->pid;
 }
 
+/*
+ * This is not strictly SMP safe: p_opptr could change
+ * from under us. However, rather than getting any lock
+ * we can use an optimistic algorithm: get the parent
+ * pid, and go back and check that the parent is still
+ * the same. If it has changed (which is extremely unlikely
+ * indeed), we just try again..
+ *
+ * NOTE! This depends on the fact that even if we _do_
+ * get an old value of "parent", we can happily dereference
+ * the pointer: we just can't necessarily trust the result
+ * until we know that the parent pointer is valid.
+ *
+ * The "mb()" macro is a memory barrier - a synchronizing
+ * event. It also makes sure that gcc doesn't optimize
+ * away the necessary memory references.. The barrier doesn't
+ * have to have all that strong semantics: on x86 we don't
+ * really require a synchronizing instruction, for example.
+ * The barrier is more important for code generation than
+ * for any real memory ordering semantics (even if there is
+ * a small window for a race, using the old pointer is
+ * harmless for a while).
+ */
 asmlinkage int sys_getppid(void)
 {
-       int ret;
+       int pid;
+       struct task_struct * me = current;
+       struct task_struct * parent;
 
-       lock_kernel();
-       ret = current->p_opptr->pid;
-       unlock_kernel();
-       return ret;
+       parent = me->p_opptr;
+       for (;;) {
+               pid = parent->pid;
+#if __SMP__
+{
+               struct task_struct *old = parent;
+               mb();
+               parent = me->p_opptr;
+               if (old != parent)
+                       continue;
+}
+#endif
+               break;
+       }
+       return pid;
 }
 
 asmlinkage int sys_getuid(void)
 {
-       int ret;
-
-       lock_kernel();
-       ret = current->uid;
-       unlock_kernel();
-       return ret;
+       /* Only we change this so SMP safe */
+       return current->uid;
 }
 
 asmlinkage int sys_geteuid(void)
 {
-       int ret;
-
-       lock_kernel();
-       ret = current->euid;
-       unlock_kernel();
-       return ret;
+       /* Only we change this so SMP safe */
+       return current->euid;
 }
 
 asmlinkage int sys_getgid(void)
 {
-       int ret;
-
-       lock_kernel();
-       ret = current->gid;
-       unlock_kernel();
-       return ret;
+       /* Only we change this so SMP safe */
+       return current->gid;
 }
 
 asmlinkage int sys_getegid(void)
 {
-       int ret;
-
-       lock_kernel();
-       ret = current->egid;
-       unlock_kernel();
-       return ret;
+       /* Only we change this so SMP safe */
+       return  current->egid;
 }
 
 /*
@@ -1327,12 +1344,17 @@ asmlinkage int sys_getegid(void)
  * moved into the arch dependent tree for those ports that require
  * it for backward compatibility?
  */
+
 asmlinkage int sys_nice(int increment)
 {
        unsigned long newprio;
        int increase = 0;
        int ret = -EPERM;
 
+       /*
+        *      We need a lock. sys_setpriority can affect other tasks.
+        */
+        
        lock_kernel();
        newprio = increment;
        if (increment < 0) {
index ab5e06bf335a879075cdd4c06459bc85d3d70767..105c7bc4429d86d09d052966f22e0d02a0f03526 100644 (file)
@@ -766,12 +766,8 @@ out:
 
 asmlinkage int sys_getpgrp(void)
 {
-       int ret;
-
-       lock_kernel();
-       ret = current->pgrp;
-       unlock_kernel();
-       return ret;
+       /* SMP - assuming writes are word atomic this is fine */
+       return current->pgrp;
 }
 
 asmlinkage int sys_getsid(pid_t pid)
@@ -779,10 +775,12 @@ asmlinkage int sys_getsid(pid_t pid)
        struct task_struct * p;
        int ret;
 
-       lock_kernel();
+       /* SMP: The 'self' case requires no lock */
        if (!pid) {
                ret = current->session;
        } else {
+               /* Walking the process table needs locks */
+               lock_kernel();
                for_each_task(p) {
                        if (p->pid == pid) {
                                ret = p->session;
@@ -790,9 +788,9 @@ asmlinkage int sys_getsid(pid_t pid)
                        }
                }
                ret = -ESRCH;
-       }
 out:
-       unlock_kernel();
+               unlock_kernel();
+       }
        return ret;
 }
 
@@ -1117,11 +1115,7 @@ out:
 
 asmlinkage int sys_umask(int mask)
 {
-       int old;
-
-       lock_kernel();
-       old = current->fs->umask;
-       current->fs->umask = mask & S_IRWXUGO;
-       unlock_kernel();
-       return (old);
+       /* The xchg() isn't SMP-safe on x86 right now.. */
+       mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
+       return mask;
 }
index 18fe70d2a7c063ae63559b0c41eeb167e3033c49..22dfce6afa6805f5fab08e8b4d565fd133532e0f 100644 (file)
@@ -26,6 +26,9 @@ if [ "$CONFIG_IPX" != "n" ]; then
   fi
 fi
 tristate 'Appletalk DDP' CONFIG_ATALK
+if [ "$CONFIG_ATALK" != "n" ]; then
+  bool 'IP-over-DDP support (EXPERIMENTAL)' CONFIG_IPDDP
+fi
 tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25
 if [ "$CONFIG_AX25" != "n" ]; then
   dep_tristate 'Amateur Radio NET/ROM' CONFIG_NETROM $CONFIG_AX25
@@ -36,5 +39,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
   bool '802.2 LLC (VERY EXPERIMENTAL)' CONFIG_LLC
+  tristate 'WAN router' CONFIG_WAN_ROUTER
 fi
 endmenu
index e663cf11ca36397c472cba646144c250efbbfc6e..dfb5e2a3ad0e47212e0006297dc7a63a32b7ce53 100644 (file)
@@ -9,7 +9,7 @@
 
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
-               netrom rose lapb x25 #decnet
+               netrom rose lapb x25 wanrouter #decnet
 SUB_DIRS     := core ethernet unix
 MOD_LIST_NAME := NET_MISC_MODULES
 
@@ -49,6 +49,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_WAN_ROUTER),y)
+SUB_DIRS += wanrouter
+else
+  ifeq ($(CONFIG_WAN_ROUTER),m)
+  MOD_SUB_DIRS += wanrouter
+  endif
+endif
+
 ifeq ($(CONFIG_X25),y)
 SUB_DIRS += x25
 else
index aae7733dd967d5a6fc38b297e24820305c645572..ef287f128d93b181ffe6414bfa5680db256819c1 100644 (file)
@@ -14,6 +14,7 @@ ipx                   alan@lxorguk.ukuu.org.uk,greg@caldera.com
 lapb                   jsn@cs.nott.ac.uk
 netrom                 jsn@cs.nott.ac.uk
 rose                   jsn@cs.nott.ac.uk
+wanrouter              genek@compuserve.com and dm@sangoma.com
 unix                   alan@lxorguk.ukuu.org.uk
 x25                    jsn@cs.nott.ac.uk
 
index 26cbdfaa9c72149747ef5759075d177b9cd0a75e..e3e87f9e4b7237aabad17451eeb4d13801c18d00 100644 (file)
@@ -441,9 +441,11 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
                 *      Compressible ?
                 * 
                 *      IFF: src_net==dest_net==device_net
+                *      (zero matches anything)
                 */
                 
-               if(at->s_net==sa->s_net && sa->s_net==ddp->deh_snet)
+               if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet)
+                 &&( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) )
                {
                        skb_pull(skb,sizeof(struct ddpehdr)-4);
                        /*
index 77e05f711dfb147c3f980bdff273e9a906b2db86..f5e21cfa875793e481864d7f13c5cb1c31163b79 100644 (file)
@@ -23,6 +23,7 @@
  *             Alan Cox                :       Hooks for PPP (based on the
  *                                             localtalk hook).
  *             Alan Cox                :       Posix bits
+ *             Bradford Johnson        :       IP-over-DDP (experimental)
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -59,6 +60,8 @@
 #include <net/p8022.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <linux/ip.h>
+#include <net/route.h>
 #include <linux/atalk.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
@@ -163,6 +166,7 @@ static struct sock *atalk_find_socket(struct sockaddr_at *sat)
 extern inline void atalk_destroy_socket(struct sock *sk)
 {
        sklist_destroy_socket(&atalk_socket_list,sk);
+       MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1109,10 +1113,15 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
 
        if(addr->sat_family!=AF_APPLETALK)
                return -EAFNOSUPPORT;
-#if 0  /* Netatalk doesn't check this - fix netatalk first!*/
        if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
+       {
+#if 1  
+               printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n",
+                       current->comm);
+#else
                return -EACCES;
-#endif
+#endif                 
+       }
        if(sk->zapped)
        {
                if(atalk_autobind(sk)<0)
@@ -1191,6 +1200,208 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
        return(0);
 }
 
+/*     
+ *     IP-over-DDP support.  Under construction.
+ */
+
+#ifdef CONFIG_IPDDP
+
+#define SIOCADDIPDDPRT SIOCDEVPRIVATE
+#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1
+#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2
+
+struct ipddp_route {
+       struct device *dev;             /* Carrier device */
+       __u32 ip;                       /* IP address */
+       struct at_addr at;              /* Gateway appletalk address */
+       int flags;
+       struct ipddp_route *next;
+};
+
+static struct ipddp_route *ipddp_route_head;
+
+static struct ipddp_route ipddp_route_test;
+
+int ipddp_open(struct device *dev)
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+int ipddp_close(struct device *dev)
+{
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+int ipddp_xmit(struct sk_buff *skb, struct device *dev)
+{
+       /* Retrieve the saved address hint */
+       struct at_addr *a=(struct at_addr *)skb->data;
+       skb_pull(skb,4);
+       
+       ((struct net_device_stats *) dev->priv)->tx_packets++;
+
+       /* printk("ipddp_xmit called with headroom %d\n",skb_headroom(skb)); */
+
+       if( aarp_send_ddp(skb->dev,skb,a,NULL) < 0 )
+               dev_kfree_skb(skb,FREE_WRITE);
+
+       return 0;
+}
+
+struct net_device_stats *ipddp_get_stats(struct device *dev)
+{
+       return (struct enet_statistics *) dev->priv;
+}
+
+int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+       struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data;
+
+       if(!suser())
+               return -EPERM;
+       
+       /* for now we only have one route at a time */
+
+       switch(cmd) 
+       {
+               case SIOCADDIPDDPRT:
+                       if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route)))
+                               return -EFAULT;
+                       ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at);
+                       if (dev==NULL)
+                               return -ENETUNREACH;
+                       ipddp_route_test.next = NULL;
+                       printk("added ipddp route through %s\n",ipddp_route_test.dev->name);
+                       ipddp_route_head = &ipddp_route_test;
+                       return 0;
+               case SIOCFINDIPDDPRT:
+                       if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route)))
+                               return -EFAULT;
+                       return 0;
+               case SIOCDELIPDDPRT:
+                       ipddp_route_test.dev = NULL;
+                       ipddp_route_head = NULL;
+                       return 0;
+               default: 
+                       return -EINVAL;
+       }
+}
+
+int ipddp_header (struct sk_buff *skb, struct device *dev, unsigned short type,
+               void *daddr, void *saddr, unsigned len)
+{
+       /* printk("ipddp_header\n"); */
+       /* Push down the header space and the type byte */
+       skb_push(skb, sizeof(struct ddpehdr)+1+4);
+       return 0;
+}
+
+/*
+ *     Now the packet really wants to go out. 
+ */
+int ipddp_rebuild_header (struct sk_buff *skb)
+{
+       struct ddpehdr *ddp;
+       struct at_addr at;
+       struct ipddp_route *rt;
+       struct at_addr *our_addr;
+       u32 paddr = ((struct rtable *)skb->dst)->rt_gateway;
+
+       /*
+        *      On entry skb->data points to the ddpehdr we reserved earlier.
+        *      skb->h.raw will be the higher level header.
+        */
+
+       /*
+        *      We created this earlier
+        */
+
+       ddp = (struct ddpehdr *) (skb->data+4);
+       
+       /* find appropriate route */
+
+       for(rt=ipddp_route_head;rt;rt=rt->next) 
+       {
+               if(rt->ip == paddr) 
+                       break;
+       }
+
+       if(!rt) {
+               printk("ipddp unreachable dst %08lx\n",ntohl(paddr));
+               return -ENETUNREACH;
+       }
+
+       our_addr = atalk_find_dev_addr(rt->dev);
+       
+       /* fill in ddpehdr */
+       ddp->deh_len = skb->len;
+       ddp->deh_hops = 1;
+       ddp->deh_pad = 0;
+       ddp->deh_sum = 0;
+       ddp->deh_dnet = rt->at.s_net;   /* FIXME more hops?? */ 
+       ddp->deh_snet = our_addr->s_net;
+       ddp->deh_dnode = rt->at.s_node;
+       ddp->deh_snode = our_addr->s_node;
+       ddp->deh_dport = 72;
+       ddp->deh_sport = 72;
+       
+       *((__u8 *)(ddp+1)) = 22;        /* ddp type = IP */
+
+       /* fix up length field */
+       *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));
+
+       /* set skb->dev to appropriate device */
+       skb->dev = rt->dev;
+
+       /* skb->raddr = (unsigned long) at */ 
+       at = rt->at;
+       /* Hide it at the start of the buffer */
+       memcpy(skb->data,(void *)&at,sizeof(at));
+       skb->arp = 1;   /* so the actual device doesn't try to arp it... */
+       skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
+       
+       return 0;
+}
+
+int ipddp_init (struct device *dev)
+{
+       ether_setup(dev);
+       dev->hard_start_xmit = ipddp_xmit;
+       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+       if(!dev->priv) 
+               return -ENOMEM;
+       memset(dev->priv,0,sizeof(struct enet_statistics));
+       dev->get_stats = ipddp_get_stats;
+       dev->do_ioctl = ipddp_ioctl;
+       dev->type = ARPHRD_IPDDP;       /* IP over DDP tunnel */
+       dev->family = AF_INET;
+       dev->mtu = 585;
+       dev->flags |= IFF_NOARP;
+       dev->hard_header = ipddp_header; /* see ip_output.c */
+       dev->rebuild_header = ipddp_rebuild_header;
+       /*
+        *      The worst case header we will need is currently a
+        *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
+        *      We send over SNAP so that takes another 8 bytes.
+        */
+       dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
+       dev->open = ipddp_open;
+       dev->stop = ipddp_close;
+
+       return 0;
+}
+
+static struct device dev_ipddp = {
+       "ipddp0\0   ",
+               0, 0, 0, 0,
+               0x0, 0,
+               0, 0, 0, NULL, ipddp_init };
+
+#endif /* CONFIG_IPDDP */
+
 /*
  *     Receive a packet (in skb) from device dev. This has come from the SNAP decoder, and on entry
  *     skb->h.raw is the DDP header, skb->len is the DDP length. The physical headers have been
@@ -1349,18 +1560,38 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
        tosat.sat_port = ddp->deh_dport;
 
        sock=atalk_search_socket( &tosat, atif );
-
+       
        if(sock==NULL)  /* But not one of our sockets */
        {
                kfree_skb(skb,FREE_READ);
                return(0);
        }
 
+#ifdef CONFIG_IPDDP
+       /*
+        *      Check if IP-over-DDP
+        */
 
+       if(skb->data[12]==22) {
+               struct enet_statistics *estats = 
+                       (struct enet_statistics *) dev_ipddp.priv;
+               skb->protocol=htons(ETH_P_IP);
+               skb_pull(skb,13);
+               skb->dev=&dev_ipddp;
+               skb->h.raw = skb->data;
+       /*      printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]);
+        *      printk("tot_len %d, skb->len %d\n",
+        *              ntohs(skb->h.iph->tot_len),skb->len);
+        */
+               estats->rx_packets++;
+               netif_rx(skb);
+               return 0;
+       }
+#endif /* CONFIG_IPDDP */      
        /*
         *      Queue packet (standard)
         */
-
+        
        skb->sk = sock;
 
        if(sock_queue_rcv_skb(sock,skb)<0)
@@ -1468,8 +1699,10 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                        return(-EINVAL);
                if(usat->sat_family != AF_APPLETALK)
                        return -EINVAL;
+#if 0         /* netatalk doesn't implement this check */
                if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
                        return -EPERM;
+#endif
        }
        else
        {
@@ -1848,7 +2081,11 @@ void atalk_proto_init(struct net_proto *pro)
        proc_net_register(&proc_appletalk);
        proc_net_register(&proc_atalk_route);
        proc_net_register(&proc_atalk_iface);
-#endif
+#endif 
+
+#ifdef CONFIG_IPDDP
+       register_netdev(&dev_ipddp);
+#endif /* CONFIG_IPDDP */
 
        printk(KERN_INFO "Appletalk 0.18 for Linux NET3.037\n");
 }
index bc4cd646b7f513a8e80872cb71ccd22bbeadd1f3..8fd6ebd702191949675b8e0641166f22aaead579 100644 (file)
  */
 ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
 
-ax25_cb *ax25_list = NULL;
+ax25_cb *volatile ax25_list = NULL;
 
 static struct proto_ops ax25_proto_ops;
 
@@ -416,7 +416,6 @@ static struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_a
  *     Find an AX.25 control block given both ends. It will only pick up
  *     floating AX.25 control blocks or non Raw socket bound control blocks.
  */
-
 static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
 {
        ax25_cb *s;
@@ -477,10 +476,8 @@ static void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto)
                        if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
                                return;
 
-                       skb_set_owner_r(copy, sk);
-                       skb_queue_tail(&sk->receive_queue, copy);
-                       if (!sk->dead)
-                               sk->data_ready(sk, skb->len);
+                       if (sock_queue_rcv_skb(sk, copy) != 0)
+                               kfree_skb(copy, FREE_READ);
                }
 
                sk = sk->next;
@@ -532,7 +529,7 @@ void ax25_destroy_socket(ax25_cb *ax25)     /* Not static as it's used by the timer
        }
 
        if (ax25->sk != NULL) {
-               if (ax25->sk->wmem_alloc || ax25->sk->rmem_alloc) { /* Defer: outstanding buffers */
+               if (ax25->sk->wmem_alloc > 0 || ax25->sk->rmem_alloc > 0) {     /* Defer: outstanding buffers */
                        init_timer(&ax25->timer);
                        ax25->timer.expires  = jiffies + 10 * HZ;
                        ax25->timer.function = ax25_destroy_timer;
@@ -841,7 +838,7 @@ static void ax25_fillin_cb(ax25_cb *ax25, struct device *dev)
        ax25->backoff = ax25_dev_get_value(dev, AX25_VALUES_BACKOFF);
 }
 
-int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest,
+int ax25_send_frame(struct sk_buff *skb, int fragment, ax25_address *src, ax25_address *dest,
        ax25_digi *digi, struct device *dev)
 {
        ax25_cb *ax25;
@@ -860,7 +857,7 @@ int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest,
                        if (ax25_queue_length(ax25, skb) > ax25->maxqueue * ax25->window) {
                                kfree_skb(skb, FREE_WRITE);
                        } else {
-                               ax25_output(ax25, skb);
+                               ax25_output(ax25, fragment, skb);
                        }
                        ax25->idletimer = ax25->idle;
                        return 1;               /* It already existed */
@@ -900,7 +897,7 @@ int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest,
 
        ax25_set_timer(ax25);
 
-       ax25_output(ax25, skb);
+       ax25_output(ax25, fragment, skb);
 
        return 1;                       /* We had to create it */
 }
@@ -1004,7 +1001,9 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
                        return 0;
 
                case AX25_BACKOFF:
-                       sk->protinfo.ax25->backoff = opt ? 1 : 0;
+                       if (opt < 0 || opt > 2)
+                               return -EINVAL;
+                       sk->protinfo.ax25->backoff = opt;
                        return 0;
 
                case AX25_EXTSEQ:
@@ -1097,7 +1096,7 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname,
        if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
                return err;
 
-       put_user(val, (int *) optval);
+       put_user(val, (int *)optval);
 
        return 0;
 }
@@ -1171,12 +1170,11 @@ static int ax25_create(struct socket *sock, int protocol)
                return -ENOMEM;
        }
 
-       sock_init_data(sock,sk);
+       sock_init_data(sock, sk);
        
-       sock->ops = &ax25_proto_ops;
-
-       sk->protocol      = protocol;
-       sk->mtu           = AX25_MTU;   /* 256 */
+       sock->ops    = &ax25_proto_ops;
+       sk->protocol = protocol;
+       sk->mtu      = AX25_MTU;        /* 256 */
 
        ax25->sk          = sk;
        sk->protinfo.ax25 = ax25;
@@ -1199,9 +1197,6 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
 
        ax25_fillin_cb(ax25, dev);
 
-       sk->type   = osk->type;
-       sk->socket = osk->socket;
-
        switch (osk->type) {
                case SOCK_DGRAM:
                        break;
@@ -1213,17 +1208,19 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
                        return NULL;
        }
 
-       sock_init_data(NULL,sk);
+       sock_init_data(NULL, sk);
        
-       sk->priority    = osk->priority;
-       sk->protocol    = osk->protocol;
-       sk->rcvbuf      = osk->rcvbuf;
-       sk->sndbuf      = osk->sndbuf;
-       sk->debug       = osk->debug;
-       sk->state       = TCP_ESTABLISHED;
-       sk->mtu         = osk->mtu;
-       sk->sleep       = osk->sleep;
-       sk->zapped      = osk->zapped;
+       sk->type     = osk->type;
+       sk->socket   = osk->socket;
+       sk->priority = osk->priority;
+       sk->protocol = osk->protocol;
+       sk->rcvbuf   = osk->rcvbuf;
+       sk->sndbuf   = osk->sndbuf;
+       sk->debug    = osk->debug;
+       sk->state    = TCP_ESTABLISHED;
+       sk->mtu      = osk->mtu;
+       sk->sleep    = osk->sleep;
+       sk->zapped   = osk->zapped;
 
        ax25->modulus = osk->protinfo.ax25->modulus;
        ax25->backoff = osk->protinfo.ax25->backoff;
@@ -1461,7 +1458,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
                        } else {
                                sk->protinfo.ax25->digipeat->repeated[ct] = 0;
                        }
-                       sk->protinfo.ax25->digipeat->calls[ct]    = fsa->fsa_digipeater[ct];
+                       sk->protinfo.ax25->digipeat->calls[ct] = fsa->fsa_digipeater[ct];
                        ct++;
                }
        }
@@ -1706,9 +1703,9 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                                return 0;
                        }
 #endif
-                       skb->arp = 1;
-                       skb->dev = dev_out;
+                       skb->dev      = dev_out;
                        skb->priority = SOPRI_NORMAL;
+
                        ax25_queue_xmit(skb);
 
                        return 0;
@@ -1771,10 +1768,8 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                                                 *      Remove the control and PID.
                                                 */
                                                skb_pull(skb, 2);
-                                               skb_set_owner_r(skb, sk);
-                                               skb_queue_tail(&sk->receive_queue, skb);
-                                               if (!sk->dead)
-                                                       sk->data_ready(sk, skb->len);
+                                               if (sock_queue_rcv_skb(sk, skb) != 0)
+                                                       kfree_skb(skb, FREE_READ);
                                        }
                                } else {
                                        kfree_skb(skb, FREE_READ);
@@ -1975,7 +1970,7 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
        if (sk->protinfo.ax25->device == NULL)
                return -ENETUNREACH;
 
-       if (usax) {
+       if (usax != NULL) {
                if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
                        return -EINVAL;
                if (usax->sax25_family != AF_AX25)
@@ -2030,8 +2025,6 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
        if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
                return err;
 
-       skb->arp = 1;
-
        skb_reserve(skb, size - len);
 
        SOCK_DEBUG(sk, "AX.25: Appending user data\n");
@@ -2052,14 +2045,15 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                        return -ENOTCONN;
                }
 
-               ax25_output(sk->protinfo.ax25, skb);    /* Shove it onto the queue and kick */
+               ax25_output(sk->protinfo.ax25, 1, skb); /* Shove it onto the queue and kick */
 
                return len;
        } else {
                asmptr = skb_push(skb, 1 + size_ax25_addr(dp));
 
                SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
-               if(dp != 0)
+
+               if (dp != NULL)
                        SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
 
                /* Build an AX.25 header */
@@ -2081,7 +2075,6 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 
                return len;
        }
-
 }
 
 static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags,
@@ -2468,9 +2461,10 @@ void ax25_queue_xmit(struct sk_buff *skb)
 
        skb->protocol = htons(ETH_P_AX25);
        skb->dev      = ax25_fwd_dev(skb->dev);
+       skb->arp      = 1;
 
-       ptr = skb_push(skb, 1);
-       *ptr++ = 0;                     /* KISS */
+       ptr    = skb_push(skb, 1);
+       *ptr++ = 0x00;                  /* KISS */
 
        dev_queue_xmit(skb);
 }
@@ -2568,7 +2562,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
 
                        skb_pull(ourskb, AX25_HEADER_LEN - 1);  /* Keep PID */
 
-                       ax25_send_frame(ourskb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
+                       ax25_send_frame(ourskb, 1, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
 
                        return 1;
                }
index 3320cdcd3131b41eb0f73d599a86e9de923275b9..ba4908fedc7e325ec584ba167fe798d4e52a33f6 100644 (file)
@@ -90,11 +90,7 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb)
                                                return 1;
                                        }
 
-                                       skbn->arp  = 1;
-                                       skbn->dev  = ax25->device;
-
-                                       if (ax25->sk != NULL)
-                                               skb_set_owner_r(skbn, ax25->sk);
+                                       skbn->dev = ax25->device;
 
                                        skb_reserve(skbn, AX25_MAX_HEADER_LEN);
 
@@ -156,7 +152,7 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
        if (skb == NULL) return 0;
 
        ax25->idletimer = ax25->idle;
-       
+
        pid = *skb->data;
 
 #ifdef CONFIG_INET
@@ -217,7 +213,6 @@ static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                case AX25_UA:
                        if (pf || dama) {
                                if (dama) ax25_dama_on(ax25); /* bke */
-                                       
                                ax25_calculate_rtt(ax25);
                                ax25->t1timer = 0;
                                ax25->t3timer = ax25->t3;
@@ -228,7 +223,6 @@ static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                                ax25->state   = AX25_STATE_3;
                                ax25->n2count = 0;
                                ax25->dama_slave = dama;        /* bke */
-                                       
                                if (ax25->sk != NULL) {
                                        ax25->sk->state = TCP_ESTABLISHED;
                                        /* For WAIT_SABM connections we will produce an accept ready socket here */
@@ -298,22 +292,8 @@ static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                        }
                        break;
 
-               case AX25_UA:
-                       if (pf) {
-                               ax25->state = AX25_STATE_0;
-                               ax25_dama_off(ax25);
-                               if (ax25->sk != NULL) {
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = 0;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
-                       }
-                       break;
-
                case AX25_DM:
+               case AX25_UA:
                        if (pf) {
                                ax25->state = AX25_STATE_0;
                                ax25_dama_off(ax25);
@@ -358,24 +338,15 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
 
        switch (frametype) {
                case AX25_SABM:
-                       if (dama) ax25_dama_on(ax25);
-                       ax25->modulus   = AX25_MODULUS;
-                       ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->condition = 0x00;
-                       ax25->t1timer   = 0;
-                       ax25->t3timer   = ax25->t3;
-                       ax25->idletimer = ax25->idle;
-                       ax25->vs        = 0;
-                       ax25->va        = 0;
-                       ax25->vr        = 0;
-                       ax25->dama_slave = dama;
-                       break;
-
                case AX25_SABME:
                        if (dama) ax25_dama_on(ax25);
-                       ax25->modulus   = AX25_EMODULUS;
-                       ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+                       if (frametype == AX25_SABM) {
+                               ax25->modulus = AX25_MODULUS;
+                               ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
+                       } else {
+                               ax25->modulus = AX25_EMODULUS;
+                               ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+                       }
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
                        ax25->condition = 0x00;
                        ax25->t1timer   = 0;
@@ -385,6 +356,7 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                        ax25->va        = 0;
                        ax25->vr        = 0;
                        ax25->dama_slave = dama;
+                       ax25_requeue_frames(ax25);
                        break;
 
                case AX25_DISC:
@@ -418,20 +390,12 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                        }
                        break;
 
-               case AX25_RNR:
-                       ax25->condition |= AX25_COND_PEER_RX_BUSY;
-                       ax25_check_need_response(ax25, type, pf);
-                       if (ax25_validate_nr(ax25, nr)) {
-                               ax25_check_iframes_acked(ax25, nr);
-                               dama_check_need_response(ax25, type, pf);
-                       } else {
-                               ax25_nr_error_recovery(ax25);
-                               ax25->state = AX25_STATE_1;
-                       }
-                       break;
-
                case AX25_RR:
-                       ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+               case AX25_RNR:
+                       if (frametype == AX25_RR)
+                               ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+                       else
+                               ax25->condition |= AX25_COND_PEER_RX_BUSY;
                        ax25_check_need_response(ax25, type, pf);
                        if (ax25_validate_nr(ax25, nr)) {
                                ax25_check_iframes_acked(ax25, nr);
@@ -546,27 +510,15 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
 
        switch (frametype) {
                case AX25_SABM:
-                       if (dama) ax25_dama_on(ax25);
-                       ax25->dama_slave = dama;
-                       ax25->modulus   = AX25_MODULUS;
-                       ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->condition = 0x00;
-                       ax25->t1timer   = 0;
-                       ax25->t3timer   = ax25->t3;
-                       ax25->idletimer = ax25->idle;
-                       ax25->vs        = 0;
-                       ax25->va        = 0;
-                       ax25->vr        = 0;
-                       ax25->state     = AX25_STATE_3;
-                       ax25->n2count   = 0;
-                       break;
-
                case AX25_SABME:
                        if (dama) ax25_dama_on(ax25);
-                       ax25->dama_slave = dama;
-                       ax25->modulus   = AX25_EMODULUS;
-                       ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+                       if (frametype == AX25_SABM) {
+                               ax25->modulus = AX25_MODULUS;
+                               ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
+                       } else {
+                               ax25->modulus = AX25_EMODULUS;
+                               ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+                       }
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
                        ax25->condition = 0x00;
                        ax25->t1timer   = 0;
@@ -577,6 +529,8 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                        ax25->vr        = 0;
                        ax25->state     = AX25_STATE_3;
                        ax25->n2count   = 0;
+                       ax25->dama_slave = dama;
+                       ax25_requeue_frames(ax25);
                        break;
 
                case AX25_DISC:
@@ -610,8 +564,12 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                        }
                        break;
 
+               case AX25_RR:
                case AX25_RNR:
-                       ax25->condition |= AX25_COND_PEER_RX_BUSY;
+                       if (frametype == AX25_RR)
+                               ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+                       else
+                               ax25->condition |= AX25_COND_PEER_RX_BUSY;
                        if (type == AX25_RESPONSE && pf) {
                                ax25->t1timer = 0;
                                if (ax25_validate_nr(ax25, nr)) {
@@ -627,38 +585,6 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                                }
                                break;
                        }
-
-                       ax25_check_need_response(ax25, type, pf);
-                       if (ax25_validate_nr(ax25, nr)) {
-                               ax25_frames_acked(ax25, nr);
-                               dama_check_need_response(ax25, type, pf);
-                       } else {
-                               ax25_nr_error_recovery(ax25);
-                               ax25->state = AX25_STATE_1;
-                       }
-                       break;
-
-               case AX25_RR:
-                       ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-                       if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) {
-                               ax25->t1timer = 0;
-                               if (ax25_validate_nr(ax25, nr)) {
-                                       ax25_frames_acked(ax25, nr);
-                                       if (ax25->vs == ax25->va) {
-                                               ax25->t3timer = ax25->t3;
-                                               ax25->n2count = 0;
-                                               ax25->state   = AX25_STATE_3;
-                                       } else {
-                                               ax25_requeue_frames(ax25);
-                                       }
-                                       dama_check_need_response(ax25, type, pf);
-                               } else {
-                                       ax25_nr_error_recovery(ax25);
-                                       ax25->state = AX25_STATE_1;
-                               }
-                               break;
-                       }
-
                        ax25_check_need_response(ax25, type, pf);
                        if (ax25_validate_nr(ax25, nr)) {
                                ax25_frames_acked(ax25, nr);
@@ -689,8 +615,7 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype
                                }
                                break;
                        }
-
-                       ax25_check_need_response(ax25, type, pf);       
+                       ax25_check_need_response(ax25, type, pf);
                        if (ax25_validate_nr(ax25, nr)) {
                                ax25_frames_acked(ax25, nr);
                                if(ax25->vs != ax25->va) {
index 2ebb77f560666d0267546351db6bc0d522b2f1bb..0c696cf91bc19344dacd8bee790566f08c327493 100644 (file)
 #include <linux/interrupt.h>
 
 /*
- * All outgoing AX.25 I frames pass via this routine. Therefore this is
- * where the fragmentation of frames takes place.
+ *     All outgoing AX.25 I frames pass via this routine. Therefore this is
+ *     where the fragmentation of frames takes place. If fragment is set to
+ *     zero then we are not allowed to do fragmentation, even if the frame
+ *     is too large.
  */
-void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
+void ax25_output(ax25_cb *ax25, int fragment, struct sk_buff *skb)
 {
        struct sk_buff *skbn;
        unsigned char *p;
@@ -67,7 +69,7 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
 
        mtu = ax25->paclen;
 
-       if ((skb->len - 1) > mtu) {
+       if ((skb->len - 1) > mtu && fragment) {
                if (*skb->data == AX25_P_TEXT) {
                        skb_pull(skb, 1); /* skip PID */
                        ka9qfrag = 0;
@@ -96,8 +98,6 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
                        
                        restore_flags(flags);
                        
-                       skbn->arp  = 1;
-
                        len = (mtu > skb->len) ? skb->len : mtu;
 
                        if (ka9qfrag == 1) {
@@ -257,7 +257,6 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
        ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
        build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-       skb->arp      = 1;
        skb->dev      = ax25->device;
        skb->priority = SOPRI_NORMAL;
 
@@ -397,9 +396,9 @@ void dama_enquiry_response(ax25_cb *ax25)
                if (!ax25o->dama_slave)
                        continue;
 
-               if ( !(ax25o->condition & AX25_COND_PEER_RX_BUSY) && 
-                    (ax25o->state == AX25_STATE_3 || 
-                    (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
+               if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && 
+                   (ax25o->state == AX25_STATE_3 || 
+                   (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
                        ax25_requeue_frames(ax25o);
                        ax25_kick(ax25o);
                }
index afbe00cd4bd70387fda26a740b81584c88431e69..7c56603361bc7374c32e238ba71e59cee075224c 100644 (file)
@@ -486,7 +486,7 @@ void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *
                return;
        }
 
-       memcpy(&dest, skb->data    , AX25_ADDR_LEN);
+       memcpy(&dest, skb->data + 0, AX25_ADDR_LEN);
        memcpy(&src,  skb->data + 7, AX25_ADDR_LEN);
 
        bp = skb_push(skb, len);
@@ -638,11 +638,11 @@ struct device *ax25_fwd_dev(struct device *dev)
 
        return ax25_dev->forward;
 }
-      
+
 #ifdef MODULE
 
 /*
- *    Free all memory associated with routing and device structures.
+ *     Free all memory associated with routing and device structures.
  */
 void ax25_rt_free(void)
 {
index f884a8f34561295dcc4d489b6e392c2382b366af..b1b552a4b05d8dfb393681b2ad84777b12de769a 100644 (file)
@@ -101,7 +101,8 @@ void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
        }
 }
 
-/* Maybe this should be your ax25_invoke_retransmission(), which appears
+/*
+ * Maybe this should be your ax25_invoke_retransmission(), which appears
  * to be used but not do anything.  ax25_invoke_retransmission() used to
  * be in AX 0.29, but has now gone in 0.30.
  */
@@ -260,11 +261,9 @@ void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, a
        /*
         *      Do the address ourselves
         */
-
        dptr  = skb_push(skb, size_ax25_addr(digi));
        dptr += build_ax25_addr(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
 
-       skb->arp      = 1;
        skb->dev      = dev;
        skb->priority = SOPRI_NORMAL;
 
@@ -278,11 +277,19 @@ unsigned short ax25_calculate_t1(ax25_cb *ax25)
 {
        int n, t = 2;
 
-       if (ax25->backoff) {
-               for (n = 0; n < ax25->n2count; n++)
-                       t *= 2;
+       switch (ax25->backoff) {
+               case 0:
+                       break;
 
-               if (t > 8) t = 8;
+               case 1:
+                       t += 2 * ax25->n2count;
+                       break;
+
+               case 2:
+                       for (n = 0; n < ax25->n2count; n++)
+                               t *= 2;
+                       if (t > 8) t = 8;
+                       break;
        }
 
        return t * ax25->rtt;
@@ -306,7 +313,7 @@ void ax25_calculate_rtt(ax25_cb *ax25)
 /*
  *     Digipeated address processing
  */
+
 
 /*
  *     Given an AX.25 address pull of to, from, digi list, command/response and the start of data
@@ -333,8 +340,10 @@ unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, a
        /* Copy to, from */
        if (dest != NULL) 
                memcpy(dest, buf + 0, AX25_ADDR_LEN);
+
        if (src != NULL)  
                memcpy(src,  buf + 7, AX25_ADDR_LEN);
+
        buf += 2 * AX25_ADDR_LEN;
        len -= 2 * AX25_ADDR_LEN;
        digi->lastrepeat = -1;
@@ -486,7 +495,6 @@ static int ax25_list_length(struct sk_buff_head *list, struct sk_buff *skb)
 /*
  *     count the number of buffers of one socket on the write/ack-queue
  */
-
 int ax25_queue_length(ax25_cb *ax25, struct sk_buff *skb)
 {
        return ax25_list_length(&ax25->write_queue, skb) + ax25_list_length(&ax25->ack_queue, skb);
@@ -500,7 +508,6 @@ int ax25_queue_length(ax25_cb *ax25, struct sk_buff *skb)
  *
  *     Not to mention this request isn't currently reliable.
  */
 void ax25_kiss_cmd(ax25_cb *ax25, unsigned char cmd, unsigned char param)
 {
        struct sk_buff *skb;
@@ -539,6 +546,7 @@ void ax25_dama_off(ax25_cb *ax25)
                return;
 
        ax25->dama_slave = 0;
+
        if (ax25_dev_is_dama_slave(ax25->device) == 0) {
                SOCK_DEBUG(ax25->sk, "ax25_dama_off: DAMA off\n");
                ax25_kiss_cmd(ax25, 5, 0);
index fb6e761fdf2a7e935b4d165b043878ef12b9ef76..44cd775a746d709e953e0810e92151374fdcc906 100644 (file)
 static void ax25_timer(unsigned long);
 
 /*
- *     Linux set/reset timer routines
+ *     Linux set timer
  */
 void ax25_set_timer(ax25_cb *ax25)
 {
        unsigned long flags;    
 
-       save_flags(flags);
-       cli();
-       del_timer(&ax25->timer);
-       restore_flags(flags);
-
-       ax25->timer.next     = ax25->timer.prev = NULL; 
-       ax25->timer.data     = (unsigned long)ax25;
-       ax25->timer.function = &ax25_timer;
-
-       ax25->timer.expires = jiffies + 10;
-       add_timer(&ax25->timer);
-}
-
-static void ax25_reset_timer(ax25_cb *ax25)
-{
-       unsigned long flags;
-       
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        del_timer(&ax25->timer);
        restore_flags(flags);
 
        ax25->timer.data     = (unsigned long)ax25;
        ax25->timer.function = &ax25_timer;
        ax25->timer.expires  = jiffies + 10;
+
        add_timer(&ax25->timer);
 }
 
@@ -158,7 +141,7 @@ static void ax25_timer(unsigned long param)
                                ax25->sk->dead      = 1;
                        }
 
-                       ax25_reset_timer(ax25);
+                       ax25_set_timer(ax25);
                        return;
                }
 
@@ -207,9 +190,8 @@ static void ax25_timer(unsigned long param)
 
        /* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */
        /*                nevertheless we have to re-enqueue the timer struct...   */
-
        if (ax25->t1timer == 0 || --ax25->t1timer > 0) {
-               ax25_reset_timer(ax25);
+               ax25_set_timer(ax25);
                return;
        }
 
@@ -229,7 +211,7 @@ static void ax25_timer(unsigned long param)
  *                Thus we'll have to do parts of our T1 handling in
  *                ax25_enquiry_response().
  */
-void ax25_t1_timeout(ax25_cb * ax25)
+void ax25_t1_timeout(ax25_cb *ax25)
 {      
        switch (ax25->state) {
                case AX25_STATE_1: 
index da40a3dbb800efe7b68822cd39b4d54c61dddc7e..6ef3f13b318d0e61b27d08b492a985b5eda4dfe1 100644 (file)
@@ -11,7 +11,7 @@
 
 static int min_ax25[] = {0, 0, 0, 0, 0, 1,  1,                1,                1,
                         0,                   0,  1,   1,  1, 0x00};
-static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ,
+static int max_ax25[] = {1, 1, 1, 2, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ,
        3600 * AX25_SLOWHZ, 65535 * AX25_SLOWHZ, 31, 512, 20, 0x03};
 
 static struct ctl_table_header *ax25_table_header;
index c7122e2b4b8f85d14272c6963a82270773c19b98..766d27a0b8387c28f59028accafb6477cc6a3dd8 100644 (file)
@@ -1006,17 +1006,19 @@ static int dev_ifconf(char *arg)
 #ifdef CONFIG_PROC_FS
 static int sprintf_stats(char *buffer, struct device *dev)
 {
-       struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
+       struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
        int size;
        
        if (stats)
-               size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",
+               size = sprintf(buffer, "%6s:%8ld %7ld %4ld %4ld %4ld %4ld %8ld %8ld %4ld %4ld %4ld %5ld %4ld\n",
                   dev->name,
+                  stats->rx_bytes,
                   stats->rx_packets, stats->rx_errors,
                   stats->rx_dropped + stats->rx_missed_errors,
                   stats->rx_fifo_errors,
                   stats->rx_length_errors + stats->rx_over_errors
                   + stats->rx_crc_errors + stats->rx_frame_errors,
+                  stats->tx_bytes,
                   stats->tx_packets, stats->tx_errors, stats->tx_dropped,
                   stats->tx_fifo_errors, stats->collisions,
                   stats->tx_carrier_errors + stats->tx_aborted_errors
@@ -1043,7 +1045,7 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy
 
 
        size = sprintf(buffer, "Inter-|   Receive                  |  Transmit\n"
-                           " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
+                           " face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n");
        
        pos+=size;
        len+=size;
index a5198472cc9f8402d355e1e1083e43827ab4fed7..c47076a0c6987c0624e826d893db6daefd9aa825 100644 (file)
@@ -10,8 +10,9 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/firewall.h>
+#include <asm/semaphore.h>
 
-static int firewall_lock=0;
+struct semaphore firewall_sem = MUTEX; 
 static int firewall_policy[NPROTO];
 static struct firewall_ops *firewall_chain[NPROTO];
 
@@ -30,13 +31,7 @@ int register_firewall(int pf, struct firewall_ops *fw)
         *      Don't allow two people to adjust at once.
         */
 
-       /*
-        *      FIXME: Swap for a kernel semaphore object
-        */
-        
-       while(firewall_lock)
-               schedule();
-       firewall_lock=1;
+       down(&firewall_sem); 
 
        p=&firewall_chain[pf];
 
@@ -47,7 +42,6 @@ int register_firewall(int pf, struct firewall_ops *fw)
                p=&((*p)->next);
        }
 
-
        /*
         * We need to use a memory barrier to make sure that this
         * works correctly even in SMP with weakly ordered writes.
@@ -56,6 +50,7 @@ int register_firewall(int pf, struct firewall_ops *fw)
         * chain), but not wrt itself (so you can't call this from
         * an interrupt. Not that you'd want to).
         */
+
        fw->next=*p;
        mb();
        *p = fw;
@@ -64,7 +59,7 @@ int register_firewall(int pf, struct firewall_ops *fw)
         *      And release the sleep lock
         */
 
-       firewall_lock=0;
+       up(&firewall_sem); 
        return 0;
 }
 
@@ -83,9 +78,7 @@ int unregister_firewall(int pf, struct firewall_ops *fw)
         *      Don't allow two people to adjust at once.
         */
 
-       while(firewall_lock)
-               schedule();
-       firewall_lock=1;
+       down(&firewall_sem); 
 
        nl=&firewall_chain[pf];
 
@@ -95,12 +88,12 @@ int unregister_firewall(int pf, struct firewall_ops *fw)
                {
                        struct firewall_ops *f=fw->next;
                        *nl = f;
-                       firewall_lock=0;
+                       up(&firewall_sem); 
                        return 0;
                }
                nl=&((*nl)->next);
        }
-       firewall_lock=0;
+       up(&firewall_sem);
        return -ENOENT;
 }
 
index 1acdc47d19136075f8efa23d1e68488fd381adb4..9bc21ffc57f2ea95294c8b283490d8db485017bb 100644 (file)
@@ -11,7 +11,8 @@
  *             Andrew Lunn     :       Errors in iovec copying.
  *             Pedro Roque     :       Added memcpy_fromiovecend and
  *                                     csum_..._fromiovecend.
- *      Andi Kleen  :   fixed error handling for 2.1
+ *             Andi Kleen      :       fixed error handling for 2.1
+ *             Alexey Kuznetsov:       2.1 optimisations
  */
 
 
@@ -35,6 +36,9 @@ extern inline int min(int x, int y)
 /*
  *     Verify iovec
  *     verify area does a simple check for completly bogus addresses
+ *
+ *     Save time not doing verify_area. copy_*_user will make this work
+ *     in any case.
  */
 
 int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
@@ -48,14 +52,10 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
                if(mode==VERIFY_READ)
                {
                        err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
-               }
-               else
-               {
-                       err=verify_area(mode, m->msg_name, m->msg_namelen);
+                       if(err<0)
+                               return err;
                }
                
-               if(err<0)
-                       return err;
                m->msg_name = address;
        } else
                m->msg_name = NULL;
@@ -67,27 +67,18 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
                        return -ENOMEM;
        }
        
-       for(ct=0;ct<m->msg_iovlen;ct++)
+       err = copy_from_user(iov, m->msg_iov, sizeof(struct iovec)*m->msg_iovlen);
+       if (err)
        {
-               err = copy_from_user(&iov[ct], &m->msg_iov[ct],
-                                    sizeof(struct iovec));
-               if (err)
-               {
-                       if (m->msg_iovlen > UIO_FASTIOV)
-                               kfree(iov);
-                       return err;
-               }
-               
-               err = verify_area(mode, iov[ct].iov_base, iov[ct].iov_len);
-               if(err)
-               {
-                       if (m->msg_iovlen > UIO_FASTIOV)
-                               kfree(iov);
-                       return err;
-               }
-               len+=iov[ct].iov_len;
+               if (m->msg_iovlen > UIO_FASTIOV)
+                       kfree(iov);
+               return -EFAULT;
        }
-       m->msg_iov=&iov[0];
+
+       for(ct=0;ct<m->msg_iovlen;ct++)
+               len+=iov[ct].iov_len;
+
+       m->msg_iov=iov;
        return len;
 }
 
@@ -131,7 +122,7 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
                        err = copy_from_user(kdata, iov->iov_base, copy);
                        if (err)
                        {
-                               return err; 
+                               return -EFAULT;
                        }
                        len-=copy;
                        kdata+=copy;
@@ -171,7 +162,7 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
                        err = copy_from_user(kdata, base, copy);
                        if (err)
                        {
-                               return err;
+                               return -EFAULT;
                        }
                        len-=copy;
                        kdata+=copy;
@@ -185,7 +176,7 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
                err = copy_from_user(kdata, iov->iov_base, copy);
                if (err)
                {
-                       return err;
+                       return -EFAULT;
                }
                len-=copy;
                kdata+=copy;
index 0c220b87b8f58f93a9ee96ddfd0feebf84b2c95a..2d6042e50de48526e9f45c2f58021cd7fd54c4ed 100644 (file)
@@ -1,7 +1,6 @@
 #
 # IP configuration
 #
-bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD
 bool 'IP: multicasting' CONFIG_IP_MULTICAST
 if [ "$CONFIG_FIREWALL" = "y" ]; then
   bool 'IP: firewalling' CONFIG_IP_FIREWALL
@@ -10,16 +9,12 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then
        bool 'IP: firewall packet netlink device' CONFIG_IP_FIREWALL_NETLINK
     fi
     bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE
-    if [ "$CONFIG_IP_FORWARD" = "y" ]; then
-      bool 'IP: masquerading' CONFIG_IP_MASQUERADE
-      if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
-        comment 'Protocol-specific masquerading support will be built as modules.'
-      fi
-# hmm... but transparent proxy is useful without forwarding too..
-# i.e. non-lan users will get anonftpd instead of wu-ftpd...
-      bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY
-      bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
+    bool 'IP: masquerading' CONFIG_IP_MASQUERADE
+    if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
+      comment 'Protocol-specific masquerading support will be built as modules.'
     fi
+    bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY
+    bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
   fi
 fi
 bool 'IP: accounting' CONFIG_IP_ACCT
index 1c67348014a314ba99e062a8c29a7945619cb0f6..acc2366e1de3a7d72c21a7e1345e3499155d6b66 100644 (file)
@@ -1732,15 +1732,21 @@ void inet_proto_init(struct net_proto *pro)
        /*
         *      Set the ARP module up
         */
+
        arp_init();
+
        /*
         *      Set the IP module up
         */
+
        ip_init();
+
        /*
         *      Set the ICMP layer up
         */
+
        icmp_init(&inet_family_ops);
+
        /*
         *      Set the firewalling up
         */
@@ -1757,7 +1763,7 @@ void inet_proto_init(struct net_proto *pro)
 #if defined(CONFIG_IP_MROUTE)
        ip_mr_init();
 #endif
-
+       
        /*
         *  Initialise AF_INET alias type (register net_alias_type)
         */
index e10c9fce012dbdad22c3a3144633b4107913faa8..a913b45b19fbecf775b97ccb0d60bb74f9b48f99 100644 (file)
@@ -1552,7 +1552,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        }
 
        start_bh_atomic();
-       arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags));
+       arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags) && dev->type != ARPHRD_METRICOM);
        end_bh_atomic();
        kfree_skb(skb, FREE_READ);
        return 0;
@@ -1617,6 +1617,13 @@ int arp_req_set(struct arpreq *r, struct device * dev)
                if (!dev)
                        dev = rt->u.dst.dev;
                if (rt->rt_flags&(RTF_LOCAL|RTF_BROADCAST|RTF_MULTICAST|RTCF_NAT)) {
+                       if (rt->rt_flags&RTF_BROADCAST &&
+                           dev->type == ARPHRD_METRICOM &&
+                           r->arp_ha.sa_family == ARPHRD_METRICOM) {
+                               memcpy(dev->broadcast, r->arp_ha.sa_data, dev->addr_len);
+                               ip_rt_put(rt);
+                               return 0;
+                       }
                        ip_rt_put(rt);
                        return -EINVAL;
                }
index e99bf15edac645d567e488b2e219b613d16c922d..6270f1fbf5d7a1413982374984504dd7968da74d 100644 (file)
@@ -1571,11 +1571,9 @@ static int rtcmsg_process(struct nlmsghdr *n, struct in_rtctlmsg *r)
 
 static int get_rt_from_user(struct in_rtmsg *rtm, void *arg)
 {
-       int err;
        struct rtentry r;
 
-       err = copy_from_user(&r, arg, sizeof(struct rtentry));
-       if (err)
+       if (copy_from_user(&r, arg, sizeof(struct rtentry)))
                return -EFAULT;
        if (r.rt_dev) {
                struct device *dev;
@@ -1662,18 +1660,16 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
                case SIOCRTMSG:
                        if (!suser())
                                return -EPERM;
-                       err = copy_from_user(&dummy_nlh, arg, sizeof(dummy_nlh));
-                       if (err)
-                               return err;
+                       if (copy_from_user(&dummy_nlh, arg, sizeof(dummy_nlh)))
+                               return -EFAULT;
                        switch (dummy_nlh.nlmsg_type)
                        {
                        case RTMSG_NEWROUTE:
                        case RTMSG_DELROUTE:
                                if (dummy_nlh.nlmsg_len < sizeof(m.rtmsg) + sizeof(dummy_nlh))
                                        return -EINVAL;
-                               err = copy_from_user(&m.rtmsg, arg+sizeof(dummy_nlh), sizeof(m.rtmsg));
-                               if (err)
-                                       return err;
+                               if (copy_from_user(&m.rtmsg, arg+sizeof(dummy_nlh), sizeof(m.rtmsg)))
+                                       return -EFAULT;
                                fib_lock();
                                err = rtmsg_process(&dummy_nlh, &m.rtmsg);
                                fib_unlock();
@@ -1682,9 +1678,8 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
                        case RTMSG_DELRULE:
                                if (dummy_nlh.nlmsg_len < sizeof(m.rtrmsg) + sizeof(dummy_nlh))
                                        return -EINVAL;
-                               err = copy_from_user(&m.rtrmsg, arg+sizeof(dummy_nlh), sizeof(m.rtrmsg));
-                               if (err)
-                                       return err;
+                               if (copy_from_user(&m.rtrmsg, arg+sizeof(dummy_nlh), sizeof(m.rtrmsg)))
+                                       return -EFAULT;
                                fib_lock();
                                err = rtrulemsg_process(&dummy_nlh, &m.rtrmsg);
                                fib_unlock();
@@ -1693,9 +1688,8 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
                        case RTMSG_DELDEVICE:
                                if (dummy_nlh.nlmsg_len < sizeof(m.ifmsg) + sizeof(dummy_nlh))
                                        return -EINVAL;
-                               err = copy_from_user(&m.ifmsg, arg+sizeof(dummy_nlh), sizeof(m.ifmsg));
-                               if (err)
-                                       return err;
+                               if (copy_from_user(&m.ifmsg, arg+sizeof(dummy_nlh), sizeof(m.ifmsg)))
+                                       return -EFAULT;
                                fib_lock();
                                err = ifmsg_process(&dummy_nlh, &m.ifmsg);
                                fib_unlock();
@@ -1703,9 +1697,8 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
                        case RTMSG_CONTROL:
                                if (dummy_nlh.nlmsg_len < sizeof(m.rtcmsg) + sizeof(dummy_nlh))
                                        return -EINVAL;
-                               err = copy_from_user(&m.rtcmsg, arg+sizeof(dummy_nlh), sizeof(m.rtcmsg));
-                               if (err)
-                                       return err;
+                               if (copy_from_user(&m.rtcmsg, arg+sizeof(dummy_nlh), sizeof(m.rtcmsg)))
+                                       return -EFAULT;
                                fib_lock();
                                err = rtcmsg_process(&dummy_nlh, &m.rtcmsg);
                                fib_unlock();
index 5f4d3562084f39c38d81b72081a77c7a0adc9d3e..731de734671657509324b93ec771d9179d9d7ac0 100644 (file)
@@ -173,7 +173,6 @@ int ip_forward(struct sk_buff *skb)
                        }
                        if (rt->rt_flags&RTCF_MASQ)
                                goto skip_call_fw_firewall;
-               }
 #endif
 #ifdef CONFIG_FIREWALL
                fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL);
@@ -191,6 +190,8 @@ int ip_forward(struct sk_buff *skb)
 #endif
 
 #ifdef CONFIG_IP_MASQUERADE
+               }
+
 skip_call_fw_firewall:
                /*
                 * If this fragment needs masquerading, make it so...
@@ -219,7 +220,7 @@ skip_call_fw_firewall:
                }
 
 #ifdef CONFIG_FIREWALL
-               if ((fw_res = call_out_firewall(PF_INET, skb->dev, iph, NULL)) < FW_ACCEPT) {
+               if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL)) < FW_ACCEPT) {
                        /* FW_ACCEPT and FW_MASQUERADE are treated equal:
                           masquerading is only supported via forward rules */
                        if (fw_res == FW_REJECT)
index 1d4df36f94cd3a16d8a21cc861de0a637904c527..547f4f14493022a1dac0ad6aa1f9d4d37d490e28 100644 (file)
@@ -1309,14 +1309,13 @@ void ip_fw_init(void)
 
        if(register_firewall(PF_INET,&ipfw_ops)<0)
                panic("Unable to register IP firewall.\n");
-
 #ifdef CONFIG_PROC_FS          
        proc_net_register(&proc_net_ipfwin);
        proc_net_register(&proc_net_ipfwout);
        proc_net_register(&proc_net_ipfwfwd);
 #endif
 #endif
-        
+
 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
        /* Register for device up/down reports */
        register_netdevice_notifier(&ipfw_dev_notifier);
index d39f921147fe7c7b6c9cbc28309abfa667b103c5..79443bfe925d8b7983ccb3483adc75d8f273a1c4 100644 (file)
@@ -799,6 +799,7 @@ static int tcp_append_tail(struct sock *sk, struct sk_buff *skb, u8 *from,
 int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                   int len, int flags)
 {
+       int err = 0;
        int copied  = 0;
        struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 
@@ -849,6 +850,8 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                        int tmp;
                        struct sk_buff *skb;
 
+                       if (err)
+                               return (err);
                        /*
                         * Stop on errors
                         */
@@ -1030,7 +1033,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                                skb->h.th->urg_ptr = ntohs(copy);
                        }
 
-                       skb->csum = csum_partial_copy_fromuser(from,
+                       skb->csum = csum_partial_copy_from_user(&err, from,
                                        skb_put(skb, copy), copy, 0);
                
                        from += copy;
@@ -1044,6 +1047,9 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
 
        sk->err = 0;
 
+       if (err)
+               return (err);
+
        return copied;
 }
 
@@ -1124,7 +1130,7 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
                                                       msg->msg_name);       
                }
                if(addr_len)
-                       *addr_len= tp->af_specific->sockaddr_len;
+                       *addr_len = tp->af_specific->sockaddr_len;
                /* 
                 *      Read urgent data
                 */
@@ -1173,14 +1179,14 @@ static void cleanup_rbuf(struct sock *sk)
                        break;
                tcp_eat_skb(sk, skb);
        }
-
+       
        SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
-
-       /*
-        *  We send a ACK if the sender is blocked
-        *  else let tcp_data deal with the acking policy.
-        */
-
+       
+       /*
+        *  We send a ACK if the sender is blocked
+        *  else let tcp_data deal with the acking policy.
+        */
+  
        if (sk->delayed_acks)
        {
                struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
@@ -1456,7 +1462,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                                               msg->msg_name);       
        }
        if(addr_len)
-               *addr_len = tp->af_specific->sockaddr_len;
+               *addr_len= tp->af_specific->sockaddr_len;
 
        remove_wait_queue(sk->sleep, &wait);
        current->state = TASK_RUNNING;
index 4a60aff40c76c394cea451c012f050557d115a18..093522d631e7bd604d21b2d472feac262bfb2578 100644 (file)
@@ -760,21 +760,19 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
        }
        else
                tcp_clear_xmit_timer(sk, TIME_RETRANS);
-
-
+       
        tcp_fast_retrans(sk, ack_seq, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE)));
 
        /*
         *      Remember the highest ack received.
         */
-
+        
        tp->snd_una = ack;
-
        return 1;
 
 uninteresting_ack:
 
-       SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
+       SOCK_DEBUG(sk, "Ack ignored %u %u\n",ack,tp->snd_nxt);
        return 0;
 }
 
@@ -893,21 +891,18 @@ static void  tcp_ofo_queue(struct sock *sk)
                        break;
 
                if (!after(skb->end_seq, tp->rcv_nxt)) {
-                       SOCK_DEBUG(sk, "ofo packet already received \n");
+                       SOCK_DEBUG(sk, "ofo packet was allready received \n");
                        skb_unlink(skb);
                        kfree_skb(skb, FREE_READ);
                        
                        continue;
                }
-               SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
-                              tp->rcv_nxt, skb->seq, skb->end_seq);
-               
-               skb_unlink(skb);
+               SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
 
+               skb_unlink(skb);
                 
                skb_queue_tail(&sk->receive_queue, skb);
 
-
                tp->rcv_nxt = skb->end_seq;
        }
 }
@@ -970,9 +965,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                 * Partial packet
                 * seq < rcv_next < end_seq
                 */
-               SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
-                              tp->rcv_nxt, skb->seq, skb->end_seq);
-
+               SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
                skb_queue_tail(&sk->receive_queue, skb);
 
                tp->rcv_nxt = skb->end_seq;
@@ -999,8 +992,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 
        tp->pred_flags = 0;
 
-       SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
-                      tp->rcv_nxt, skb->seq, skb->end_seq);
+       SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
 
        if (skb_peek(&sk->out_of_order_queue) == NULL) {
                skb_queue_head(&sk->out_of_order_queue,skb);
@@ -1078,16 +1070,16 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
        }
 
        sk->delayed_acks++;
-
+       
        /*
         *      Now tell the user we may have some data. 
         */
-
-       if (!sk->dead)
+        
+       if (!sk->dead) 
        {
-               SOCK_DEBUG(sk, "Data Wakeup.\n");
+               SOCK_DEBUG(sk, "Data wakeup.\n");
                sk->data_ready(sk,0);
-       }
+       } 
        return(1);
 }
 
index 96ffdc3b2c6ab36eccafb982b7a3cbd2650e3a2d..cc707111856c32afbca31750749cd54c34ca6401 100644 (file)
@@ -1004,6 +1004,8 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
        default:
                /* CHECKSUM_UNNECESSARY */
        }
+       
+       tcp_statistics.TcpInSegs++;
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
        if (IPCB(skb)->redirport)
index cc124d3a07c570a2b224311e7458ec0a681448be..961d127c89d2da54798af2a087ab65cfcd5d2ec6 100644 (file)
@@ -778,8 +778,8 @@ int udp_rcv(struct sk_buff *skb, unsigned short len)
                /* <mea@utu.fi> wants to know, who sent it, to
                   go and stomp on the garbage sender... */
 
-         /* RFC1122: OK.  Discards the bad packet silently (as far as */
-         /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
+               /* RFC1122: OK.  Discards the bad packet silently (as far as */
+               /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
 
                NETDEBUG(printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
                       ntohl(saddr),ntohs(uh->source),
@@ -793,11 +793,17 @@ int udp_rcv(struct sk_buff *skb, unsigned short len)
 
        len = ulen;
 
-       /* Wrong! --ANK */
+       /*
+        *      FIXME:
+        *      Trimming things wrongly. We must adjust the base/end to allow
+        *      for the headers we keep!
+        *               --ANK 
+        */
        skb_trim(skb,len);
 
 
-       if (rt->rt_flags&(RTF_BROADCAST|RTF_MULTICAST)) {
+       if (rt->rt_flags&(RTF_BROADCAST|RTF_MULTICAST))
+       {
                /*
                 *      Multicasts and broadcasts go to each listener.
                 */
index 8d95efe5af7c1d016aeca48cdf395c5dc77451ee..fa42a0131faae85cf6250007351a9903c8520b2d 100644 (file)
@@ -129,6 +129,7 @@ static int inet6_create(struct socket *sock, int protocol)
        }
        
        sock_init_data(sock,sk);
+       sk->zapped=0;
 
        sk->family = AF_INET6;
        sk->protocol = protocol;
@@ -779,8 +780,8 @@ void inet6_proto_init(struct net_proto *pro)
 
        if (sizeof(struct ipv6_options) > sizeof(dummy_skb->cb))
        {
-               printk(KERN_CRIT "inet6_proto_init: panic\n");
-               return;
+               printk(KERN_CRIT "inet6_proto_init: size fault\n");
+               return -EINVAL;
        }
 
        (void) sock_register(&inet6_family_ops);
index efc41e7941f0bf4cfa387f51f36717ade411c4ab..9e4eeae531b7a34ee365b610e440eef3cc188240 100644 (file)
@@ -905,6 +905,8 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
                                /* CHECKSUM_UNNECESSARY */
                }
 
+               tcp_statistics.TcpInSegs++;
+               
                sk = inet6_get_sock(&tcpv6_prot, daddr, saddr, 
                                    th->dest, th->source);
 
index 1f0e69942d04f5cf846699ceaf5a36d1154765bd..85cb067381373735b5de75c644f20523cf9c4c2a 100644 (file)
@@ -49,8 +49,6 @@ static lapb_cb *volatile lapb_list = NULL;
  */
 static void lapb_free_cb(lapb_cb *lapb)
 {
-       del_timer(&lapb->timer);
-
        kfree_s(lapb, sizeof(lapb_cb));
 
        MOD_DEC_USE_COUNT;
@@ -161,6 +159,10 @@ int lapb_register(void *token, struct lapb_register_struct *callbacks)
 
        lapb_insert_cb(lapb);
 
+       lapb->t1timer = lapb->t1;
+
+       lapb_set_timer(lapb);
+
        return LAPB_OK;
 }
 
@@ -171,6 +173,8 @@ int lapb_unregister(void *token)
        if ((lapb = lapb_tokentostruct(token)) == NULL)
                return LAPB_BADTOKEN;
 
+       del_timer(&lapb->timer);
+
        lapb_clear_queues(lapb);
 
        lapb_remove_cb(lapb);
@@ -225,14 +229,8 @@ int lapb_setparms(void *token, struct lapb_parms_struct *parms)
                                return LAPB_INVALUE;
                }
 
-               lapb->mode   = parms->mode;
-               lapb->window = parms->window;
-
-               if (lapb->mode & LAPB_DCE) {
-                       lapb_set_timer(lapb);
-               } else {
-                       lapb->t1timer = 0;
-               }
+               lapb->mode    = parms->mode;
+               lapb->window  = parms->window;
        }
 
        lapb->t1    = parms->t1;
@@ -265,8 +263,6 @@ int lapb_connect_request(void *token)
 
        lapb->state = LAPB_STATE_1;
 
-       lapb_set_timer(lapb);
-
        return LAPB_OK;
 }
        
@@ -290,7 +286,7 @@ int lapb_disconnect_request(void *token)
 #endif
                        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
                        lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                       lapb->t1timer = lapb->t1;
                        return LAPB_NOTCONNECTED;
 
                case LAPB_STATE_2:
index 2671a26eaa5b0193768dec6210304ccc57570659..cbe51bbf3c936a114c38864a1fc67887c6d9a821 100644 (file)
@@ -198,7 +198,7 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
 #endif
                                lapb_clear_queues(lapb);
                                lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                               lapb->t1timer = lapb->t1;
                                lapb->t2timer = 0;
                                lapb_disconnect_indication(lapb, LAPB_REFUSED);
                        }
@@ -244,7 +244,7 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                                printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
                                lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                               lapb->t1timer = lapb->t1;
                                lapb->t2timer = 0;
                                lapb_disconnect_confirmation(lapb, LAPB_OK);
                        }
@@ -259,7 +259,7 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                                printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
                                lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                               lapb->t1timer = lapb->t1;
                                lapb->t2timer = 0;
                                lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
                        }
@@ -315,6 +315,7 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                                lapb->vs        = 0;
                                lapb->vr        = 0;
                                lapb->va        = 0;
+                               lapb_requeue_frames(lapb);
                        }
                        break;
 
@@ -333,6 +334,7 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                                lapb->vs        = 0;
                                lapb->vr        = 0;
                                lapb->va        = 0;
+                               lapb_requeue_frames(lapb);
                        } else {
 #if LAPB_DEBUG > 1
                                printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, pf);
@@ -351,7 +353,7 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                        lapb_clear_queues(lapb);
                        lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
                        lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                       lapb->t1timer = lapb->t1;
                        lapb->t2timer = 0;
                        lapb_disconnect_indication(lapb, LAPB_OK);
                        break;
@@ -365,7 +367,7 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
 #endif
                        lapb_clear_queues(lapb);
                        lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                       lapb->t1timer = lapb->t1;
                        lapb->t2timer = 0;
                        lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
                        break;
@@ -519,6 +521,7 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                                lapb->vs        = 0;
                                lapb->vr        = 0;
                                lapb->va        = 0;
+                               lapb_requeue_frames(lapb);
                        }
                        break;
 
@@ -537,6 +540,7 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                                lapb->vs        = 0;
                                lapb->vr        = 0;
                                lapb->va        = 0;
+                               lapb_requeue_frames(lapb);
                        } else {
 #if LAPB_DEBUG > 1
                                printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, pf);
@@ -555,7 +559,7 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
                        lapb_clear_queues(lapb);
                        lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
                        lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                       lapb->t1timer = lapb->t1;
                        lapb->t2timer = 0;
                        lapb_disconnect_indication(lapb, LAPB_OK);
                        break;
@@ -569,7 +573,7 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, int frametyp
 #endif
                        lapb_clear_queues(lapb);
                        lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+                       lapb->t1timer = lapb->t1;
                        lapb->t2timer = 0;
                        lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
                        break;
index cf59172e51b7f7adffce965846a5885d9427c475..d006b0f17b004345a2ba1f11b4366c2a8cb81b4c 100644 (file)
 static void lapb_timer(unsigned long);
 
 /*
- *     Linux set/reset timer routines
+ *     Linux set timer
  */
 void lapb_set_timer(lapb_cb *lapb)
 {
        unsigned long flags;    
 
-       save_flags(flags);
-       cli();
-       del_timer(&lapb->timer);
-       restore_flags(flags);
-
-       lapb->timer.next     = lapb->timer.prev = NULL; 
-       lapb->timer.data     = (unsigned long)lapb;
-       lapb->timer.function = &lapb_timer;
-
-       lapb->timer.expires = jiffies + 10;
-       add_timer(&lapb->timer);
-}
-
-static void lapb_reset_timer(lapb_cb *lapb)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        del_timer(&lapb->timer);
        restore_flags(flags);
 
        lapb->timer.data     = (unsigned long)lapb;
        lapb->timer.function = &lapb_timer;
        lapb->timer.expires  = jiffies + 10;
+
        add_timer(&lapb->timer);
 }
 
@@ -98,7 +81,7 @@ static void lapb_timer(unsigned long param)
        }
 
        if (lapb->t1timer == 0 || --lapb->t1timer > 0) {
-               lapb_reset_timer(lapb);
+               lapb_set_timer(lapb);
                return;
        }
 
@@ -111,7 +94,6 @@ static void lapb_timer(unsigned long param)
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
                                lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
                                lapb->t2timer = 0;
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
@@ -137,7 +119,6 @@ static void lapb_timer(unsigned long param)
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
                                lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
                                lapb->t2timer = 0;
                                lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
@@ -156,13 +137,15 @@ static void lapb_timer(unsigned long param)
                        lapb->n2count = 1;
                        lapb_transmit_enquiry(lapb);
                        lapb->state   = LAPB_STATE_4;
+#if LAPB_DEBUG > 0
+                       printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+#endif
                        break;
 
                case LAPB_STATE_4:
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
                                lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
                                lapb->t2timer = 0;
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
index b4b15007fdb9b4dd2db04686d0e1a7c4a411a155..3915f8e110a75811b57b87dedc7831957d0c5afd 100644 (file)
@@ -74,7 +74,6 @@ int sysctl_netrom_transport_acknowledge_delay     = NR_DEFAULT_T2;
 int sysctl_netrom_transport_busy_delay            = NR_DEFAULT_T4;
 int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
 int sysctl_netrom_transport_no_activity_timeout   = NR_DEFAULT_IDLE;
-int sysctl_netrom_transport_packet_length         = NR_DEFAULT_PACLEN;
 int sysctl_netrom_routing_control                 = NR_DEFAULT_ROUTING;
 int sysctl_netrom_link_fails_count                = NR_DEFAULT_FAILS;
 
@@ -119,7 +118,6 @@ static struct sock *nr_alloc_sock(void)
 /*
  *     Socket removal during an interrupt is now safe.
  */
-
 static void nr_remove_socket(struct sock *sk)
 {
        struct sock *s;
@@ -310,7 +308,7 @@ void nr_destroy_socket(struct sock *sk)     /* Not static as it's used by the timer
                kfree_skb(skb, FREE_READ);
        }
 
-       if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+       if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) { /* Defer: outstanding buffers */
                init_timer(&sk->timer);
                sk->timer.expires  = jiffies + 10 * HZ;
                sk->timer.function = nr_destroy_timer;
@@ -365,7 +363,6 @@ static int nr_ctl_ioctl(const unsigned int cmd, void *arg)
                case NETROM_T1:
                        if (nr_ctl.arg < 1) 
                                return -EINVAL;
-                       sk->protinfo.nr->rtt = (nr_ctl.arg * NR_SLOWHZ) / 2;
                        sk->protinfo.nr->t1  = nr_ctl.arg * NR_SLOWHZ;
                        save_flags(flags); cli();
                        if (sk->protinfo.nr->t1timer > sk->protinfo.nr->t1)
@@ -410,14 +407,6 @@ static int nr_ctl_ioctl(const unsigned int cmd, void *arg)
                        restore_flags(flags);
                        break;
 
-               case NETROM_PACLEN:
-                       if (nr_ctl.arg < 16 || nr_ctl.arg > 65535) 
-                               return -EINVAL;
-                       if (nr_ctl.arg > 236) /* we probably want this */
-                               printk(KERN_WARNING "nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
-                       sk->protinfo.nr->paclen = nr_ctl.arg;
-                       break;
-
                default:
                        return -EINVAL;
          }
@@ -446,7 +435,7 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
                case NETROM_T1:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.nr->rtt = (opt * NR_SLOWHZ) / 2;
+                       sk->protinfo.nr->t1 = opt * NR_SLOWHZ;
                        return 0;
 
                case NETROM_T2:
@@ -477,12 +466,6 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
                        sk->protinfo.nr->hdrincl = opt ? 1 : 0;
                        return 0;
 
-               case NETROM_PACLEN:
-                       if (opt < 1 || opt > 65536)
-                               return -EINVAL;
-                       sk->protinfo.nr->paclen = opt;
-                       return 0;
-
                default:
                        return -ENOPROTOOPT;
        }
@@ -523,10 +506,6 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
                        val = sk->protinfo.nr->hdrincl;
                        break;
 
-               case NETROM_PACLEN:
-                       val = sk->protinfo.nr->paclen;
-                       break;
-
                default:
                        return -ENOPROTOOPT;
        }
@@ -571,30 +550,25 @@ static int nr_create(struct socket *sock, int protocol)
 
        nr = sk->protinfo.nr;
 
-       sock_init_data(sock,sk);
-
-       init_timer(&sk->timer);
-
-       sock->ops         = &nr_proto_ops;
+       sock_init_data(sock, sk);
 
-       sk->protocol      = protocol;
-       sk->mtu           = NETROM_MTU; /* 236 */
+       sock->ops    = &nr_proto_ops;
+       sk->protocol = protocol;
+       sk->mtu      = NETROM_MTU;      /* 236 */
 
        skb_queue_head_init(&nr->ack_queue);
        skb_queue_head_init(&nr->reseq_queue);
        skb_queue_head_init(&nr->frag_queue);
 
-       nr->rtt      = sysctl_netrom_transport_timeout / 2;
-       nr->t1       = sysctl_netrom_transport_timeout;
-       nr->t2       = sysctl_netrom_transport_acknowledge_delay;
-       nr->n2       = sysctl_netrom_transport_maximum_tries;
-       nr->t4       = sysctl_netrom_transport_busy_delay;
-       nr->idle     = sysctl_netrom_transport_no_activity_timeout;
-       nr->paclen   = sysctl_netrom_transport_packet_length;
-       nr->window   = sysctl_netrom_transport_requested_window_size;
+       nr->t1     = sysctl_netrom_transport_timeout;
+       nr->t2     = sysctl_netrom_transport_acknowledge_delay;
+       nr->n2     = sysctl_netrom_transport_maximum_tries;
+       nr->t4     = sysctl_netrom_transport_busy_delay;
+       nr->idle   = sysctl_netrom_transport_no_activity_timeout;
+       nr->window = sysctl_netrom_transport_requested_window_size;
 
-       nr->bpqext     = 1;
-       nr->state      = NR_STATE_0;
+       nr->bpqext = 1;
+       nr->state  = NR_STATE_0;
 
        return 0;
 }
@@ -612,38 +586,34 @@ static struct sock *nr_make_new(struct sock *osk)
 
        nr = sk->protinfo.nr;
 
-       sock_init_data(NULL,sk);
+       sock_init_data(NULL, sk);
 
-       init_timer(&sk->timer);
-
-       sk->type        = osk->type;
-       sk->socket      = osk->socket;
-       sk->priority    = osk->priority;
-       sk->protocol    = osk->protocol;
-       sk->rcvbuf      = osk->rcvbuf;
-       sk->sndbuf      = osk->sndbuf;
-       sk->debug       = osk->debug;
-       sk->state       = TCP_ESTABLISHED;
-       sk->mtu         = osk->mtu;
-       sk->sleep       = osk->sleep;
-       sk->zapped      = osk->zapped;
+       sk->type     = osk->type;
+       sk->socket   = osk->socket;
+       sk->priority = osk->priority;
+       sk->protocol = osk->protocol;
+       sk->rcvbuf   = osk->rcvbuf;
+       sk->sndbuf   = osk->sndbuf;
+       sk->debug    = osk->debug;
+       sk->state    = TCP_ESTABLISHED;
+       sk->mtu      = osk->mtu;
+       sk->sleep    = osk->sleep;
+       sk->zapped   = osk->zapped;
 
        skb_queue_head_init(&nr->ack_queue);
        skb_queue_head_init(&nr->reseq_queue);
        skb_queue_head_init(&nr->frag_queue);
 
-       nr->rtt      = osk->protinfo.nr->rtt;
-       nr->t1       = osk->protinfo.nr->t1;
-       nr->t2       = osk->protinfo.nr->t2;
-       nr->n2       = osk->protinfo.nr->n2;
-       nr->t4       = osk->protinfo.nr->t4;
-       nr->idle     = osk->protinfo.nr->idle;
-       nr->paclen   = osk->protinfo.nr->paclen;
-       nr->window   = osk->protinfo.nr->window;
+       nr->t1      = osk->protinfo.nr->t1;
+       nr->t2      = osk->protinfo.nr->t2;
+       nr->n2      = osk->protinfo.nr->n2;
+       nr->t4      = osk->protinfo.nr->t4;
+       nr->idle    = osk->protinfo.nr->idle;
+       nr->window  = osk->protinfo.nr->window;
 
-       nr->device   = osk->protinfo.nr->device;
-       nr->bpqext   = osk->protinfo.nr->bpqext;
-       nr->hdrincl  = osk->protinfo.nr->hdrincl;
+       nr->device  = osk->protinfo.nr->device;
+       nr->bpqext  = osk->protinfo.nr->bpqext;
+       nr->hdrincl = osk->protinfo.nr->hdrincl;
 
        return sk;
 }
@@ -687,7 +657,7 @@ static int nr_release(struct socket *sock, struct socket *peer)
                        nr_write_internal(sk, NR_DISCACK);
                        sk->protinfo.nr->state = NR_STATE_0;
                        sk->state              = TCP_CLOSE;
-                       sk->shutdown           = SEND_SHUTDOWN;
+                       sk->shutdown          |= SEND_SHUTDOWN;
                        sk->state_change(sk);
                        sk->dead               = 1;
                        nr_destroy_socket(sk);
@@ -697,7 +667,7 @@ static int nr_release(struct socket *sock, struct socket *peer)
                        nr_clear_queues(sk);
                        sk->protinfo.nr->n2count = 0;
                        nr_write_internal(sk, NR_DISCREQ);
-                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
                        sk->protinfo.nr->t2timer = 0;
                        sk->protinfo.nr->t4timer = 0;
                        sk->protinfo.nr->state   = NR_STATE_2;
@@ -1033,8 +1003,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        /* L4 timeout negotiation */
        if (skb->len == 37) {
                timeout = skb->data[36] * 256 + skb->data[35];
-               if (timeout * NR_SLOWHZ < make->protinfo.nr->rtt * 2)
-                       make->protinfo.nr->rtt = (timeout * NR_SLOWHZ) / 2;
+               if (timeout * NR_SLOWHZ < make->protinfo.nr->t1)
+                       make->protinfo.nr->t1 = timeout * NR_SLOWHZ;
                make->protinfo.nr->bpqext = 1;
        } else {
                make->protinfo.nr->bpqext = 0;
@@ -1110,8 +1080,6 @@ static int nr_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct s
        if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
                return err;
 
-       skb->arp = 1;
-
        skb_reserve(skb, size - len);
 
        /*
@@ -1285,7 +1253,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
 
        cli();
 
-       len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2    n2  rtt wnd paclen Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2    n2  wnd Snd-Q Rcv-Q\n");
 
        for (s = nr_list; s != NULL; s = s->next) {
                if ((dev = s->protinfo.nr->device) == NULL)
@@ -1297,7 +1265,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
                        ax2asc(&s->protinfo.nr->user_addr));
                len += sprintf(buffer + len, "%-9s ",
                        ax2asc(&s->protinfo.nr->dest_addr));
-               len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %3d %6d %5d %5d\n",
+               len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %5d %5d\n",
                        ax2asc(&s->protinfo.nr->source_addr),
                        devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id,
                        s->protinfo.nr->your_index, s->protinfo.nr->your_id,
@@ -1307,9 +1275,9 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
                        s->protinfo.nr->t1      / NR_SLOWHZ,
                        s->protinfo.nr->t2timer / NR_SLOWHZ,
                        s->protinfo.nr->t2      / NR_SLOWHZ,
-                       s->protinfo.nr->n2count, s->protinfo.nr->n2,
-                       s->protinfo.nr->rtt     / NR_SLOWHZ,
-                       s->protinfo.nr->window, s->protinfo.nr->paclen,
+                       s->protinfo.nr->n2count,
+                       s->protinfo.nr->n2,
+                       s->protinfo.nr->window,
                        s->wmem_alloc, s->rmem_alloc);
 
                pos = begin + len;
@@ -1399,7 +1367,7 @@ void nr_proto_init(struct net_proto *pro)
 
        sock_register(&nr_family_ops);
        register_netdevice_notifier(&nr_dev_notifier);
-       printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.034 Linux 2.1\n");
+       printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.1\n");
 
        if (!ax25_protocol_register(AX25_P_NETROM, nr_route_frame))
                printk(KERN_ERR "NET/ROM unable to register protocol with AX.25\n");
index 4982ccb340c353f86f09a91fe129c00b9637c7af..af2dbbb679d6a96fee820d3ebf0859e1d511ff6d 100644 (file)
@@ -228,9 +228,7 @@ static struct enet_statistics *nr_get_stats(struct device *dev)
 
 int nr_init(struct device *dev)
 {
-       int i;
-
-       dev->mtu                = 236;          /* MTU                  */
+       dev->mtu                = NR_MAX_PACKET_SIZE;
        dev->tbusy              = 0;
        dev->hard_start_xmit    = nr_xmit;
        dev->open               = nr_open;
@@ -259,9 +257,7 @@ int nr_init(struct device *dev)
 
        dev->get_stats = nr_get_stats;
 
-       /* Fill in the generic fields of the device structure. */
-       for (i = 0; i < DEV_NUMBUFFS; i++)
-               skb_queue_head_init(&dev->buffs[i]);
+       dev_init_buffers(dev);
 
        return 0;
 };
index 7e4d3ac81519f1e8f2a4a4c0855af7e4fe7a5ac7..cbddc677a7ead6989c1e6a40860d9c3bd60599cb 100644 (file)
@@ -67,8 +67,6 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
                if ((skbn = alloc_skb(sk->protinfo.nr->fraglen, GFP_ATOMIC)) == NULL)
                        return 1;
 
-               skbn->arp  = 1;
-               skb_set_owner_r(skbn, sk);
                skbn->h.raw = skbn->data;
 
                skbo = skb_dequeue(&sk->protinfo.nr->frag_queue);
@@ -97,7 +95,6 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
        switch (frametype) {
 
                case NR_CONNACK:
-                       nr_calculate_rtt(sk);
                        sk->protinfo.nr->your_index = skb->data[17];
                        sk->protinfo.nr->your_id    = skb->data[18];
                        sk->protinfo.nr->t1timer    = 0;
@@ -311,7 +308,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
 int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
        int queued = 0, frametype;
-       
+
        if (sk->protinfo.nr->state == NR_STATE_0)
                return 0;
 
@@ -319,8 +316,7 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 
        frametype = skb->data[19];
 
-       switch (sk->protinfo.nr->state)
-       {
+       switch (sk->protinfo.nr->state) {
                case NR_STATE_1:
                        queued = nr_state1_machine(sk, skb, frametype);
                        break;
index af3e0e5c20131571e1d670137dbbf463db89ceca..7ee32c736b0a017a01fef4ab5f1350e1ec50f442 100644 (file)
@@ -50,11 +50,9 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
 {
        struct sk_buff *skbn;
        unsigned char transport[NR_TRANSPORT_LEN];
-       int err, frontlen, len, mtu;
+       int err, frontlen, len;
 
-       mtu = sk->protinfo.nr->paclen;
-
-       if (skb->len - NR_TRANSPORT_LEN > mtu) {
+       if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) {
                /* Save a copy of the Transport Header */
                memcpy(transport, skb->data, NR_TRANSPORT_LEN);
                skb_pull(skb, NR_TRANSPORT_LEN);
@@ -62,15 +60,12 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
                frontlen = skb_headroom(skb);
 
                while (skb->len > 0) {
-                       if ((skbn = sock_alloc_send_skb(sk, frontlen + mtu, 0, 0, &err)) == NULL)
+                       if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, 0, &err)) == NULL)
                                return;
 
-                       skbn->sk   = sk;
-                       skbn->arp  = 1;
-
                        skb_reserve(skbn, frontlen);
 
-                       len = (mtu > skb->len) ? skb->len : mtu;
+                       len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE;
 
                        /* Copy the user data */
                        memcpy(skb_put(skbn, len), skb->data, len);
@@ -187,9 +182,8 @@ void nr_kick(struct sock *sk)
                sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
                sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 
-               if (sk->protinfo.nr->t1timer == 0) {
-                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
-               }
+               if (sk->protinfo.nr->t1timer == 0)
+                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
        }
 
        nr_set_timer(sk);
@@ -218,8 +212,6 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
 
        *dptr++ = sysctl_netrom_network_ttl_initialiser;
 
-       skb->arp = 1;
-
        if (!nr_route_frame(skb, NULL)) {
                kfree_skb(skb, FREE_WRITE);
 
@@ -245,7 +237,7 @@ void nr_establish_data_link(struct sock *sk)
        nr_write_internal(sk, NR_CONNREQ);
 
        sk->protinfo.nr->t2timer = 0;
-       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 }
 
 /*
@@ -258,9 +250,8 @@ void nr_enquiry_response(struct sock *sk)
        if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY) {
                frametype |= NR_CHOKE_FLAG;
        } else {
-               if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL) {
+               if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL)
                        frametype |= NR_NAK_FLAG;
-               }
        }
 
        nr_write_internal(sk, frametype);
@@ -273,13 +264,12 @@ void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
 {
        if (sk->protinfo.nr->vs == nr) {
                nr_frames_acked(sk, nr);
-               nr_calculate_rtt(sk);
                sk->protinfo.nr->t1timer = 0;
                sk->protinfo.nr->n2count = 0;
        } else {
                if (sk->protinfo.nr->va != nr) {
                        nr_frames_acked(sk, nr);
-                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
                }
        }
 }
index 70395ed40fc106945592cef7669f35c5a130ffdd..9ff8df41bdb7860db50afc1fe2e911f335c7c838 100644 (file)
@@ -101,6 +101,7 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
                nr_neigh->locked   = 0;
                nr_neigh->count    = 0;
                nr_neigh->number   = nr_neigh_no++;
+               nr_neigh->failed   = 0;
 
                if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
                        if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
@@ -330,7 +331,7 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct d
 
                        if (nr_neigh->count == 0 && !nr_neigh->locked)
                                nr_remove_neigh(nr_neigh);
-                               
+
                        nr_node->count--;
 
                        if (nr_node->count == 0) {
@@ -697,7 +698,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 
        if (ax25 != NULL)
                nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
-                           ax25->device, 0, sysctl_netrom_network_ttl_initialiser);
+                           ax25->device, 0, sysctl_netrom_obsolescence_count_initialiser);
 
        if ((dev = nr_dev_get(nr_dest)) != NULL)        /* Its for me */
                return nr_rx_frame(skb, dev);
@@ -729,7 +730,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        dptr  = skb_push(skb, 1);
        *dptr = AX25_P_NETROM;
 
-       return ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+       return ax25_send_frame(skb, 0, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
 }
 
 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
index 3f7928e10c1201454cc8a5cdef192f9113545fbf..eb1b225f82b5c6ad01e2622d04b9009a08dae6e1 100644 (file)
@@ -175,7 +175,7 @@ void nr_write_internal(struct sock *sk, int frametype)
        switch (frametype & 0x0F) {
 
                case NR_CONNREQ:
-                       timeout  = (sk->protinfo.nr->rtt / NR_SLOWHZ) * 2;
+                       timeout  = sk->protinfo.nr->t1 / NR_SLOWHZ;
                        *dptr++  = sk->protinfo.nr->my_index;
                        *dptr++  = sk->protinfo.nr->my_id;
                        *dptr++  = 0;
@@ -267,40 +267,8 @@ void nr_transmit_dm(struct sk_buff *skb)
        *dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
        *dptr++ = 0;
 
-       skbn->sk   = NULL;
-
        if (!nr_route_frame(skbn, NULL))
                kfree_skb(skbn, FREE_WRITE);
 }
 
-/*
- *     Exponential backoff for NET/ROM
- */
-unsigned short nr_calculate_t1(struct sock *sk)
-{
-       int n, t;
-       
-       for (t = 2, n = 0; n < sk->protinfo.nr->n2count; n++)
-               t *= 2;
-
-       if (t > 8) t = 8;
-
-       return t * sk->protinfo.nr->rtt;
-}
-
-/*
- *     Calculate the Round Trip Time
- */
-void nr_calculate_rtt(struct sock *sk)
-{
-       if (sk->protinfo.nr->t1timer > 0 && sk->protinfo.nr->n2count == 0)
-               sk->protinfo.nr->rtt = (9 * sk->protinfo.nr->rtt + sk->protinfo.nr->t1 - sk->protinfo.nr->t1timer) / 10;
-
-       if (sk->protinfo.nr->rtt < NR_T1CLAMPLO)
-               sk->protinfo.nr->rtt = NR_T1CLAMPLO;
-
-        if (sk->protinfo.nr->rtt > NR_T1CLAMPHI)
-                sk->protinfo.nr->rtt = NR_T1CLAMPHI;
-}
-
 #endif
index 566f2a6f72669a780122167fe8832fe92a1f2263..930faa2bfc81ff4e9bf8c7deefdebedb9b4ade57 100644 (file)
 static void nr_timer(unsigned long);
 
 /*
- *     Linux set/reset timer routines
+ *     Linux set timer
  */
 void nr_set_timer(struct sock *sk)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
-       del_timer(&sk->timer);
-       restore_flags(flags);
-
-       sk->timer.next     = sk->timer.prev = NULL;     
-       sk->timer.data     = (unsigned long)sk;
-       sk->timer.function = &nr_timer;
-
-       sk->timer.expires = jiffies+10;
-       add_timer(&sk->timer);
-}
-
-static void nr_reset_timer(struct sock *sk)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        del_timer(&sk->timer);
        restore_flags(flags);
 
        sk->timer.data     = (unsigned long)sk;
        sk->timer.function = &nr_timer;
        sk->timer.expires  = jiffies+10;
+
        add_timer(&sk->timer);
 }
 
@@ -133,7 +116,7 @@ static void nr_timer(unsigned long param)
        }
 
        if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
-               nr_reset_timer(sk);
+               nr_set_timer(sk);
                return;
        }
 
@@ -187,7 +170,7 @@ static void nr_timer(unsigned long param)
                        break;
        }
 
-       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 
        nr_set_timer(sk);
 }
index f6eac6179d1e98b441ab2a60a5e5e53588e4bb94..2502885a3a2dad7fda3b0ac5ea024739943be45c 100644 (file)
@@ -26,7 +26,6 @@ static int max_t4[]      = {1000 * NR_SLOWHZ};
 static int min_window[]  = {1}, max_window[]  = {127};
 static int min_idle[]    = {0 * NR_SLOWHZ};
 static int max_idle[]    = {65535 * NR_SLOWHZ};
-static int min_n1[]      = {1}, max_n1[]      = {236};
 static int min_route[]   = {0}, max_route[]   = {1};
 static int min_fails[]   = {1}, max_fails[]   = {10};
 
@@ -60,9 +59,6 @@ static ctl_table nr_table[] = {
         {NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT, "transport_no_activity_timeout",
          &sysctl_netrom_transport_no_activity_timeout, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_idle, &max_idle},
-        {NET_NETROM_TRANSPORT_PACKET_LENGTH, "transport_packet_length",
-         &sysctl_netrom_transport_packet_length, sizeof(int), 0644, NULL,
-         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_n1, &max_n1},
         {NET_NETROM_ROUTING_CONTROL, "routing_control",
          &sysctl_netrom_routing_control, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_route, &max_route},
index 9c897df78bb9e9cefbf3c03bc77050a2bcc3fe95..f71ee0e56f4f1deda7d17099376d22a509d20b36 100644 (file)
@@ -93,6 +93,7 @@ EXPORT_SYMBOL(sk_alloc);
 EXPORT_SYMBOL(sk_free);
 EXPORT_SYMBOL(sock_wake_async);
 EXPORT_SYMBOL(sock_alloc_send_skb);
+EXPORT_SYMBOL(sock_init_data);
 EXPORT_SYMBOL(sock_no_fcntl);
 EXPORT_SYMBOL(sock_rfree);
 EXPORT_SYMBOL(sock_wfree);
@@ -102,7 +103,6 @@ EXPORT_SYMBOL(skb_copy_datagram);
 EXPORT_SYMBOL(skb_copy_datagram_iovec);
 EXPORT_SYMBOL(skb_realloc_headroom);
 EXPORT_SYMBOL(datagram_poll);
-EXPORT_SYMBOL(sock_init_data);
 EXPORT_SYMBOL(put_cmsg);
 
 EXPORT_SYMBOL(neigh_table_init);
index e094cdf06abc2efd96db96358d824cace2549049..e4a7a1bdc0da48a3410196c58e0ff82cfdcb69ba 100644 (file)
@@ -59,7 +59,8 @@ int sysctl_rose_reset_request_timeout   = ROSE_DEFAULT_T2;
 int sysctl_rose_clear_request_timeout   = ROSE_DEFAULT_T3;
 int sysctl_rose_no_activity_timeout     = ROSE_DEFAULT_IDLE;
 int sysctl_rose_ack_hold_back_timeout   = ROSE_DEFAULT_HB;
-int sysctl_rose_routing_control         = 1;
+int sysctl_rose_routing_control         = ROSE_DEFAULT_ROUTING;
+int sysctl_rose_link_fail_timeout       = ROSE_DEFAULT_FAIL_TIMEOUT;
 
 static unsigned int lci = 1;
 
@@ -157,7 +158,7 @@ static struct sock *rose_alloc_sock(void)
        memset(rose, 0x00, sizeof(*rose));
 
        sk->protinfo.rose = rose;
-       rose->sk = sk;
+       rose->sk          = sk;
 
        return sk;
 }
@@ -221,7 +222,7 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
 
        if (event != NETDEV_DOWN)
                return NOTIFY_DONE;
-               
+
        rose_kill_by_device(dev);
        rose_rt_device_down(dev);
        rose_link_device_down(dev);
@@ -356,7 +357,7 @@ void rose_destroy_socket(struct sock *sk)   /* Not static as it's used by the time
                kfree_skb(skb, FREE_READ);
        }
 
-       if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+       if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) { /* Defer: outstanding buffers */
                init_timer(&sk->timer);
                sk->timer.expires  = jiffies + 10 * HZ;
                sk->timer.function = rose_destroy_timer;
@@ -412,16 +413,6 @@ static int rose_ctl_ioctl(const unsigned int cmd, void *arg)
                        rose_set_timer(sk);
                        break;
 
-               case ROSE_T0:
-                       if (rose_ctl.arg < 1) 
-                               return -EINVAL;
-                       if (sk->protinfo.rose->neighbour != NULL) {
-                               save_flags(flags); cli();
-                               sk->protinfo.rose->neighbour->t0 = rose_ctl.arg * ROSE_SLOWHZ;
-                               restore_flags(flags);
-                       }
-                       break;
-
                case ROSE_T1:
                        if (rose_ctl.arg < 1) 
                                return -EINVAL;
@@ -487,13 +478,6 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
        get_user(opt, (int *)optval);
 
        switch (optname) {
-               case ROSE_T0:
-                       if (opt < 1)
-                               return -EINVAL;
-                       if (sk->protinfo.rose->neighbour != NULL)
-                               sk->protinfo.rose->neighbour->t0 = opt * ROSE_SLOWHZ;
-                       return 0;
-
                case ROSE_T1:
                        if (opt < 1)
                                return -EINVAL;
@@ -544,13 +528,6 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
                return -EOPNOTSUPP;
        
        switch (optname) {
-               case ROSE_T0:
-                       if (sk->protinfo.rose->neighbour != NULL)
-                               val = sk->protinfo.rose->neighbour->t0 / ROSE_SLOWHZ;
-                       else
-                               val = sysctl_rose_restart_request_timeout / ROSE_SLOWHZ;
-                       break;
-
                case ROSE_T1:
                        val = sk->protinfo.rose->t1 / ROSE_SLOWHZ;
                        break;
@@ -609,28 +586,6 @@ static int rose_listen(struct socket *sock, int backlog)
        return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-       if (!sk->dead)
-               wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-       if (!sk->dead) {
-               wake_up_interruptible(sk->sleep);
-               sock_wake_async(sk->socket, 1);
-       }
-}
-
-static void def_callback3(struct sock *sk)
-{
-       if (!sk->dead) {
-               wake_up_interruptible(sk->sleep);
-               sock_wake_async(sk->socket, 2); 
-       }               
-}
-
 static int rose_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
@@ -644,19 +599,19 @@ static int rose_create(struct socket *sock, int protocol)
 
        rose = sk->protinfo.rose;
 
-       sock_init_data(sock,sk);
+       sock_init_data(sock, sk);
        
-       sock->ops         = &rose_proto_ops;
-       sk->protocol      = protocol;
-       sk->mtu           = ROSE_MTU;   /* 128 */
+       sock->ops    = &rose_proto_ops;
+       sk->protocol = protocol;
+       sk->mtu      = ROSE_MTU;        /* 128 */
 
        skb_queue_head_init(&rose->frag_queue);
 
-       rose->t1    = sysctl_rose_call_request_timeout;
-       rose->t2    = sysctl_rose_reset_request_timeout;
-       rose->t3    = sysctl_rose_clear_request_timeout;
-       rose->hb    = sysctl_rose_ack_hold_back_timeout;
-       rose->idle  = sysctl_rose_no_activity_timeout;
+       rose->t1   = sysctl_rose_call_request_timeout;
+       rose->t2   = sysctl_rose_reset_request_timeout;
+       rose->t3   = sysctl_rose_clear_request_timeout;
+       rose->hb   = sysctl_rose_ack_hold_back_timeout;
+       rose->idle = sysctl_rose_no_activity_timeout;
 
        rose->state = ROSE_STATE_0;
 
@@ -676,28 +631,19 @@ static struct sock *rose_make_new(struct sock *osk)
 
        rose = sk->protinfo.rose;
 
-       skb_queue_head_init(&sk->receive_queue);
-       skb_queue_head_init(&sk->write_queue);
-       skb_queue_head_init(&sk->back_log);
-
-       init_timer(&sk->timer);
-
-       sk->type        = osk->type;
-       sk->socket      = osk->socket;
-       sk->priority    = osk->priority;
-       sk->protocol    = osk->protocol;
-       sk->rcvbuf      = osk->rcvbuf;
-       sk->sndbuf      = osk->sndbuf;
-       sk->debug       = osk->debug;
-       sk->state       = TCP_ESTABLISHED;
-       sk->mtu         = osk->mtu;
-       sk->sleep       = osk->sleep;
-       sk->zapped      = osk->zapped;
-
-       sk->state_change = def_callback1;
-       sk->data_ready   = def_callback2;
-       sk->write_space  = def_callback3;
-       sk->error_report = def_callback1;
+       sock_init_data(NULL, sk);
+
+       sk->type     = osk->type;
+       sk->socket   = osk->socket;
+       sk->priority = osk->priority;
+       sk->protocol = osk->protocol;
+       sk->rcvbuf   = osk->rcvbuf;
+       sk->sndbuf   = osk->sndbuf;
+       sk->debug    = osk->debug;
+       sk->state    = TCP_ESTABLISHED;
+       sk->mtu      = osk->mtu;
+       sk->sleep    = osk->sleep;
+       sk->zapped   = osk->zapped;
 
        skb_queue_head_init(&rose->frag_queue);
 
@@ -845,7 +791,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        if (sk->state == TCP_ESTABLISHED)
                return -EISCONN;        /* No reconnect on a seqpacket socket */
 
-       sk->state   = TCP_CLOSE;        
+       sk->state   = TCP_CLOSE;
        sock->state = SS_UNCONNECTED;
 
        if (addr_len != sizeof(struct sockaddr_rose))
@@ -894,7 +840,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        /* Now the loop */
        if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
                return -EINPROGRESS;
-               
+
        cli();  /* To avoid races on the sleep */
 
        /*
@@ -920,7 +866,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
 
        return 0;
 }
-       
+
 static int rose_socketpair(struct socket *sock1, struct socket *sock2)
 {
        return -EOPNOTSUPP;
@@ -1139,8 +1085,6 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
        if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
                return err;
 
-       skb->arp = 1;
-
        skb_reserve(skb, size - len);
 
        /*
@@ -1470,7 +1414,7 @@ void rose_proto_init(struct net_proto *pro)
        proc_net_register(&proc_net_rose_neigh);
        proc_net_register(&proc_net_rose_nodes);
        proc_net_register(&proc_net_rose_routes);
-#endif 
+#endif
 }
 
 #ifdef MODULE
index b13680e90585e2d0c7d65fff73a0ca98e8a50089..1ba762171dc20ead365f3cca7da2a750b802e685 100644 (file)
@@ -200,9 +200,7 @@ static struct enet_statistics *rose_get_stats(struct device *dev)
 
 int rose_init(struct device *dev)
 {
-       int i;
-
-       dev->mtu                = ROSE_PACLEN - 2;
+       dev->mtu                = ROSE_MAX_PACKET_SIZE - 2;
        dev->tbusy              = 0;
        dev->hard_start_xmit    = rose_xmit;
        dev->open               = rose_open;
@@ -231,9 +229,7 @@ int rose_init(struct device *dev)
 
        dev->get_stats = rose_get_stats;
 
-       /* Fill in the generic fields of the device structure. */
-       for (i = 0; i < DEV_NUMBUFFS; i++)
-               skb_queue_head_init(&dev->buffs[i]);
+       dev_init_buffers(dev);
 
        return 0;
 };
index e30d550b0a2a7641cf490faaedc98f80cb34fbca..5599bd82a4a38daa2d4ee92dd16abad6d62649d2 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *     Rose release 001
  *
- *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *     releases, misbehave and/or generally screw up. It might even work. 
+ *     This is ALPHA test software. This code may break your machine, randomly fail to work with new
+ *     releases, misbehave and/or generally screw up. It might even work.
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -64,8 +64,6 @@ static int rose_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
                if ((skbn = alloc_skb(sk->protinfo.rose->fraglen, GFP_ATOMIC)) == NULL)
                        return 1;
 
-               skbn->arp  = 1;
-               skb_set_owner_r(skbn, sk);
                skbn->h.raw = skbn->data;
 
                skbo = skb_dequeue(&sk->protinfo.rose->frag_queue);
@@ -189,11 +187,10 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
 
                case ROSE_RR:
                case ROSE_RNR:
-                       if (frametype == ROSE_RNR) {
+                       if (frametype == ROSE_RNR)
                                sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
-                       } else {
+                       else
                                sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
-                       }
                        if (!rose_validate_nr(sk, nr)) {
                                rose_clear_queues(sk);
                                rose_write_internal(sk, ROSE_RESET_REQUEST);
@@ -246,7 +243,7 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                         * If the window is full, ack the frame, else start the
                         * acknowledge hold back timer.
                         */
-                       if (((sk->protinfo.rose->vl + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
+                       if (((sk->protinfo.rose->vl + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
                                sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
                                sk->protinfo.rose->timer      = 0;
                                rose_enquiry_response(sk);
index bab651fc4f54565304e431db3d53e400599f263c..6f317a5d1eb7688b94a0559ee2f25984dd4ca116 100644 (file)
 static void rose_link_timer(unsigned long);
 
 /*
- *     Linux set/reset timer routines
+ *     Linux set timer
  */
-static void rose_link_set_timer(struct rose_neigh *neigh)
+void rose_link_set_timer(struct rose_neigh *neigh)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        del_timer(&neigh->timer);
        restore_flags(flags);
 
-       neigh->timer.next     = neigh->timer.prev = NULL;       
        neigh->timer.data     = (unsigned long)neigh;
        neigh->timer.function = &rose_link_timer;
-
        neigh->timer.expires  = jiffies + 10;
-       add_timer(&neigh->timer);
-}
-
-static void rose_link_reset_timer(struct rose_neigh *neigh)
-{
-       unsigned long flags;
 
-       save_flags(flags);
-       cli();
-       del_timer(&neigh->timer);
-       restore_flags(flags);
-
-       neigh->timer.data     = (unsigned long)neigh;
-       neigh->timer.function = &rose_link_timer;
-       neigh->timer.expires  = jiffies + 10;
        add_timer(&neigh->timer);
 }
 
@@ -88,19 +71,22 @@ static void rose_link_timer(unsigned long param)
 {
        struct rose_neigh *neigh = (struct rose_neigh *)param;
 
-       if (neigh->t0timer == 0 || --neigh->t0timer > 0) {
-               rose_link_reset_timer(neigh);
-               return;
-       }
+       if (neigh->ftimer > 0)
+               neigh->ftimer--;
 
-       /*
-        * T0 for a link has expired.
-        */
-       rose_transmit_restart_request(neigh);
+       if (neigh->t0timer > 0) {
+               neigh->t0timer--;
 
-       neigh->t0timer = neigh->t0;
+               if (neigh->t0timer == 0) {
+                       rose_transmit_restart_request(neigh);
+                       neigh->t0timer = sysctl_rose_restart_request_timeout;
+               }
+       }
 
-       rose_link_set_timer(neigh);
+       if (neigh->ftimer > 0 || neigh->t0timer > 0)
+               rose_link_set_timer(neigh);
+       else
+               del_timer(&neigh->timer);
 }
 
 /*
@@ -117,7 +103,7 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
        else
                rose_call = &rose_callsign;
 
-       return ax25_send_frame(skb, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+       return ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 }
 
 /*
@@ -199,8 +185,6 @@ void rose_transmit_restart_request(struct rose_neigh *neigh)
        *dptr++ = 0x00;
        *dptr++ = 0;
 
-       skb->sk = NULL;
-
        if (!rose_send_frame(skb, neigh))
                kfree_skb(skb, FREE_WRITE);
 }
@@ -228,8 +212,6 @@ void rose_transmit_restart_confirmation(struct rose_neigh *neigh)
        *dptr++ = 0x00;
        *dptr++ = ROSE_RESTART_CONFIRMATION;
 
-       skb->sk = NULL;
-
        if (!rose_send_frame(skb, neigh))
                kfree_skb(skb, FREE_WRITE);
 }
@@ -258,8 +240,6 @@ void rose_transmit_diagnostic(struct rose_neigh *neigh, unsigned char diag)
        *dptr++ = ROSE_DIAGNOSTIC;
        *dptr++ = diag;
 
-       skb->sk = NULL;
-
        if (!rose_send_frame(skb, neigh))
                kfree_skb(skb, FREE_WRITE);
 }
@@ -290,8 +270,6 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns
        *dptr++ = cause;
        *dptr++ = 0x00;
 
-       skb->sk = NULL;
-
        if (!rose_send_frame(skb, neigh))
                kfree_skb(skb, FREE_WRITE);
 }
@@ -311,8 +289,6 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
        dptr = skb_push(skb, 1);
        *dptr++ = AX25_P_ROSE;
 
-       skb->arp = 1;
-
        if (neigh->restarted) {
                if (!rose_send_frame(skb, neigh))
                        kfree_skb(skb, FREE_WRITE);
@@ -321,7 +297,7 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
 
                if (neigh->t0timer == 0) {
                        rose_transmit_restart_request(neigh);
-                       neigh->t0timer = neigh->t0;
+                       neigh->t0timer = sysctl_rose_restart_request_timeout;
                        rose_link_set_timer(neigh);
                }
        }
index 0ea18e522a1272b265854696d33767cb1c238cd3..8ab4d932504d7ff655496d959565a1b27b3a58bb 100644 (file)
@@ -49,7 +49,7 @@ void rose_output(struct sock *sk, struct sk_buff *skb)
        unsigned char header[ROSE_MIN_LEN];
        int err, frontlen, len;
 
-       if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) {
+       if (skb->len - ROSE_MIN_LEN > ROSE_MAX_PACKET_SIZE) {
                /* Save a copy of the Header */
                memcpy(header, skb->data, ROSE_MIN_LEN);
                skb_pull(skb, ROSE_MIN_LEN);
@@ -57,15 +57,12 @@ void rose_output(struct sock *sk, struct sk_buff *skb)
                frontlen = skb_headroom(skb);
 
                while (skb->len > 0) {
-                       if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL)
+                       if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_MAX_PACKET_SIZE, 0, 0, &err)) == NULL)
                                return;
 
-                       skbn->sk   = sk;
-                       skbn->arp  = 1;
-
                        skb_reserve(skbn, frontlen);
 
-                       len = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;
+                       len = (ROSE_MAX_PACKET_SIZE > skb->len) ? skb->len : ROSE_MAX_PACKET_SIZE;
 
                        /* Copy the user data */
                        memcpy(skb_put(skbn, len), skb->data, len);
@@ -112,7 +109,7 @@ void rose_kick(struct sock *sk)
 
        del_timer(&sk->timer);
 
-       end = (sk->protinfo.rose->va + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS;
+       end = (sk->protinfo.rose->va + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS;
 
        if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) &&
            sk->protinfo.rose->vs != end                             &&
@@ -149,11 +146,10 @@ void rose_kick(struct sock *sk)
 
 void rose_enquiry_response(struct sock *sk)
 {
-       if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY) {
+       if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
                rose_write_internal(sk, ROSE_RNR);
-       } else {
+       else
                rose_write_internal(sk, ROSE_RR);
-       }
 
        sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
        sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
index 6ac59bcd8f911be435314409ada8c679ab6c13c4..88935bd73e17e5c69c2a96973bca3b4b42e20067 100644 (file)
@@ -86,8 +86,8 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
                rose_neigh->number    = rose_neigh_no++;
                rose_neigh->restarted = 0;
                skb_queue_head_init(&rose_neigh->queue);
-               rose_neigh->t0        = sysctl_rose_restart_request_timeout;
                rose_neigh->t0timer   = 0;
+               rose_neigh->ftimer    = 0;
                init_timer(&rose_neigh->timer);
 
                if (rose_route->ndigis != 0) {
@@ -114,10 +114,10 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
         * best match.
         */
        if (rose_node == NULL) {
-
                rose_tmpn = rose_node_list;
                rose_tmpp = NULL;
-               while(rose_tmpn != NULL) {
+
+               while (rose_tmpn != NULL) {
                        if (rose_tmpn->mask > rose_route->mask) {
                                rose_tmpp = rose_tmpn;
                                rose_tmpn = rose_tmpn->next;
@@ -132,7 +132,6 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
 
                rose_node->address = rose_route->address;
                rose_node->mask    = rose_route->mask;
-               rose_node->which   = 0;
                rose_node->count   = 1;
                rose_node->neighbour[0] = rose_neigh;
 
@@ -163,13 +162,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
                return 0;
        }
 
-       /* We have space at the bottom, slot it in */
+       /* We have space, slot it in */
        if (rose_node->count < 3) {
-               rose_node->neighbour[2] = rose_node->neighbour[1];
-               rose_node->neighbour[1] = rose_node->neighbour[0];
-
-               rose_node->neighbour[0] = rose_neigh;
-
+               rose_node->neighbour[rose_node->count] = rose_neigh;
                rose_node->count++;
                rose_neigh->count++;
        }
@@ -302,7 +297,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
 
                        if (rose_neigh->count == 0)
                                rose_remove_neigh(rose_neigh);
-                               
+
                        rose_node->count--;
 
                        if (rose_node->count == 0) {
@@ -436,6 +431,7 @@ struct device *rose_dev_get(rose_address *addr)
 struct rose_neigh *rose_get_neigh(rose_address *addr)
 {
        struct rose_node *node;
+       int i;
 
        for (node = rose_node_list; node != NULL; node = node->next)
                if (rosecmpm(addr, &node->address, node->mask) == 0)
@@ -443,9 +439,11 @@ struct rose_neigh *rose_get_neigh(rose_address *addr)
 
        if (node == NULL) return NULL;
 
-       if (node->which >= node->count) return NULL;
+       for (i = 0; i < node->count; i++)
+               if (node->neighbour[i]->ftimer == 0)
+                       return node->neighbour[i];
 
-       return node->neighbour[node->which];
+       return NULL;
 }
 
 /*
@@ -494,25 +492,22 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
 void rose_link_failed(ax25_address *callsign, struct device *dev)
 {
        struct rose_neigh *rose_neigh;
-       struct rose_node  *rose_node;
        struct sk_buff    *skb;
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
                if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev)
                        break;
-                       
+
        if (rose_neigh == NULL) return;
 
        rose_neigh->restarted = 0;
        rose_neigh->t0timer   = 0;
-       del_timer(&rose_neigh->timer);
+       rose_neigh->ftimer    = sysctl_rose_link_fail_timeout;
+
+       rose_link_set_timer(rose_neigh);
 
        while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
-
-       for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-               if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh)
-                       rose_node->which++;
 }
 
 /*
@@ -521,35 +516,29 @@ void rose_link_failed(ax25_address *callsign, struct device *dev)
 void rose_link_device_down(struct device *dev)
 {
        struct rose_neigh *rose_neigh;
-       struct rose_node  *rose_node;
        struct sk_buff    *skb;
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
                if (rose_neigh->dev == dev) {
                        rose_neigh->restarted = 0;
                        rose_neigh->t0timer   = 0;
+                       rose_neigh->ftimer    = 0;
                        del_timer(&rose_neigh->timer);
 
                        while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
                                kfree_skb(skb, FREE_WRITE);
-       
-                       for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-                               if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh)
-                                       rose_node->which++;
                }
        }
 }
 
 /*
- *     Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
- *     indicates an internally generated frame.
+ *     Route a frame to an appropriate AX.25 connection.
  */
 int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 {
        struct rose_neigh *rose_neigh, *new_neigh;
-       struct rose_node  *rose_node;
        struct rose_route *rose_route;
-       rose_address *dest_addr;
+       rose_address *src_addr, *dest_addr;
        struct sock *sk;
        unsigned short frametype;
        unsigned int lci;
@@ -563,6 +552,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 
        frametype = skb->data[2];
        lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+       src_addr  = (rose_address *)(skb->data + 9);
+       dest_addr = (rose_address *)(skb->data + 4);
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
                if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->device == rose_neigh->dev)
@@ -571,6 +562,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        if (rose_neigh == NULL)
                return 0;
 
+       /*
+        *      Obviously the link is working, halt the ftimer.
+        */
+       rose_neigh->ftimer = 0;
+
        /*
         *      LCI of zero is always for us, and its always a restart
         *      frame.
@@ -591,12 +587,9 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        /*
         *      Is is a Call Request and is it for us ?
         */
-       if (frametype == ROSE_CALL_REQUEST) {
-               dest_addr = (rose_address *)(skb->data + 4);
-
+       if (frametype == ROSE_CALL_REQUEST)
                if ((dev = rose_dev_get(dest_addr)) != NULL)
                        return rose_rx_call_request(skb, dev, rose_neigh, lci);
-       }
 
        if (!sysctl_rose_routing_control) {
                rose_transmit_clear_request(rose_neigh, lci, 0x0D);
@@ -640,18 +633,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        if (frametype != ROSE_CALL_REQUEST)     /* XXX */
                return 0;
 
-       dest_addr = (rose_address *)(skb->data + 4);
-
-       /*
-        *      Create a new route entry, if we can.
-        */
-       for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-               if (rosecmpm(dest_addr, &rose_node->address, rose_node->mask) == 0)
-                       break;
-       /*
-        *      Its an unknown node, or is unreachable.
-        */
-       if (rose_node == NULL || rose_node->which >= rose_node->count) {
+       if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) {
                rose_transmit_clear_request(rose_neigh, lci, 0x0D);
                return 0;
        }
@@ -661,8 +643,6 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                return 0;
        }
 
-       new_neigh = rose_node->neighbour[rose_node->which];
-
        rose_route->lci1   = lci;
        rose_route->neigh1 = rose_neigh;
        rose_route->lci2   = rose_new_lci(new_neigh->dev);
@@ -693,13 +673,12 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset,
 
        cli();
 
-       len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
+       len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
 
        for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) {
-               len += sprintf(buffer + len, "%-10s %04d %d %d",
+               len += sprintf(buffer + len, "%-10s %04d %d",
                        rose2asc(&rose_node->address),
                        rose_node->mask,
-                       rose_node->which + 1,
                        rose_node->count);                      
 
                for (i = 0; i < rose_node->count; i++)
@@ -739,17 +718,17 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset,
 
        cli();
 
-       len += sprintf(buffer, "addr  callsign  dev  count  restart     t0\n");
+       len += sprintf(buffer, "addr  callsign  dev  count  restart   t0   tf\n");
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
-               len += sprintf(buffer + len, "%05d %-9s %-4s   %3d      %3s  %3d/%03d\n",
+               len += sprintf(buffer + len, "%05d %-9s %-4s   %3d      %3s  %3d  %3d\n",
                        rose_neigh->number,
                        ax2asc(&rose_neigh->callsign),
                        rose_neigh->dev ? rose_neigh->dev->name : "???",
                        rose_neigh->count,
                        (rose_neigh->restarted) ? "yes" : "no",
                        rose_neigh->t0timer / ROSE_SLOWHZ,
-                       rose_neigh->t0      / ROSE_SLOWHZ);
+                       rose_neigh->ftimer  / ROSE_SLOWHZ);
 
                pos = begin + len;
 
index 77ebabb1e1ffe0fee1eb75f2e7fa52703f847b0c..ffcb1cf9f1942ba7ec3168323a3fed93747d4510 100644 (file)
 static void rose_timer(unsigned long);
 
 /*
- *     Linux set/reset timer routines
+ *     Linux set timer
  */
 void rose_set_timer(struct sock *sk)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
-       del_timer(&sk->timer);
-       restore_flags(flags);
-
-       sk->timer.next     = sk->timer.prev = NULL;     
-       sk->timer.data     = (unsigned long)sk;
-       sk->timer.function = &rose_timer;
-
-       sk->timer.expires = jiffies + 10;
-       add_timer(&sk->timer);
-}
-
-static void rose_reset_timer(struct sock *sk)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        del_timer(&sk->timer);
        restore_flags(flags);
 
        sk->timer.data     = (unsigned long)sk;
        sk->timer.function = &rose_timer;
        sk->timer.expires  = jiffies + 10;
+
        add_timer(&sk->timer);
 }
 
@@ -121,7 +104,7 @@ static void rose_timer(unsigned long param)
        }
 
        if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) {
-               rose_reset_timer(sk);
+               rose_set_timer(sk);
                return;
        }
 
index 95234881756fbbd2a537293a95f26df26c51e5aa..c899a1837c21d578f61b924069fecbffebd15150 100644 (file)
 #include <net/ax25.h>
 #include <net/rose.h>
 
-static int min_timer[] = {1 * ROSE_SLOWHZ};
-static int max_timer[] = {300 * ROSE_SLOWHZ};
-static int min_idle[]  = {0 * ROSE_SLOWHZ};
-static int max_idle[]  = {65535 * ROSE_SLOWHZ};
-static int min_route[] = {0};
-static int max_route[] = {1};
+static int min_timer[]  = {1 * ROSE_SLOWHZ};
+static int max_timer[]  = {300 * ROSE_SLOWHZ};
+static int min_idle[]   = {0 * ROSE_SLOWHZ};
+static int max_idle[]   = {65535 * ROSE_SLOWHZ};
+static int min_route[]  = {0}, max_route[] = {1};
+static int min_ftimer[] = {60 * ROSE_SLOWHZ};
+static int max_ftimer[] = {600 * ROSE_SLOWHZ};
 
 static struct ctl_table_header *rose_table_header;
 
@@ -41,6 +42,9 @@ static ctl_table rose_table[] = {
         {NET_ROSE_ROUTING_CONTROL, "routing_control",
          &sysctl_rose_routing_control, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_route, &max_route},
+        {NET_ROSE_LINK_FAIL_TIMEOUT, "link_fail_timeout",
+         &sysctl_rose_link_fail_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_ftimer, &max_ftimer},
        {0}
 };
 
index 4e72dbbb370e60541defa1f8215f1207e471c10d..6f3b019c4ae511f894e4c2933c53899c39504087 100644 (file)
@@ -35,6 +35,9 @@
  *             Alan Cox        :       sendmsg/recvmsg basics.
  *             Tom Dyas        :       Export net symbols.
  *             Marcin Dalecki  :       Fixed problems with CONFIG_NET="n".
+ *             Alan Cox        :       Added thread locking to sys_* calls
+ *                                     for sockets. May have errors at the
+ *                                     moment.
  *
  *
  *             This program is free software; you can redistribute it and/or
  *     This module is effectively the top level interface to the BSD socket
  *     paradigm. 
  *
- * PROBLEMS:
- *     - CLONE_FILES. Big problem, cloned thread can close file,
- *       while other thread sleeps in kernel. It can be solved
- *       by increasing f_count and releasing it on exit from syscall.
- *       _HAS_ to be fixed before 2.2 is released. I assume whoever is
- *       working on the CLONE stuff will fix that pile of accidents. If
- *       you find this comment in a 2.2-preXXX kernel scream loudly.
- *
  */
 
 #include <linux/config.h>
 #include <linux/stat.h>
 #include <linux/socket.h>
 #include <linux/fcntl.h>
+#include <linux/file.h>
 #include <linux/net.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/firewall.h>
+#include <linux/wanrouter.h>
 
 #if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
 #include <linux/kerneld.h>
@@ -232,7 +229,7 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
        struct file *file;
        struct inode *inode;
 
-       if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd]))
+       if (!(file = fget(fd)))
        {
                *err = -EBADF;
                return NULL;
@@ -242,12 +239,18 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
        if (!inode || !inode->i_sock || !socki_lookup(inode))
        {
                *err = -ENOTSOCK;
+               fput(file,inode);
                return NULL;
        }
 
        return socki_lookup(inode);
 }
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+       fput(sock->file,sock->inode);
+}
+
 /*
  *     Allocate a socket.
  */
@@ -713,22 +716,16 @@ out:
 asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen)
 {
        struct socket *sock;
-       int i;
        char address[MAX_SOCK_ADDR];
        int err;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd,&err))) 
-               goto out;
-  
-       if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0)
-               goto out;
-  
-       if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0) 
-               err = i;
-       else
-               err = 0;
-out:
+       if((sock = sockfd_lookup(fd,&err))!=NULL)
+       {
+               if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0)
+                       err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
+               sockfd_put(sock);
+       }                       
        unlock_kernel();
        return err;
 }
@@ -743,15 +740,14 @@ out:
 asmlinkage int sys_listen(int fd, int backlog)
 {
        struct socket *sock;
-       int err=-EOPNOTSUPP;
+       int err;
        
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err))) 
-               goto out;
-
-       if (sock->ops && sock->ops->listen)
+       if((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
                err=sock->ops->listen(sock, backlog);
-out:
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -778,54 +774,50 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad
        int len;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err)))
-               goto out;
-       err = -EOPNOTSUPP;
-       if (!sock->ops->accept)
-               goto out;
-
-       err = -ENOSR;
-       if (!(newsock = sock_alloc())) 
-       {
-               printk(KERN_WARNING "accept: no more sockets\n");
-               goto out;       /* Was: EAGAIN, but we are out of system
-                                  resources! */
-       }
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               if (!(newsock = sock_alloc())) 
+               {
+                       printk(KERN_WARNING "accept: no more sockets\n");
+                       err=-EMFILE;
+                       goto out;
+               }
 
-       inode = newsock->inode;
-       newsock->type = sock->type;
+               inode = newsock->inode;
+               newsock->type = sock->type;
 
-       if ((err = sock->ops->dup(newsock, sock)) < 0) 
-       {
-               sock_release(newsock);
-               goto out;
-       }
+               if ((err = sock->ops->dup(newsock, sock)) < 0) 
+               {
+                       sock_release(newsock);
+                       goto out;
+               }
 
-       err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags);
+               err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags);
 
-       if (err < 0)
-       {
-               sock_release(newsock);
-               goto out;
-       }
-       newsock = socki_lookup(inode);
+               if (err < 0)
+               {
+                       sock_release(newsock);
+                       goto out;
+               }
+               newsock = socki_lookup(inode);
 
-       if ((fd = get_fd(inode)) < 0) 
-       {
-               sock_release(newsock);
-               err = -EINVAL;
-               goto out;
-       }
+               if ((err = get_fd(inode)) < 0) 
+               {
+                       sock_release(newsock);
+                       err=-EINVAL;
+                       goto out;
+               }
 
-       newsock->file = current->files->fd[fd];
+               newsock->file = current->files->fd[err];
        
-       if (upeer_sockaddr)
-       {
-               newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
-               move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
-       }
-       err = fd;
+               if (upeer_sockaddr)
+               {
+                       newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
+                       move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
+               }
 out:
+               sockfd_put(sock);               
+       }
        unlock_kernel();
        return err;
 }
@@ -850,17 +842,13 @@ asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
        int err;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd,&err)))
-               goto out;
-
-       if((err=move_addr_to_kernel(uservaddr,addrlen,address))<0)
-               goto out;
-  
-       err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
+       if ((sock = sockfd_lookup(fd,&err))!=NULL)
+       {
+               if((err=move_addr_to_kernel(uservaddr,addrlen,address))>=0)
+                       err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
                             current->files->fd[fd]->f_flags);
-       if (err >= 0)
-               err = 0;
-out:
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -878,16 +866,12 @@ asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockadd
        int err;
        
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err)))
-               goto out;
-
-       err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0);
-       if(err)
-               goto out;
-       if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
-               goto out;
-       err = 0;
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0))==0)
+                       err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -905,16 +889,12 @@ asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockadd
        int err;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err)))
-               goto out;
-
-       err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
-       if(err)
-               goto out;
-       if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
-               goto out;
-       err = 0;
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1))==0)
+                       err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -932,30 +912,27 @@ asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags)
        struct iovec iov;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err))) 
-               goto out;
-
-       err = -EINVAL;
-       if(len<0)
-               goto out;
-       err=verify_area(VERIFY_READ, buff, len);
-       if(err)
-               goto out;
-               
-       iov.iov_base=buff;
-       iov.iov_len=len;
-       msg.msg_name=NULL;
-       msg.msg_namelen=0;
-       msg.msg_iov=&iov;
-       msg.msg_iovlen=1;
-       msg.msg_control=NULL;
-       msg.msg_controllen=0;
-       if (current->files->fd[fd]->f_flags & O_NONBLOCK)
-               flags |= MSG_DONTWAIT;
-       msg.msg_flags=flags;
-
-       err = sock_sendmsg(sock, &msg, len);
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               if(len>=0)
+               {
+                       iov.iov_base=buff;
+                       iov.iov_len=len;
+                       msg.msg_name=NULL;
+                       msg.msg_namelen=0;
+                       msg.msg_iov=&iov;
+                       msg.msg_iovlen=1;
+                       msg.msg_control=NULL;
+                       msg.msg_controllen=0;
+                       if (current->files->fd[fd]->f_flags & O_NONBLOCK)
+                               flags |= MSG_DONTWAIT;
+                       msg.msg_flags=flags;
+                       err=sock_sendmsg(sock, &msg, len);
+               }
+               else
+                       err=-EINVAL;
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -976,35 +953,30 @@ asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags,
        struct iovec iov;
        
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd,&err)))
-               goto out;
-
-       err=verify_area(VERIFY_READ,buff,len);
-       if(err)
-               goto out;
-
-       iov.iov_base=buff;
-       iov.iov_len=len;
-       msg.msg_name=NULL;
-       msg.msg_iov=&iov;
-       msg.msg_iovlen=1;
-       msg.msg_control=NULL;
-       msg.msg_controllen=0;
-       msg.msg_namelen=addr_len;
-       if(addr)
+       if ((sock = sockfd_lookup(fd,&err))!=NULL)
        {
-               err=move_addr_to_kernel(addr,addr_len,address);
-               if (err < 0)
-                       goto out;
-               msg.msg_name=address;
+               iov.iov_base=buff;
+               iov.iov_len=len;
+               msg.msg_name=NULL;
+               msg.msg_iov=&iov;
+               msg.msg_iovlen=1;
+               msg.msg_control=NULL;
+               msg.msg_controllen=0;
+               msg.msg_namelen=addr_len;
+               if(addr)
+               {
+                       err=move_addr_to_kernel(addr,addr_len,address);
+                       if (err < 0)
+                               goto bad;
+                       msg.msg_name=address;
+               }
+               if (current->files->fd[fd]->f_flags & O_NONBLOCK)
+                       flags |= MSG_DONTWAIT;
+               msg.msg_flags=flags;
+               err=sock_sendmsg(sock, &msg, len);
+bad:           
+               sockfd_put(sock);
        }
-
-       if (current->files->fd[fd]->f_flags & O_NONBLOCK)
-               flags |= MSG_DONTWAIT;
-       msg.msg_flags=flags;
-
-       err = sock_sendmsg(sock, &msg, len);
-out:
        unlock_kernel();
        return err;
 }
@@ -1022,28 +994,20 @@ asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags)
        int err;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err))) 
-               goto out;
-
-       err = 0;
-       if(size==0)
-               goto out;
-       err=verify_area(VERIFY_WRITE, ubuf, size);
-       if(err)
-               goto out;
-
-       msg.msg_name=NULL;
-       msg.msg_iov=&iov;
-       msg.msg_iovlen=1;
-       msg.msg_control=NULL;
-       msg.msg_controllen=0;
-       iov.iov_base=ubuf;
-       iov.iov_len=size;
-
-       err = sock_recvmsg(sock, &msg, size,
-                          (current->files->fd[fd]->f_flags & O_NONBLOCK)
-                          ? flags | MSG_DONTWAIT : flags);
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {               
+               msg.msg_name=NULL;
+               msg.msg_iov=&iov;
+               msg.msg_iovlen=1;
+               msg.msg_control=NULL;
+               msg.msg_controllen=0;
+               iov.iov_base=ubuf;
+               iov.iov_len=size;
+
+               err=sock_recvmsg(sock, &msg, size,
+                           (current->files->fd[fd]->f_flags & O_NONBLOCK) ? flags | MSG_DONTWAIT : flags);
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -1061,39 +1025,29 @@ asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags,
        struct iovec iov;
        struct msghdr msg;
        char address[MAX_SOCK_ADDR];
-       int err;
+       int err,err2;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err)))
-               goto out;
-       err = 0;
-       if (size==0)
-               goto out;
-
-       err=verify_area(VERIFY_WRITE,ubuf,size);
-       if(err)
-               goto out;
-
-       msg.msg_control=NULL;
-       msg.msg_controllen=0;
-       msg.msg_iovlen=1;
-       msg.msg_iov=&iov;
-       iov.iov_len=size;
-       iov.iov_base=ubuf;
-       msg.msg_name=address;
-       msg.msg_namelen=MAX_SOCK_ADDR;
-       err = sock_recvmsg(sock, &msg, size,
-                          (current->files->fd[fd]->f_flags & O_NONBLOCK)
-                          ? (flags | MSG_DONTWAIT) : flags);
-
-       if(err<0)
-               goto out;
-       size=err;
-       if(addr!=NULL &&
-          (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0)
-               goto out;
-       err = size;
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {  
+               msg.msg_control=NULL;
+               msg.msg_controllen=0;
+               msg.msg_iovlen=1;
+               msg.msg_iov=&iov;
+               iov.iov_len=size;
+               iov.iov_base=ubuf;
+               msg.msg_name=address;
+               msg.msg_namelen=MAX_SOCK_ADDR;
+               err=sock_recvmsg(sock, &msg, size,
+                         (current->files->fd[fd]->f_flags & O_NONBLOCK) ? (flags | MSG_DONTWAIT) : flags);
+               if(err>=0 && addr!=NULL)
+               {
+                       err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
+                       if(err2<0)
+                               err=err2;
+               }
+               sockfd_put(sock);                       
+       }               
        unlock_kernel();
        return err;
 }
@@ -1109,16 +1063,14 @@ asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int
        struct socket *sock;
        
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err))) 
-               goto out;
-
-       if (level == SOL_SOCKET)
-               err = sock_setsockopt(sock,level,optname,optval,optlen);
-       else if (sock->ops->setsockopt)
-               err = sock->ops->setsockopt(sock, level, optname, optval, optlen);
-       else
-               err = -EOPNOTSUPP;
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               if (level == SOL_SOCKET)
+                       err=sock_setsockopt(sock,level,optname,optval,optlen);
+               else
+                       err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -1134,16 +1086,14 @@ asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int
        struct socket *sock;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err)))
-               goto out;
-           
-       if (level == SOL_SOCKET)
-               err = sock_getsockopt(sock,level,optname,optval,optlen);
-       else if (sock->ops->getsockopt)
-               err = sock->ops->getsockopt(sock, level, optname, optval, optlen);
-       else
-               err = -EOPNOTSUPP;
-out:
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               if (level == SOL_SOCKET)
+                       err=sock_getsockopt(sock,level,optname,optval,optlen);
+               else
+                       err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -1159,12 +1109,11 @@ asmlinkage int sys_shutdown(int fd, int how)
        struct socket *sock;
 
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err))) 
-               goto out;
-
-       err = sock->ops->shutdown(sock, how);
-out:
-       unlock_kernel();
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               err=sock->ops->shutdown(sock, how);
+               sockfd_put(sock);
+       }
        return err;
 }
 
@@ -1179,36 +1128,32 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
        struct iovec iov[UIO_FASTIOV];
        unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */
        struct msghdr msg_sys;
-       int err;
+       int err= -EINVAL;
        int total_len;
        
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd,&err)))
-               goto out;
-       
-       err = -EOPNOTSUPP;
-       if (sock->ops->sendmsg==NULL)
-               goto out;
 
-       err = -EFAULT;
        if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-               goto out;
-
+       {
+               err=-EFAULT;
+               goto out; 
+       }
        /* do not move before msg_sys is valid */
-       err = -EINVAL;
        if (msg_sys.msg_iovlen>UIO_MAXIOV)
                goto out;
-
        /* This will also move the address data into kernel space */
        err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
        if (err < 0)
                goto out;
        total_len=err;
 
-       if (msg_sys.msg_controllen) {
-               if (msg_sys.msg_controllen > sizeof(ctl)) {
+       if (msg_sys.msg_controllen) 
+       {
+               if (msg_sys.msg_controllen > sizeof(ctl)) 
+               {
                        char *tmp = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
-                       if (tmp == NULL) {
+                       if (tmp == NULL) 
+                       {
                                err = -ENOBUFS;
                                goto failed2;
                        }
@@ -1221,12 +1166,15 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
                if (err)
                        goto failed;
        }
-
        msg_sys.msg_flags = flags;
        if (current->files->fd[fd]->f_flags & O_NONBLOCK)
                msg_sys.msg_flags |= MSG_DONTWAIT;
 
-       err = sock_sendmsg(sock, &msg_sys, total_len);
+       if ((sock = sockfd_lookup(fd,&err))!=NULL)
+       {
+               err = sock_sendmsg(sock, &msg_sys, total_len);
+               sockfd_put(sock);
+       }
 
 failed:
        if (msg_sys.msg_controllen && msg_sys.msg_control != ctl)
@@ -1262,17 +1210,17 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        int *uaddr_len;
        
        lock_kernel();
-       if (!(sock = sockfd_lookup(fd, &err)))
-               goto out;
-
-       err = -EFAULT;
        if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-               goto out; 
-
-       err = -EINVAL;
+       {
+               err=-EFAULT;
+               goto out;
+       }
        if (msg_sys.msg_iovlen>UIO_MAXIOV)
+       {
+               err=-EFAULT;
                goto out;
-
+       }
+       
        /*
         *      Save the user-mode address (verify_iovec will change the
         *      kernel msghdr to use the kernel address space)
@@ -1291,34 +1239,35 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        
        if (current->files->fd[fd]->f_flags&O_NONBLOCK)
                flags |= MSG_DONTWAIT;
-       len=sock_recvmsg(sock, &msg_sys, total_len, flags);
+
+
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               err=sock_recvmsg(sock, &msg_sys, total_len, flags);
+               if(err>=0)
+                       len=err;
+               sockfd_put(sock);
+       }
        if (msg_sys.msg_iov != iov)
                kfree(msg_sys.msg_iov);
-       if (len<0) {
-               err = len;
-               goto out;
-       }
 
-       if (uaddr != NULL)
-       {
+       if (uaddr != NULL && err>=0)
                err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
-               if (err)
-                       goto out;
-       }
-       err = -EFAULT;
-       if (put_user(msg_sys.msg_flags, &msg->msg_flags))
-               goto out;
-       if (put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen))
-               goto out;
-       err = len;
+       if (err>=0 && (put_user(msg_sys.msg_flags, &msg->msg_flags) || 
+               put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen)))
+               err = -EFAULT;
 out:
        unlock_kernel();
-       return err;
+       if(err<0)
+               return err;
+       return len;
 }
 
 
 /*
  *     Perform a file control on a socket file descriptor.
+ *
+ *     FIXME: does this need an fd lock ?
  */
 
 int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
@@ -1356,6 +1305,12 @@ asmlinkage int sys_socketcall(int call, unsigned long *args)
        if(call<1||call>SYS_RECVMSG)
                goto out;
        err = -EFAULT;
+
+       /*
+        *      Ideally we want to precompute the maths, but unsigned long
+        *      isnt a fixed size....
+        */
+        
        if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long))))
                goto out;
                
@@ -1478,7 +1433,8 @@ void sock_init(void)
         *      Initialize all address (protocol) families. 
         */
         
-       for (i = 0; i < NPROTO; i++) net_families[i] = NULL;
+       for (i = 0; i < NPROTO; i++) 
+               net_families[i] = NULL;
 
        /*
         *      Initialize sock SLAB cache.
@@ -1494,6 +1450,14 @@ void sock_init(void)
        init_netlink();
 #endif
 
+       /*
+        *      Wan router layer. 
+        */
+
+#ifdef CONFIG_WAN_ROUTER        
+       wanrouter_init();
+#endif
+
        /*
         *      Attach the firewall module if configured
         */
diff --git a/net/wanrouter/Makefile b/net/wanrouter/Makefile
new file mode 100644 (file)
index 0000000..12afaee
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for the Linux WAN router layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := wanrouter.o
+O_OBJS   := wanmain.o wanproc.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+tar:
+       tar -cvf /dev/f1 .
diff --git a/net/wanrouter/patchlevel b/net/wanrouter/patchlevel
new file mode 100644 (file)
index 0000000..3eefcb9
--- /dev/null
@@ -0,0 +1 @@
+1.0.0
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
new file mode 100644 (file)
index 0000000..948bf81
--- /dev/null
@@ -0,0 +1,676 @@
+/*****************************************************************************
+* wanmain.c    WAN Multiprotocol Router Module. Main code.
+*
+*              This module is completely hardware-independent and provides
+*              the following common services for the WAN Link Drivers:
+*               o WAN device managenment (registering, unregistering)
+*               o Network interface management
+*               o Physical connection management (dial-up, incomming calls)
+*               o Logical connection management (switched virtual circuits)
+*               o Protocol encapsulation/decapsulation
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 27, 1996 Gene Kozin      Initial version (based on Sangoma's WANPIPE)
+* Jan 31, 1997  Alan Cox       Hacked it about a bit for 2.1
+*****************************************************************************/
+
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/config.h>      /* OS configuration options */
+#include <linux/kernel.h>
+#include <linux/module.h>      /* support for loadable modules */
+#include <linux/malloc.h>      /* kmalloc(), kfree() */
+#include <linux/mm.h>          /* verify_area(), etc. */
+#include <linux/string.h>      /* inline mem*, str* functions */
+#include <asm/segment.h>       /* kernel <-> user copy */
+#include <asm/byteorder.h>     /* htons(), etc. */
+#include <asm/uaccess.h>       /* copy_to/from_user */
+#include <linux/wanrouter.h>   /* WAN router API definitions */
+
+/****** Defines and Macros **************************************************/
+
+#ifndef        min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef        max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/****** Function Prototypes *************************************************/
+
+/*
+ *     Kernel loadable module interface.
+ */
+
+#ifdef MODULE
+int init_module (void);
+void cleanup_module (void);
+#endif
+
+/*
+ *     WAN device IOCTL handlers 
+ */
+
+static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf);
+static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat);
+static int device_shutdown (wan_device_t* wandev);
+static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf);
+static int device_del_if (wan_device_t* wandev, char* u_name);
+
+/*
+ *     Miscellaneous 
+ */
+
+static wan_device_t* find_device (char* name);
+static int delete_interface (wan_device_t* wandev, char* name, int forse);
+
+/*
+ *     Global Data
+ */
+
+static char fullname[]         = "WAN Router";
+static char copyright[]                = "(c) 1995-1996 Sangoma Technologies Inc.";
+static char modname[]          = ROUTER_NAME;  /* short module name */
+static wan_device_t* devlist   = NULL; /* list of registered devices */
+static int devcnt              = 0;
+
+/*
+ *     Organizationally Unique Identifiers for encapsulation/decapsulation
+ */
+static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 };
+static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };
+
+#ifdef MODULE
+
+/*
+ *     Kernel Loadable Module Entry Points
+ */
+
+/*
+ *     Module 'insert' entry point.
+ *     o print announcement
+ *     o initialize static data
+ *     o create /proc/net/router directory and static entries
+ *
+ *     Return: 0       Ok
+ *             < 0     error.
+ *     Context:        process
+ */
+
+int init_module        (void)
+{
+       int err;
+
+       printk(KERN_INFO "%s v%u.%u %s\n",
+               fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
+       err = wanrouter_proc_init();
+       if (err) printk(KERN_ERR
+               "%s: can't create entry in proc filesystem!\n", modname);
+       return err;
+}
+
+/*
+ *     Module 'remove' entry point.
+ *     o delete /proc/net/router directory and static entries.
+ */
+void cleanup_module (void)
+{
+       wanrouter_proc_cleanup();
+}
+
+#else
+
+void wanrouter_init(void)
+{
+       int err = wanrouter_proc_init();
+       if (err) printk(KERN_ERR
+               "%s: can't create entry in proc filesystem!\n", modname);
+}
+#endif
+
+/*
+ *     Kernel APIs
+ */
+
+/*
+ *     Register WAN device.
+ *     o verify device credentials
+ *     o create an entry for the device in the /proc/net/router directory
+ *     o initialize internally maintained fields of the wan_device structure
+ *     o link device data space to a singly-linked list
+ *     o if it's the first device, then start kernel 'thread'
+ *     o increment module use count
+ *
+ *      Return:
+ *             0       Ok
+ *             < 0     error.
+ *
+ *     Context:        process
+ */
+
+int register_wan_device(wan_device_t* wandev)
+{
+       int err, namelen;
+
+       if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) ||
+           (wandev->name == NULL))
+               return -EINVAL;
+               
+       namelen = strlen(wandev->name);
+       if (!namelen || (namelen > WAN_DRVNAME_SZ))
+               return -EINVAL;
+               
+       if (find_device(wandev->name) != NULL)
+               return -EEXIST;
+
+#ifdef WANDEBUG                
+       printk(KERN_INFO "%s: registering WAN device %s\n",
+               modname, wandev->name);
+#endif
+
+       /*
+        *      Register /proc directory entry 
+        */
+       err = wanrouter_proc_add(wandev);
+       if (err)
+       {
+               printk(KERN_ERR
+                       "%s: can't create /proc/net/router/%s entry!\n",
+                       modname, wandev->name)
+               ;
+               return err;
+       }
+
+       /*
+        *      Initialize fields of the wan_device structure maintained by the
+        *      router and update local data.
+        */
+        
+       wandev->ndev = 0;
+       wandev->dev  = NULL;
+       wandev->next = devlist;
+       devlist = wandev;
+       ++devcnt;
+        MOD_INC_USE_COUNT;     /* prevent module from unloading */
+       return 0;
+}
+
+/*
+ *     Unregister WAN device.
+ *     o shut down device
+ *     o unlink device data space from the linked list
+ *     o delete device entry in the /proc/net/router directory
+ *     o decrement module use count
+ *
+ *     Return:         0       Ok
+ *                     <0      error.
+ *     Context:        process
+ */
+int unregister_wan_device(char* name)
+{
+       wan_device_t *wandev, *prev;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       for (wandev = devlist, prev = NULL;
+               wandev && strcmp(wandev->name, name);
+               prev = wandev, wandev = wandev->next)
+               ;
+       if (wandev == NULL)
+               return -ENODEV;
+
+#ifdef WANDEBUG                
+       printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name);
+#endif
+       
+       if (wandev->state != WAN_UNCONFIGURED)
+       {
+               while(wandev->dev)
+                       delete_interface(wandev, wandev->dev->name, 1);
+               if (wandev->shutdown)   
+                       wandev->shutdown(wandev);
+       }
+       if (prev)
+               prev->next = wandev->next;
+       else
+               devlist = wandev->next;
+       --devcnt;
+       wanrouter_proc_delete(wandev);
+        MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/*
+ *     Encapsulate packet.
+ *
+ *     Return: encapsulation header size
+ *             < 0     - unsupported Ethertype
+ *
+ *     Notes:
+ *     1. This function may be called on interrupt context.
+ */
+
+int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev)
+{
+       int hdr_len = 0;
+
+       switch (skb->protocol)
+       {
+       case ETH_P_IP:          /* IP datagram encapsulation */
+               hdr_len += 1;
+               skb_push(skb, 1);
+               skb->data[0] = NLPID_IP;
+               break;
+
+       case ETH_P_IPX:         /* SNAP encapsulation */
+       case ETH_P_ARP:
+               hdr_len += 6;
+               skb_push(skb, 6);
+               skb->data[0] = NLPID_SNAP;
+               memcpy(&skb->data[1], oui_ether, sizeof(oui_ether));
+               *((unsigned short*)&skb->data[4]) = htons(skb->protocol);
+               break;
+
+       default:                /* Unknown packet type */
+               printk(KERN_INFO
+                       "%s: unsupported Ethertype 0x%04X on interface %s!\n",
+                       modname, skb->protocol, dev->name);
+               hdr_len = -EINVAL;
+       }
+       return hdr_len;
+}
+
+/*
+ *     Decapsulate packet.
+ *
+ *     Return: Ethertype (in network order)
+ *                     0       unknown encapsulation
+ *
+ *     Notes:
+ *     1. This function may be called on interrupt context.
+ */
+
+unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev)
+{
+       int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */
+       unsigned short ethertype;
+
+       switch (skb->data[cnt])
+       {
+       case NLPID_IP:          /* IP datagramm */
+               ethertype = htons(ETH_P_IP);
+               cnt += 1;
+               break;
+
+        case NLPID_SNAP:       /* SNAP encapsulation */
+               if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether)))
+               {
+                       printk(KERN_INFO
+                               "%s: unsupported SNAP OUI %02X-%02X-%02X "
+                               "on interface %s!\n", modname,
+                               skb->data[cnt+1], skb->data[cnt+2],
+                               skb->data[cnt+3], dev->name);
+                       ;
+                       return 0;
+               }       
+               ethertype = *((unsigned short*)&skb->data[cnt+4]);
+               cnt += 6;
+               break;
+
+       /* add other protocols, e.g. CLNP, ESIS, ISIS, if needed */
+
+       default:
+               printk(KERN_INFO
+                       "%s: unsupported NLPID 0x%02X on interface %s!\n",
+                       modname, skb->data[cnt], dev->name)
+               ;
+               return 0;
+       }
+       skb->protocol = ethertype;
+       skb->pkt_type = PACKET_HOST;    /*      Physically point to point */
+       skb->mac.raw  = skb->data;
+       skb_pull(skb, cnt);
+       return ethertype;
+}
+
+/*
+ *     WAN device IOCTL.
+ *     o find WAN device associated with this node
+ *     o execute requested action or pass command to the device driver
+ */
+
+int wanrouter_ioctl(struct inode* inode, struct file* file,
+               unsigned int cmd, unsigned long arg)
+{
+       int err = 0;
+       struct proc_dir_entry* dent;
+       wan_device_t* wandev;
+
+       if (!suser())
+               return -EPERM;
+               
+       if ((cmd >> 8) != ROUTER_IOCTL)
+               return -EINVAL;
+               
+       dent = inode->u.generic_ip;
+       if ((dent == NULL) || (dent->data == NULL))
+               return -EINVAL;
+               
+       wandev = dent->data;
+       if (wandev->magic != ROUTER_MAGIC)
+               return -EINVAL;
+               
+       switch (cmd)
+       {
+       case ROUTER_SETUP:
+               err = device_setup(wandev, (void*)arg);
+               break;
+
+       case ROUTER_DOWN:
+               err = device_shutdown(wandev);
+               break;
+
+       case ROUTER_STAT:
+               err = device_stat(wandev, (void*)arg);
+               break;
+
+       case ROUTER_IFNEW:
+               err = device_new_if(wandev, (void*)arg);
+               break;
+
+       case ROUTER_IFDEL:
+               err = device_del_if(wandev, (void*)arg);
+               break;
+
+       case ROUTER_IFSTAT:
+               break;
+
+       default:
+               if ((cmd >= ROUTER_USER) &&
+                   (cmd <= ROUTER_USER_MAX) &&
+                   wandev->ioctl)
+                       err = wandev->ioctl(wandev, cmd, arg)
+               ;
+               else err = -EINVAL;
+       }
+       return err;
+}
+
+/*
+ *     WAN Driver IOCTL Handlers
+ */
+
+/*
+ *     Setup WAN link device.
+ *     o verify user address space
+ *     o allocate kernel memory and copy configuration data to kernel space
+ *     o if configuration data includes extension, copy it to kernel space too
+ *     o call driver's setup() entry point
+ */
+
+static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
+{
+       void* data;
+       wandev_conf_t* conf;
+       int err= -EINVAL;
+
+       if (wandev->setup == NULL)      /* Nothing to do ? */
+               return 0;
+               
+       conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL);
+       if (conf == NULL)
+               return -ENOBUFS;
+               
+       if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t)))
+       {
+               kfree(conf);
+               return -EFAULT;
+       }
+       
+       if (conf->magic != ROUTER_MAGIC)
+               goto bail;
+
+       if (conf->data_size && conf->data)
+       {
+               if(conf->data_size > 1024 || conf->data_size < 0)
+                       goto bail;
+               data = kmalloc(conf->data_size, GFP_KERNEL);
+               if (data)
+               {
+                       if(!copy_from_user(data, conf->data, conf->data_size))
+                       {
+                               conf->data=data;
+                               wandev->setup(wandev,conf);
+                       }
+                       else 
+                               err = -ENOBUFS;
+               }
+               if (data)
+                       kfree(data);
+       }
+bail:
+       kfree(conf);
+       return err;
+}
+
+/*
+ *     Shutdown WAN device.
+ *     o delete all not opened logical channels for this device
+ *     o call driver's shutdown() entry point
+ */
+static int device_shutdown (wan_device_t* wandev)
+{
+       struct device* dev;
+
+       if (wandev->state == WAN_UNCONFIGURED)
+               return 0;
+               
+       for (dev = wandev->dev; dev;)
+       {
+               if (delete_interface(wandev, dev->name, 0))
+                       dev = dev->slave;
+       }
+       if (wandev->ndev)
+               return -EBUSY;  /* there are opened interfaces  */
+               
+       if (wandev->shutdown)
+               return wandev->shutdown(wandev);
+       return 0;
+}
+
+/*
+ *     Get WAN device status & statistics.
+ */
+
+static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat)
+{
+       wandev_stat_t stat;
+
+       memset(&stat, 0, sizeof(stat));
+
+       /* Ask device driver to update device statistics */
+       if ((wandev->state != WAN_UNCONFIGURED) && wandev->update)
+               wandev->update(wandev);
+
+       /* Fill out structure */
+       stat.ndev  = wandev->ndev;
+       stat.state = wandev->state;
+
+       if(copy_to_user(u_stat, &stat, sizeof(stat)))
+               return -EFAULT;
+       return 0;
+}
+
+/*
+ *     Create new WAN interface.
+ *     o verify user address space
+ *     o copy configuration data to kernel address space
+ *     o allocate network interface data space
+ *     o call driver's new_if() entry point
+ *     o make sure there is no interface name conflict
+ *     o register network interface
+ */
+
+static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf)
+{
+       wanif_conf_t conf;
+       struct device* dev;
+       int err;
+
+       if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
+               return -ENODEV;
+               
+       if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
+               return -EFAULT;
+               
+       if (conf.magic != ROUTER_MAGIC)
+               return -EINVAL;
+               
+       dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+       if (dev == NULL)
+               return -ENOBUFS;
+               
+       memset(dev, 0, sizeof(struct device));
+       err = wandev->new_if(wandev, dev, &conf);
+       if (!err)
+       {
+               /* Register network interface. This will invoke init()
+                * function supplied by the driver.  If device registered
+                * successfully, add it to the interface list.
+                */
+               if (dev->name == NULL)
+                       err = -EINVAL;
+                       
+               else if (dev_get(dev->name))
+                       err = -EEXIST;  /* name already exists */
+               else
+               {
+#ifdef WANDEBUG                
+                       printk(KERN_INFO "%s: registering interface %s...\n",
+                               modname, dev->name);
+#endif                         
+                       err = register_netdev(dev);
+                       if (!err)
+                       {
+                               cli();  /***** critical section start *****/
+                               dev->slave = wandev->dev;
+                               wandev->dev = dev;
+                               ++wandev->ndev;
+                               sti();  /****** critical section end ******/
+                               return 0;       /* done !!! */
+                       }
+               }
+               if (wandev->del_if)
+                       wandev->del_if(wandev, dev);
+       }
+       kfree(dev);
+       return err;
+}
+
+/*
+ *     Delete WAN logical channel.
+ *      o verify user address space
+ *      o copy configuration data to kernel address space
+ */
+
+static int device_del_if (wan_device_t* wandev, char* u_name)
+{
+       char name[WAN_IFNAME_SZ + 1];
+
+       if (wandev->state == WAN_UNCONFIGURED)
+               return -ENODEV;
+               
+       memset(name, 0, sizeof(name));
+       if(copy_from_user(name, u_name, WAN_IFNAME_SZ))
+               return -EFAULT;
+       return delete_interface(wandev, name, 0);
+}
+
+/*
+ *     Miscellaneous Functions
+ */
+
+/*
+ *     Find WAN device by name.
+ *     Return pointer to the WAN device data space or NULL if device not found.
+ */
+
+static wan_device_t* find_device (char* name)
+{
+       wan_device_t* wandev;
+
+       for (wandev = devlist;wandev && strcmp(wandev->name, name);
+               wandev = wandev->next);
+       return wandev;
+}
+
+/*
+ *     Delete WAN logical channel identified by its name.
+ *     o find logical channel by its name
+ *     o call driver's del_if() entry point
+ *     o unregister network interface
+ *     o unlink channel data space from linked list of channels
+ *     o release channel data space
+ *
+ *     Return: 0               success
+ *             -ENODEV         channel not found.
+ *             -EBUSY          interface is open
+ *
+ *     Note: If (force != 0), then device will be destroyed even if interface
+ *     associated with it is open. It's caller's responsibility to make
+ *     sure that opened interfaces are not removed!
+ */
+
+static int delete_interface (wan_device_t* wandev, char* name, int force)
+{
+       struct device *dev, *prev;
+
+       for (dev = wandev->dev, prev = NULL;
+               dev && strcmp(name, dev->name);
+               prev = dev, dev = dev->slave);
+
+       if (dev == NULL)
+               return -ENODEV; /* interface not found */
+
+       if (dev->start)
+       {
+               if (force)
+               {
+                       printk(KERN_WARNING
+                               "%s: deleting opened interface %s!\n",modname, name);
+               }
+               else
+                       return -EBUSY;  /* interface in use */
+       }
+       if (wandev->del_if)
+               wandev->del_if(wandev, dev);
+
+       cli();                  /***** critical section start *****/
+       if (prev)
+               prev->slave = dev->slave;
+       else
+               wandev->dev = dev->slave;
+       --wandev->ndev;
+       sti();                  /****** critical section end ******/
+
+       unregister_netdev(dev);
+       kfree(dev);
+       return 0;
+}
+
+/*
+ *     End
+ */
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
new file mode 100644 (file)
index 0000000..769269b
--- /dev/null
@@ -0,0 +1,460 @@
+/*****************************************************************************
+* wanproc.c    WAN Multiprotocol Router Module. proc filesystem interface.
+*
+*              This module is completely hardware-independent and provides
+*              access to the router using Linux /proc filesystem.
+*
+* Author:      Gene Kozin      <genek@compuserve.com>
+*
+* Copyright:   (c) 1995-1996 Sangoma Technologies Inc.
+*
+*              This program is free software; you can redistribute it and/or
+*              modify it under the terms of the GNU General Public License
+*              as published by the Free Software Foundation; either version
+*              2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 13, 1996 Gene Kozin      Initial version (based on Sangoma's WANPIPE)
+* Jan 30, 1997 Alan Cox        Hacked around for 2.1
+*****************************************************************************/
+
+#include <linux/stddef.h>      /* offsetof(), etc. */
+#include <linux/errno.h>       /* return codes */
+#include <linux/kernel.h>
+#include <linux/malloc.h>      /* kmalloc(), kfree() */
+#include <linux/mm.h>          /* verify_area(), etc. */
+#include <linux/string.h>      /* inline mem*, str* functions */
+#include <asm/segment.h>       /* kernel <-> user copy */
+#include <asm/byteorder.h>     /* htons(), etc. */
+#include <asm/uaccess.h>       /* copy_to_user */
+#include <linux/wanrouter.h>   /* WAN router API definitions */
+
+
+/****** Defines and Macros **************************************************/
+
+#ifndef        min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef        max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define        ROUTER_PAGE_SZ  4000    /* buffer size for printing proc info */
+
+/****** Data Types **********************************************************/
+
+typedef struct wan_stat_entry
+{
+       struct wan_stat_entry * next;
+       char *description;              /* description string */
+       void *data;                     /* -> data */
+       unsigned data_type;             /* data type */
+} wan_stat_entry_t;
+
+/****** Function Prototypes *************************************************/
+
+/* Proc filesystem interface */
+static int router_proc_perms (struct inode*, int);
+static long router_proc_read(struct inode* inode, struct file* file, char* buf,
+                               unsigned long count);
+
+/* Methods for preparing data for reading proc entries */
+
+static int about_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+
+/* Miscellaneous */
+
+/*
+ *     Global Data
+ */
+
+/*
+ *     Names of the proc directory entries 
+ */
+
+static char name_root[]        = ROUTER_NAME;
+static char name_info[]        = "about";
+static char name_conf[]        = "config";
+static char name_stat[]        = "status";
+
+/*
+ *     Structures for interfacing with the /proc filesystem.
+ *     Router creates its own directory /proc/net/router with the folowing
+ *     entries:
+ *     About           general information (version, copyright, etc.)
+ *     Conf            device configuration
+ *     Stat            global device statistics
+ *     <device>        entry for each WAN device
+ */
+
+/*
+ *     Generic /proc/net/router/<file> file and inode operations 
+ */
+
+static struct file_operations router_fops =
+{
+       NULL,                   /* lseek   */
+       router_proc_read,       /* read    */
+       NULL,                   /* write   */
+       NULL,                   /* readdir */
+       NULL,                   /* select  */
+       NULL,                   /* ioctl   */
+       NULL,                   /* mmap    */
+       NULL,                   /* no special open code    */
+       NULL,                   /* no special release code */
+       NULL                    /* can't fsync */
+};
+
+static struct inode_operations router_inode =
+{
+       &router_fops,
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       router_proc_perms
+};
+
+/*
+ *     /proc/net/router/<device> file and inode operations
+ */
+
+static struct file_operations wandev_fops =
+{
+       NULL,                   /* lseek   */
+       router_proc_read,       /* read    */
+       NULL,                   /* write   */
+       NULL,                   /* readdir */
+       NULL,                   /* select  */
+       wanrouter_ioctl,        /* ioctl   */
+       NULL,                   /* mmap    */
+       NULL,                   /* no special open code    */
+       NULL,                   /* no special release code */
+       NULL                    /* can't fsync */
+};
+
+static struct inode_operations wandev_inode =
+{
+       &wandev_fops,
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       router_proc_perms
+};
+
+/*
+ * Proc filesystem derectory entries.
+ */
+
+/*
+ *     /proc/net/router 
+ */
+static struct proc_dir_entry proc_router =
+{
+       0,                      /* .low_ino */
+       sizeof(name_root) - 1,  /* .namelen */
+       name_root,              /* .name */
+       0555 | S_IFDIR,         /* .mode */
+       2,                      /* .nlink */
+       0,                      /* .uid */
+       0,                      /* .gid */
+       0,                      /* .size */
+       &proc_dir_inode_operations, /* .ops */
+       NULL,                   /* .get_info */
+       NULL,                   /* .fill_node */
+       NULL,                   /* .next */
+       NULL,                   /* .parent */
+       NULL,                   /* .subdir */
+       NULL,                   /* .data */
+};
+
+/*
+ *     /proc/net/router/about 
+ */
+static struct proc_dir_entry proc_router_info =
+{
+       0,                      /* .low_ino */
+       sizeof(name_info) - 1,  /* .namelen */
+       name_info,              /* .name */
+       0444 | S_IFREG,         /* .mode */
+       1,                      /* .nlink */
+       0,                      /* .uid */
+       0,                      /* .gid */
+       0,                      /* .size */
+       &router_inode,          /* .ops */
+       &about_get_info,        /* .get_info */
+       NULL,                   /* .fill_node */
+       NULL,                   /* .next */
+       NULL,                   /* .parent */
+       NULL,                   /* .subdir */
+       NULL,                   /* .data */
+};
+
+/*
+ *     /proc/net/router/config 
+ */
+static struct proc_dir_entry proc_router_conf =
+{
+       0,                      /* .low_ino */
+       sizeof(name_conf) - 1,  /* .namelen */
+       name_conf,              /* .name */
+       0444 | S_IFREG,         /* .mode */
+       1,                      /* .nlink */
+       0,                      /* .uid */
+       0,                      /* .gid */
+       0,                      /* .size */
+       &router_inode,          /* .ops */
+       &config_get_info,       /* .get_info */
+       NULL,                   /* .fill_node */
+       NULL,                   /* .next */
+       NULL,                   /* .parent */
+       NULL,                   /* .subdir */
+       NULL,                   /* .data */
+};
+
+/*
+ *     /proc/net/router/status 
+ */
+static struct proc_dir_entry proc_router_stat =
+{
+       0,                      /* .low_ino */
+       sizeof(name_stat) - 1,  /* .namelen */
+       name_stat,              /* .name */
+       0444 | S_IFREG,         /* .mode */
+       1,                      /* .nlink */
+       0,                      /* .uid */
+       0,                      /* .gid */
+       0,                      /* .size */
+       &router_inode,          /* .ops */
+       status_get_info,        /* .get_info */
+       NULL,                   /* .fill_node */
+       NULL,                   /* .next */
+       NULL,                   /* .parent */
+       NULL,                   /* .subdir */
+       NULL,                   /* .data */
+};
+
+/*
+ *     Interface functions
+ */
+
+/*
+ *     Initialize router proc interface.
+ */
+
+int wanrouter_proc_init (void)
+{
+       int err = proc_register_dynamic(&proc_net, &proc_router);
+
+       if (!err)
+       {
+               proc_register_dynamic(&proc_router, &proc_router_info);
+               proc_register_dynamic(&proc_router, &proc_router_conf);
+               proc_register_dynamic(&proc_router, &proc_router_stat);
+       }
+       return err;
+}
+
+/*
+ *     Clean up router proc interface.
+ */
+
+void wanrouter_proc_cleanup (void)
+{
+       proc_unregister(&proc_router, proc_router_info.low_ino);
+       proc_unregister(&proc_router, proc_router_conf.low_ino);
+       proc_unregister(&proc_router, proc_router_stat.low_ino);
+       proc_unregister(&proc_net, proc_router.low_ino);
+}
+
+/*
+ *     Add directory entry for WAN device.
+ */
+
+int wanrouter_proc_add (wan_device_t* wandev)
+{
+       if (wandev->magic != ROUTER_MAGIC)
+               return -EINVAL;
+               
+       memset(&wandev->dent, 0, sizeof(wandev->dent));
+       wandev->dent.namelen    = strlen(wandev->name);
+       wandev->dent.name       = wandev->name;
+       wandev->dent.mode       = 0444 | S_IFREG;
+       wandev->dent.nlink      = 1;
+       wandev->dent.ops        = &wandev_inode;
+       wandev->dent.get_info   = &wandev_get_info;
+       wandev->dent.data       = wandev;
+       return proc_register_dynamic(&proc_router, &wandev->dent);
+}
+
+/*
+ *     Delete directory entry for WAN device.
+ */
+int wanrouter_proc_delete(wan_device_t* wandev)
+{
+       if (wandev->magic != ROUTER_MAGIC)
+               return -EINVAL;
+       proc_unregister(&proc_router, wandev->dent.low_ino);
+       return 0;
+}
+
+/****** Proc filesystem entry points ****************************************/
+
+/*
+ *     Verify access rights.
+ */
+
+static int router_proc_perms (struct inode* inode, int op)
+{
+       return 0;
+}
+
+/*
+ *     Read router proc directory entry.
+ *     This is universal routine for reading all entries in /proc/net/router
+ *     directory.  Each directory entry contains a pointer to the 'method' for
+ *     preparing data for that entry.
+ *     o verify arguments
+ *     o allocate kernel buffer
+ *     o call get_info() to prepare data
+ *     o copy data to user space
+ *     o release kernel buffer
+ *
+ *     Return: number of bytes copied to user space (0, if no data)
+ *             <0      error
+ */
+
+static long router_proc_read(struct inode* inode, struct file* file, 
+                               char* buf, unsigned long count)
+{
+       struct proc_dir_entry* dent;
+       char* page;
+       int pos, offs, len;
+
+       if (count <= 0)
+               return 0;
+               
+       dent = inode->u.generic_ip;
+       if ((dent == NULL) || (dent->get_info == NULL))
+               return 0;
+               
+       page = kmalloc(ROUTER_PAGE_SZ, GFP_KERNEL);
+       if (page == NULL)
+               return -ENOBUFS;
+               
+       pos = dent->get_info(page, dent->data, 0, 0, 0);
+       offs = file->f_pos;
+       if (offs < pos)
+       {
+               len = min(pos - offs, count);
+               if(copy_to_user(buf, (page + offs), len))
+                       return -EFAULT;
+               file->f_pos += len;
+       }
+       else
+               len = 0;
+       kfree(page);
+       return len;
+}
+
+/*
+ *     Prepare data for reading 'About' entry.
+ *     Return length of data.
+ */
+
+static int about_get_info(char* buf, char** start, off_t offs, int len, 
+                               int dummy)
+{
+       int cnt = 0;
+
+       cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
+               "version", ROUTER_VERSION, ROUTER_RELEASE);
+       return cnt;
+}
+
+/*
+ *     Prepare data for reading 'Config' entry.
+ *     Return length of data.
+ *     NOT YET IMPLEMENTED
+ */
+
+static int config_get_info(char* buf, char** start, off_t offs, int len, 
+       int dummy)
+{
+       int cnt = 0;
+
+       cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
+               "version", ROUTER_VERSION, ROUTER_RELEASE);
+       return cnt;
+}
+
+/*
+ *     Prepare data for reading 'Status' entry.
+ *     Return length of data.
+ *     NOT YET IMPLEMENTED
+ */
+
+static int status_get_info(char* buf, char** start, off_t offs, int len, 
+                       int dummy)
+{
+       int cnt = 0;
+
+       cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
+               "version", ROUTER_VERSION, ROUTER_RELEASE);
+       return cnt;
+}
+
+/*
+ *     Prepare data for reading <device> entry.
+ *     Return length of data.
+ *
+ *     On entry, the 'start' argument will contain a pointer to WAN device
+ *     data space.
+ */
+
+static int wandev_get_info(char* buf, char** start, off_t offs, int len, 
+                       int dummy)
+{
+       wan_device_t* wandev = (void*)start;
+       int cnt = 0;
+
+       if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
+               return 0;
+       cnt += sprintf(&buf[cnt], "%12s : %s\n", "name", wandev->name);
+       return cnt;
+}
+
+/*
+ *     End
+ */
index c54760c29daeaa37365651ccbff24118458c23eb..4ae7f144752eae13a00921e2d06a933ce3cb3b41 100644 (file)
@@ -421,28 +421,6 @@ static int x25_listen(struct socket *sock, int backlog)
        return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-       if (!sk->dead)
-               wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-       if (!sk->dead) {
-               wake_up_interruptible(sk->sleep);
-               sock_wake_async(sk->socket, 1);
-       }
-}
-
-static void def_callback3(struct sock *sk)
-{
-       if (!sk->dead) {
-               wake_up_interruptible(sk->sleep);
-               sock_wake_async(sk->socket, 2);
-       }
-}
-
 static struct sock *x25_alloc_socket(void)
 {
        struct sock *sk;
@@ -463,16 +441,7 @@ static struct sock *x25_alloc_socket(void)
 
        MOD_INC_USE_COUNT;
 
-       skb_queue_head_init(&sk->receive_queue);
-       skb_queue_head_init(&sk->write_queue);
-       skb_queue_head_init(&sk->back_log);
-
-       init_timer(&sk->timer);
-
-       sk->state_change = def_callback1;
-       sk->data_ready   = def_callback2;
-       sk->write_space  = def_callback3;
-       sk->error_report = def_callback1;
+       sock_init_data(NULL, sk);
 
        skb_queue_head_init(&x25->fragment_queue);
        skb_queue_head_init(&x25->interrupt_in_queue);
@@ -494,30 +463,17 @@ static int x25_create(struct socket *sock, int protocol)
 
        x25 = sk->protinfo.x25;
 
-       sock->ops         = &x25_proto_ops;
-
-       sk->socket        = sock;
-       sk->type          = sock->type;
-       sk->protocol      = protocol;
-       sk->allocation    = GFP_KERNEL;
-       sk->rcvbuf        = SK_RMEM_MAX;
-       sk->sndbuf        = SK_WMEM_MAX;
-       sk->state         = TCP_CLOSE;
-       sk->priority      = SOPRI_NORMAL;
-       sk->mtu           = X25_DEFAULT_PACKET_SIZE;    /* X25_PS128 */
-       sk->zapped        = 1;
-
-       if (sock != NULL) {
-               sock->sk  = sk;
-               sk->sleep = &sock->wait;
-       }
+       sock_init_data(sock, sk);
 
-       x25->t21      = sysctl_x25_call_request_timeout;
-       x25->t22      = sysctl_x25_reset_request_timeout;
-       x25->t23      = sysctl_x25_clear_request_timeout;
-       x25->t2       = sysctl_x25_ack_holdback_timeout;
+       sock->ops    = &x25_proto_ops;
+       sk->protocol = protocol;
+       sk->mtu      = X25_DEFAULT_PACKET_SIZE; /* X25_PS128 */
 
-       x25->state       = X25_STATE_0;
+       x25->t21   = sysctl_x25_call_request_timeout;
+       x25->t22   = sysctl_x25_reset_request_timeout;
+       x25->t23   = sysctl_x25_clear_request_timeout;
+       x25->t2    = sysctl_x25_ack_holdback_timeout;
+       x25->state = X25_STATE_0;
 
        x25->facilities.winsize_in  = X25_DEFAULT_WINDOW_SIZE;
        x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
index 63ac3587a19d2f8192002921ab8fad07daefc913..0c884a31f0b4294945fd65fb7d7aa2bbfc0245e5 100644 (file)
@@ -52,31 +52,14 @@ static void x25_link_set_timer(struct x25_neigh *neigh)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        del_timer(&neigh->timer);
        restore_flags(flags);
 
-       neigh->timer.next     = neigh->timer.prev = NULL;       
        neigh->timer.data     = (unsigned long)neigh;
        neigh->timer.function = &x25_link_timer;
-
        neigh->timer.expires  = jiffies + 100;
-       add_timer(&neigh->timer);
-}
-
-static void x25_link_reset_timer(struct x25_neigh *neigh)
-{
-       unsigned long flags;
 
-       save_flags(flags);
-       cli();
-       del_timer(&neigh->timer);
-       restore_flags(flags);
-
-       neigh->timer.data     = (unsigned long)neigh;
-       neigh->timer.function = &x25_link_timer;
-       neigh->timer.expires  = jiffies + 100;
        add_timer(&neigh->timer);
 }
 
@@ -91,7 +74,7 @@ static void x25_link_timer(unsigned long param)
        struct x25_neigh *neigh = (struct x25_neigh *)param;
 
        if (neigh->t20timer == 0 || --neigh->t20timer > 0) {
-               x25_link_reset_timer(neigh);
+               x25_link_set_timer(neigh);
                return;
        }
 
index 26266327178dffdb360a80bd3309ed2fa962efe8..fc6bf863f29efb7459f4f274c8a30f7a3c6e6ba9 100644 (file)
 static void x25_timer(unsigned long);
 
 /*
- *     Linux set/reset timer routines
+ *     Linux set timer
  */
 void x25_set_timer(struct sock *sk)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
-
+       save_flags(flags); cli();
        del_timer(&sk->timer);
-
-       restore_flags(flags);
-
-       sk->timer.next     = sk->timer.prev = NULL;     
-       sk->timer.data     = (unsigned long)sk;
-       sk->timer.function = &x25_timer;
-       sk->timer.expires  = jiffies + 100;
-
-       add_timer(&sk->timer);
-}
-
-static void x25_reset_timer(struct sock *sk)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-
-       del_timer(&sk->timer);
-
        restore_flags(flags);
 
        sk->timer.data     = (unsigned long)sk;
@@ -125,7 +103,7 @@ static void x25_timer(unsigned long param)
        }
 
        if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) {
-               x25_reset_timer(sk);
+               x25_set_timer(sk);
                return;
        }