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
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,
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
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)
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
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
--- /dev/null
+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);
+
'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
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
- 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
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
--- /dev/null
+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.
+
+
--- /dev/null
+------------------------------------------------------------------------------
+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 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
--- /dev/null
+ 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
--- /dev/null
+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.
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.
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
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 24
+SUBLEVEL = 25
ARCH = i386
* within the United States, $35 abroad.
*/
#include <linux/config.h>
+#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#else /* CONFIG_PCI */
-#include <linux/kernel.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/malloc.h>
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);
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
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
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];
* 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
*
*/
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 */
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;
#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);
return_to_32bit(regs, VM86_INTx + (intno << 8));
}
do_int(regs, intno, ssp, sp);
- goto out;
+ return;
}
/* iret */
default:
return_to_32bit(regs, VM86_UNKNOWN);
}
-out:
- unlock_kernel();
}
/* ---------------- vm86 special IRQ passing stuff ----------------- */
* 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
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)
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;
}
+
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
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;
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/poll.h>
#include <linux/types.h>
#include <linux/stddef.h>
* 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
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)
struct timer_list watchdog_ticktock;
static int timer_alive = 0;
-static int in_use = 0;
/*
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
del_timer(&watchdog_ticktock);
watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
add_timer(&watchdog_ticktock);
- timer_alive++;
+ timer_alive=1;
return 0;
}
#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)
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
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 */
dev->trans_start = jiffies;
}
- if (skb == NULL)
- {
- dev_tint(dev);
- return 0;
- }
-
save_flags(flags);
/*
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.
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;
}
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
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);
*
******************************************************/
-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;
/*
* 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
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;
/* 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;
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);
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;
return 0;
}
-\f
-
-static int
-el16_open(struct device *dev)
+static int el16_open(struct device *dev)
{
irq2dev_map[dev->irq] = 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;
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);
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;
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)
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;
/* 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;
}
/* 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;
}
-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;
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;
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;
#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];
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
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;
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));
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);
}
-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;
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 */
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);}
* 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;
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. */
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
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;
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);
send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
+ ei_local->stat.tx_bytes+=send_length;
+
#ifdef EI_PINGPONG
/*
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++;
}
-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;
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. */
DEFXX_OPTS =
ELP_OPTS =
TULIP_OPTS =
+CS89x0_OPTS =
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
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
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
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
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
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
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:
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 $<
-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
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!
--- /dev/null
+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>
+
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
--- /dev/null
+------------------------------------------------------------------------------
+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 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
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;
#ifdef CONFIG_AT1500
&& at1500_probe(dev)
#endif
+#ifdef CONFIG_CS89x0
+ && cs89x0_probe(dev)
+#endif
#ifdef CONFIG_AT1700
&& at1700_probe(dev)
#endif
# 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
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;
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;
struct i596_cmd *cmd_head;
int cmd_backlog;
unsigned long last_cmd;
- struct enet_statistics stats;
+ struct net_device_stats stats;
};
char init_setup[] = {
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);
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;
/* 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) */
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);
* 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;
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;
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
}
-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;
/* 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. */
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
/* 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;
/* 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 */
};
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 };
/* 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;
}
/* 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 */
};
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);
/* 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;
}
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;
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 );
}
-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;
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
/* 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;
#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. */
};
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
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. */
/* 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. */
}
/*
* 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. */
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;
/*
* 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;
--- /dev/null
+/* 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:
+ *
--- /dev/null
+/* 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
+
-/* 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>
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 */
#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 */
** 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 */
char id_block_crc;
char reserved2;
char version;
- char num_adapters;
+ char num_controllers;
char ieee_addr[6];
char info[100];
short chksum;
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;
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 */
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 */
};
/*
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:
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);
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);
/*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);
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);
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);
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...
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
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;
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
*/
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) {
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++) {
}
#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;
#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;
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;
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;
}
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) {
/*
** 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));
printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
}
-
+
MOD_INC_USE_COUNT;
-
+
return status;
}
*/
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;
}
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);
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 */
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
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
} 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 */
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 */
}
}
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
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",
dev->interrupt = UNMASK_INTERRUPTS;
ENABLE_IRQs;
-
+
return;
}
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);
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++;
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;
/* 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);
lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
barrier();
}
-
+
/*
** Update entry information
*/
lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
}
-
+
return 0;
}
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. */
lp->tx_skb[entry] = NULL;
}
}
-
+
/* Update all the pointers */
lp->tx_old = (++lp->tx_old) % lp->txRingSize;
}
dev->tbusy = 0; /* Clear TX busy flag */
if (dev->interrupt) mark_bh(NET_BH);
}
-
+
return 0;
}
{
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);
}
lp->linkOK = 0;
enable_ast(dev, next_tick);
-
+
return 0;
}
}
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;
}
outl(omr, DE4X5_OMR);
-
+
return 0;
}
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;
/* 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;
}
(*(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));
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);
barrier();
lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
barrier();
-
+
return;
}
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;
}
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;
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;
}
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;
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) {
}
}
}
-
+
return;
}
{
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);
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);
/* 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;
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;
}
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) {
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;
}
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
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
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);
}
u_long iobase = dev->base_addr;
int next_tick = DE4X5_AUTOSENSE_MS;
s32 imr;
-
+
switch (lp->media) {
case INIT:
DISABLE_IRQs;
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);
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;
lp->local_state++;
next_tick = 500;
break;
-
+
case 1:
if (!lp->tx_enable) {
linkBad = fn(dev, timeout);
}
break;
}
-
+
return next_tick;
}
switch (lp->local_state) {
case 1:
- if (lp->linkOK && !LOST_MEDIA) {
+ if (lp->linkOK) {
lp->media = prev_state;
} else {
lp->local_state++;
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;
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;
next_tick = dc21041_autoconf(dev);
}
break;
-
+
case ANS:
if (!lp->tx_enable) {
irqs = STS_LNP;
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;
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;
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;
next_tick = dc21041_autoconf(dev);
}
break;
-
+
case 1:
if (!lp->tx_enable) {
if ((sts = ping_media(dev, 3000)) < 0) {
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);
lp->tx_enable = NO;
break;
}
-
+
return next_tick;
}
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:
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;
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;
}
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 :
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);
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);
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);
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)
{
cli();
de4x5_rx(dev);
de4x5_setup_intr(dev);
- lp->lostMedia = 0;
lp->tx_enable = YES;
dev->tbusy = 0;
sti();
return;
}
+/*
+** General PHY reset function.
+*/
static int
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;
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);
/* 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;
}
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) {
} else {
lp->timeout = -1;
}
-
+
return sisr;
}
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));
} else {
lp->timeout = -1;
}
-
+
return gep;
}
{
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;
}
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;
}
{
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);
{
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);
{
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;
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;
}
lp->timeout = -1;
}
-
+
return sisr;
}
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
}
lp->cache.save_cnt--;
START_DE4X5;
}
-
+
return;
}
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
- s32 gep;
switch(flag) {
case DE4X5_SAVE_STATE:
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;
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;
}
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;
outl(sts, DE4X5_STS);
ENABLE_IRQs;
}
-
+
return;
}
{
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);
}
/*
-** 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;
}
de4x5_us_delay(u32 usec)
{
udelay(usec);
-
+
return;
}
de4x5_ms_delay(u32 msec)
{
u_int i;
-
+
for (i=0; i<msec; i++) {
de4x5_us_delay(1000);
}
-
+
return;
}
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);
break;
}
}
-
+
return status; /* return the device name string */
}
{
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++) {
} 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;
}
{
int i;
struct bus_type *lp = &bus;
-
+
if (lp->chipset == DC21040) {
outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
} else { /* Read new srom */
}
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)
{
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);
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);
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;
}
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
*/
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);
}
sendto_srom(command, addr);
sendto_srom(command | DT_CLK, addr);
sendto_srom(command, addr);
-
+
return;
}
srom_latch(command, addr);
srom_latch(command, addr);
srom_latch((command & 0x0000ff00) | DT_CS, addr);
-
+
return;
}
{
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;
}
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;
}
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;
}
*/
{
outl(command, addr);
udelay(1);
-
+
return;
}
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
*/
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 */
}
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;
}
{
int i;
s32 tmp = 0;
-
+
for (i=0; i<16; i++) {
tmp <<= 1;
tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
}
-
+
return tmp;
}
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;
}
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;
}
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;
}
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;
}
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;
}
udelay(1);
outl(command | MII_MDC, ioaddr);
udelay(1);
-
+
return ((inl(ioaddr) >> 19) & 1);
}
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? */
(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;
}
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 */
if (i & 0x01) pa += 4;
}
}
-
+
return pa; /* Points to the next entry */
}
enable_ast(struct device *dev, u32 time_out)
{
timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
-
+
return;
}
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 */
{
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;
}
{
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++) {
}
}
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;
}
{
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));
printk("MII 20: %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
}
}
-
+
return;
}
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 {
}
lp->c_media = lp->media;
}
-
+
return;
}
{
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++) {
{
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],
(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++) {
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;
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);
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()) {
} else {
status = -EPERM;
}
-
+
break;
case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */
if (suser()) {
} 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()) {
} else {
status = -EPERM;
}
-
+
break;
case DE4X5_CLR_MCA: /* Clear all multicast addresses */
if (suser()) {
} else {
status = -EPERM;
}
-
+
break;
case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
if (suser()) {
} 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()) {
} 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()) {
} else {
status = -EPERM;
}
-
+
break;
case DE4X5_GET_REG: /* Get the DE4X5 Registers */
j = 0;
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;
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;
}
}
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;
}
}
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;
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;
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;
}
** 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 */
#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);\
}\
}
#define DE600_DEBUG 0
#define PRINTK(x) /**/
#endif
-unsigned int de600_debug = DE600_DEBUG;
-MODULE_PARM(de600_debug, "i");
\f
#include <linux/module.h>
#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;
/**************************************************
/* 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. */
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
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;
}
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);
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. */
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;
/* Constant definitions for the DE-620 registers, commands and bits */
#include "de620.h"
-#define netstats enet_statistics
typedef unsigned char byte;
/*******************************************************
/* 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 *);
* 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);
}
/*********************************************
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 */
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;
}
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;
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 */
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++;
}
}
int
de620_probe(struct device *dev)
{
- static struct netstats de620_netstats;
+ static struct net_device_stats de620_netstats;
int i;
byte checkbyte = 0xa5;
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;
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);
* None
*/
-struct enet_statistics *dfx_ctl_get_stats(
+struct net_device_stats *dfx_ctl_get_stats(
struct device *dev
)
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 */
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 */
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
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;
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);
/*
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;
*/
char devname[8]; /* "ethN" string */
struct device *next_dev;
- struct enet_statistics stats;
+ struct net_device_stats stats;
/*
* DGRS specific data
* 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;
dev->interrupt = 0;
dev->start = 1;
- #ifdef MODULE
- MOD_INC_USE_COUNT;
- #endif
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
return (0);
}
/*
* 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);
}
/*
* 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;
/*
* 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;
/*
* 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;
}
}
*
* 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;
* 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>
*
* 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
#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];
/* 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);
}
/*
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
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 */
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)
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
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
}
#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
/* 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 */
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);
/* 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;
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 */
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);
* 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;
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
---------------- */
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;
}
-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;
#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 */
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 */
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";
#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, ð16i_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, ð16i_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 = ð16i_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 = ð16i_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
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;
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;
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);
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;
/* 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. */
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
/* 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;
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))
/* --------------------------------------------------------------------- */
-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;
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;
};
/*
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);
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
* 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;
#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
* 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
#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"
/* 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
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
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
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
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
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;
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
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;
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,
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);
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
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;
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;
};
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
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;
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;
/*
* 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;
*/
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
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)
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;
/*
--- /dev/null
+/*** 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 = <pc_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(<pc_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(<pc_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, <_probe_handler, 0, "ltpc_probe",NULL);
+ probe4 = request_irq( 4, <_probe_handler, 0, "ltpc_probe",NULL);
+ probe9 = request_irq( 9, <_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 = <dmabuf[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(<pc_timer);
+ ltpc_timer.function=ltpc_poll;
+ ltpc_timer.data = (unsigned long) dev;
+
+ if (irq) {
+ irq2dev_map[irq] = dev;
+ (void) request_irq( irq, <pc_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(<pc_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(<pc_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(<pc_timer)
+ while(del_timer(<pc_timer) && (timeout > jiffies))
+ {
+ add_timer(<pc_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 */
--- /dev/null
+/*** 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;
+
}
-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;
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;
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 */
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. */
#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
#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))
#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(); \
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 *);
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;
};
/**********************************************
*/
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;
}
/**********************************************
*/
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 */
}
/**********************************************
*/
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;
}
/******************************************************************
*/
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));
}
/**********************************************
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;
}
/**********************************************
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;
}
/******************************************************
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;
}
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;
}
/*******************************************************
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");
}
/**********************************************************
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);
}
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);
}
/***********************************************************
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!!) */
}
/******************************************************
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;
}
/********************************************************
*/
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");
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 */
*/
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
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);
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 */
*/
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 */
}
/*
*/
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;
+ }
}
/*
*/
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;
}
/*
#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;
}
/*
*/
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 */
}
/*
*/
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 ? */
+ }
}
/*
*/
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;
}
/*
*/
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 */
}
/*
*/
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);
}
*/
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);
}
/*
*/
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 */
}
/*
*/
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;
}
/*
*/
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);
}
/*
*/
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;
+ }
}
/*
*/
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)
#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;
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 */
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);
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)
/* 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
#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
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
};
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;
\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;
/* 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;
};
/* 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;
}
}
-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)
{
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;
/* 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;
}
/* 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);
/* 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;
}
/* 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);
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();
}
/* 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;
}
\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;
}
\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;
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;
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;
}
/* 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;
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;
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;
}
};
-int
-init_module(void)
+int init_module(void)
{
int no_parameters=1;
int devices=0;
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
int i;
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
* 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;
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);
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;
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)
*/
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 */
}
/* 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);
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;
}
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 */
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++;
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
*/
#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' */
#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
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";
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);
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;
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;
+ }
}
/****************************************************
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 */
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);
}
/************************************************
*
************************************************/
-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);
}
/***********************************************
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);
}
/**************************
/* 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
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
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 */
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
/* 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. */
};
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 ;->. */
/* 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;
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;
}
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;
};
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 */
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);
* 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;
/* 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. */
};
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.
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. */
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;
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.
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;
}
* 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;
/* 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",
* 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;
}
#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);
}
/* 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);
}
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. :-) */
}
* 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;
}
-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;
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) {
/* 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 */
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
. 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
. 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;
-#error "Doesn't run with 2.1.x"
-
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
* Junior University. All Rights Reserved.
*/
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++ = '*';
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;
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;
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;
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;
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;
/* 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));
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];
/* 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;
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. */
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;
}
}
- 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;
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;
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 */
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;
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 */
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");
}
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;
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);
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;
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;
}
}
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;
}
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;
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;
/* 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));
/* 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];
/* 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);
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;
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;
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;
/* 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))
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 */
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? */
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 =
#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 */
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);
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
} 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 |
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;*/
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
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 */
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);
}
/*
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 */
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 */
/* 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;
+++ /dev/null
-/* $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:
- */
#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;
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);
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);
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
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;
/* 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;
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
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
};
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;
* 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>
#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 */
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 *);
* 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,
#endif /* RELOAD_FIRMWARE */
-unsigned short risc_code_length01 = 0x283a;
+static const unsigned short risc_code_length01 = 0x283a;
{"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 */
#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>
* 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
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);
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 = {
(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",
/*
* 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,
#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)
: "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 */
#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 */
#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 */
};
/*
- * 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 */
--- /dev/null
+#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
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
* 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);
/*
#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
--- /dev/null
+/*****************************************************************************
+* 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 */
+
--- /dev/null
+/*****************************************************************************
+* 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 */
--- /dev/null
+/*****************************************************************************
+* 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 */
--- /dev/null
+/*****************************************************************************
+* 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 */
--- /dev/null
+/*****************************************************************************
+* 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 */
+
(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;
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
};
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 */
* 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);
--- /dev/null
+/*****************************************************************************
+* 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 */
+
--- /dev/null
+/*****************************************************************************
+* 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 */
#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 */
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 *);
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 *);
#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;
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;
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];
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 *);
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 *);
#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
unsigned int number;
int restarted;
struct sk_buff_head queue;
- unsigned short t0, t0timer;
+ unsigned short t0timer, ftimer;
struct timer_list timer;
};
struct rose_node *next;
rose_address address;
unsigned short mask;
- unsigned char which;
unsigned char count;
struct rose_neigh *neighbour[3];
};
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 *);
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 *);
}
if (checksetup(line))
continue;
+
/*
* Then check if it's an environment variable or
* an option.
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;
* 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;
}
/*
* 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) {
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)
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;
}
}
ret = -ESRCH;
- }
out:
- unlock_kernel();
+ unlock_kernel();
+ }
return ret;
}
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(¤t->fs->umask, mask & S_IRWXUGO);
+ return mask;
}
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
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
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
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
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
* 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);
/*
* 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
#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>
extern inline void atalk_destroy_socket(struct sock *sk)
{
sklist_destroy_socket(&atalk_socket_list,sk);
+ MOD_DEC_USE_COUNT;
}
/*
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)
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
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)
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
{
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");
}
*/
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;
* 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;
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;
}
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;
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;
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 */
ax25_set_timer(ax25);
- ax25_output(ax25, skb);
+ ax25_output(ax25, fragment, skb);
return 1; /* We had to create it */
}
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:
if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
return err;
- put_user(val, (int *) optval);
+ put_user(val, (int *)optval);
return 0;
}
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;
ax25_fillin_cb(ax25, dev);
- sk->type = osk->type;
- sk->socket = osk->socket;
-
switch (osk->type) {
case SOCK_DGRAM:
break;
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;
} 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++;
}
}
return 0;
}
#endif
- skb->arp = 1;
- skb->dev = dev_out;
+ skb->dev = dev_out;
skb->priority = SOPRI_NORMAL;
+
ax25_queue_xmit(skb);
return 0;
* 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);
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)
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");
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 */
return len;
}
-
}
static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags,
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);
}
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;
}
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);
if (skb == NULL) return 0;
ax25->idletimer = ax25->idle;
-
+
pid = *skb->data;
#ifdef CONFIG_INET
case AX25_UA:
if (pf || dama) {
if (dama) ax25_dama_on(ax25); /* bke */
-
ax25_calculate_rtt(ax25);
ax25->t1timer = 0;
ax25->t3timer = ax25->t3;
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 */
}
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);
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;
ax25->va = 0;
ax25->vr = 0;
ax25->dama_slave = dama;
+ ax25_requeue_frames(ax25);
break;
case AX25_DISC:
}
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);
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;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
+ ax25->dama_slave = dama;
+ ax25_requeue_frames(ax25);
break;
case AX25_DISC:
}
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)) {
}
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);
}
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) {
#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;
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;
restore_flags(flags);
- skbn->arp = 1;
-
len = (mtu > skb->len) ? skb->len : mtu;
if (ka9qfrag == 1) {
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;
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);
}
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);
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)
{
}
}
-/* 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.
*/
/*
* 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;
{
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;
/*
* Digipeated address processing
*/
-
+
/*
* Given an AX.25 address pull of to, from, digi list, command/response and the start of data
/* 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;
/*
* 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);
*
* 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;
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);
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);
}
ax25->sk->dead = 1;
}
- ax25_reset_timer(ax25);
+ ax25_set_timer(ax25);
return;
}
/* 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;
}
* 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:
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;
#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
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;
#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];
* 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];
p=&((*p)->next);
}
-
/*
* We need to use a memory barrier to make sure that this
* works correctly even in SMP with weakly ordered writes.
* 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;
* And release the sleep lock
*/
- firewall_lock=0;
+ up(&firewall_sem);
return 0;
}
* Don't allow two people to adjust at once.
*/
- while(firewall_lock)
- schedule();
- firewall_lock=1;
+ down(&firewall_sem);
nl=&firewall_chain[pf];
{
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;
}
* 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
*/
/*
* 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)
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;
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;
}
err = copy_from_user(kdata, iov->iov_base, copy);
if (err)
{
- return err;
+ return -EFAULT;
}
len-=copy;
kdata+=copy;
err = copy_from_user(kdata, base, copy);
if (err)
{
- return err;
+ return -EFAULT;
}
len-=copy;
kdata+=copy;
err = copy_from_user(kdata, iov->iov_base, copy);
if (err)
{
- return err;
+ return -EFAULT;
}
len-=copy;
kdata+=copy;
#
# 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
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
/*
* 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
*/
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
-
+
/*
* Initialise AF_INET alias type (register net_alias_type)
*/
}
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;
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;
}
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;
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();
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();
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();
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();
}
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);
#endif
#ifdef CONFIG_IP_MASQUERADE
+ }
+
skip_call_fw_firewall:
/*
* If this fragment needs masquerading, make it so...
}
#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)
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);
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);
int tmp;
struct sk_buff *skb;
+ if (err)
+ return (err);
/*
* Stop on errors
*/
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;
sk->err = 0;
+ if (err)
+ return (err);
+
return copied;
}
msg->msg_name);
}
if(addr_len)
- *addr_len= tp->af_specific->sockaddr_len;
+ *addr_len = tp->af_specific->sockaddr_len;
/*
* Read urgent data
*/
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);
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;
}
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;
}
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;
}
}
* 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;
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);
}
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);
}
default:
/* CHECKSUM_UNNECESSARY */
}
+
+ tcp_statistics.TcpInSegs++;
#ifdef CONFIG_IP_TRANSPARENT_PROXY
if (IPCB(skb)->redirport)
/* <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),
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.
*/
}
sock_init_data(sock,sk);
+ sk->zapped=0;
sk->family = AF_INET6;
sk->protocol = protocol;
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);
/* CHECKSUM_UNNECESSARY */
}
+ tcp_statistics.TcpInSegs++;
+
sk = inet6_get_sock(&tcpv6_prot, daddr, saddr,
th->dest, th->source);
*/
static void lapb_free_cb(lapb_cb *lapb)
{
- del_timer(&lapb->timer);
-
kfree_s(lapb, sizeof(lapb_cb));
MOD_DEC_USE_COUNT;
lapb_insert_cb(lapb);
+ lapb->t1timer = lapb->t1;
+
+ lapb_set_timer(lapb);
+
return LAPB_OK;
}
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
+ del_timer(&lapb->timer);
+
lapb_clear_queues(lapb);
lapb_remove_cb(lapb);
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;
lapb->state = LAPB_STATE_1;
- lapb_set_timer(lapb);
-
return LAPB_OK;
}
#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:
#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);
}
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);
}
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);
}
lapb->vs = 0;
lapb->vr = 0;
lapb->va = 0;
+ lapb_requeue_frames(lapb);
}
break;
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);
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;
#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;
lapb->vs = 0;
lapb->vr = 0;
lapb->va = 0;
+ lapb_requeue_frames(lapb);
}
break;
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);
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;
#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;
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);
}
}
if (lapb->t1timer == 0 || --lapb->t1timer > 0) {
- lapb_reset_timer(lapb);
+ lapb_set_timer(lapb);
return;
}
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
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
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
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;
/*
* Socket removal during an interrupt is now safe.
*/
-
static void nr_remove_socket(struct sock *sk)
{
struct sock *s;
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;
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)
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;
}
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:
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;
}
val = sk->protinfo.nr->hdrincl;
break;
- case NETROM_PACLEN:
- val = sk->protinfo.nr->paclen;
- break;
-
default:
return -ENOPROTOOPT;
}
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;
}
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;
}
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);
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;
/* 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;
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);
/*
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)
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,
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;
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");
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;
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;
};
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);
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;
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;
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;
{
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);
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);
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);
*dptr++ = sysctl_netrom_network_ttl_initialiser;
- skb->arp = 1;
-
if (!nr_route_frame(skb, NULL)) {
kfree_skb(skb, FREE_WRITE);
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;
}
/*
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);
{
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;
}
}
}
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) {
if (nr_neigh->count == 0 && !nr_neigh->locked)
nr_remove_neigh(nr_neigh);
-
+
nr_node->count--;
if (nr_node->count == 0) {
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);
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,
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;
*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
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);
}
}
if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
- nr_reset_timer(sk);
+ nr_set_timer(sk);
return;
}
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);
}
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};
{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},
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);
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);
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;
memset(rose, 0x00, sizeof(*rose));
sk->protinfo.rose = rose;
- rose->sk = sk;
+ rose->sk = sk;
return sk;
}
if (event != NETDEV_DOWN)
return NOTIFY_DONE;
-
+
rose_kill_by_device(dev);
rose_rt_device_down(dev);
rose_link_device_down(dev);
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;
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;
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;
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;
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;
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;
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);
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))
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS;
-
+
cli(); /* To avoid races on the sleep */
/*
return 0;
}
-
+
static int rose_socketpair(struct socket *sock1, struct socket *sock2)
{
return -EOPNOTSUPP;
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);
/*
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
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;
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;
};
/*
* 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
*
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);
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);
* 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);
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);
}
{
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);
}
/*
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);
}
/*
*dptr++ = 0x00;
*dptr++ = 0;
- skb->sk = NULL;
-
if (!rose_send_frame(skb, neigh))
kfree_skb(skb, FREE_WRITE);
}
*dptr++ = 0x00;
*dptr++ = ROSE_RESTART_CONFIRMATION;
- skb->sk = NULL;
-
if (!rose_send_frame(skb, neigh))
kfree_skb(skb, FREE_WRITE);
}
*dptr++ = ROSE_DIAGNOSTIC;
*dptr++ = diag;
- skb->sk = NULL;
-
if (!rose_send_frame(skb, neigh))
kfree_skb(skb, FREE_WRITE);
}
*dptr++ = cause;
*dptr++ = 0x00;
- skb->sk = NULL;
-
if (!rose_send_frame(skb, neigh))
kfree_skb(skb, FREE_WRITE);
}
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);
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);
}
}
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);
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);
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 &&
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;
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) {
* 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;
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;
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++;
}
if (rose_neigh->count == 0)
rose_remove_neigh(rose_neigh);
-
+
rose_node->count--;
if (rose_node->count == 0) {
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)
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;
}
/*
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++;
}
/*
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;
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)
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.
/*
* 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);
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;
}
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);
cli();
- len += sprintf(buffer, "address mask w 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++)
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;
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);
}
}
if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) {
- rose_reset_timer(sk);
+ rose_set_timer(sk);
return;
}
#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;
{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}
};
* 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>
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;
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.
*/
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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)
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)
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)
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;
* 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.
init_netlink();
#endif
+ /*
+ * Wan router layer.
+ */
+
+#ifdef CONFIG_WAN_ROUTER
+ wanrouter_init();
+#endif
+
/*
* Attach the firewall module if configured
*/
--- /dev/null
+#
+# 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 .
--- /dev/null
+/*****************************************************************************
+* 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
+ */
--- /dev/null
+/*****************************************************************************
+* 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
+ */
+
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;
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);
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;
{
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);
}
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;
}
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;
}
if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) {
- x25_reset_timer(sk);
+ x25_set_timer(sk);
return;
}