diff -u --recursive --new-file v2.1.24/linux/CREDITS linux/CREDITS --- v2.1.24/linux/CREDITS Tue Jan 28 18:49:43 1997 +++ linux/CREDITS Sun Feb 2 15:18:29 1997 @@ -757,6 +757,16 @@ 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 diff -u --recursive --new-file v2.1.24/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.24/linux/Documentation/Configure.help Tue Jan 28 18:49:45 1997 +++ linux/Documentation/Configure.help Sun Feb 2 15:18:29 1997 @@ -841,41 +841,6 @@ on sunsite.unc.edu:/pub/Linux/docs/HOWTO). Short answer: say Y. -IP: forwarding/gatewaying -CONFIG_IP_FORWARD - People who want to use their Linux box as the router for a local - network (i.e. the computer responsible for distributing Internet - traffic to and from the machines in the local network and the - subnetworks) should say Y here (thereby enlarging their kernel by - about 5 kB). Note that in this case, you possibly have two ethernet - devices in your computer: one for the "outside world" and one for - your local net. The kernel is not able to recognize both at boot - time without help; for details read the - Multiple-Ethernet-mini-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your box is - connected to two networks, it may still make sense to say N here, - namely if you want to turn your box into a firewall protecting a - local network from the internet. The Firewall-HOWTO tells you how to - do this. If your setup is more complex, say you are connected to - three networks and you want to act as a firewall between two of them - and route traffic for the others, you need to say Y here and Y to - "IP firewalling" below. If you intend to use IP masquerading (i.e. IP - traffic from one of the local computers and destined for an outside - host is changed by your box so that it appears to come from you), - you'll have to say Y here and also to IP firewalling and IP - masquerading below. You should also say Y here if you want to - configure your box as a SLIP (the protocol for sending internet - traffic over telephone lines) or PPP (a better SLIP) server for - other people to dial into and your box is connected to a local - network at the same time. You would then most likely use proxy-ARP - (Address Resolution Protocol), explained in the Proxy-Arp mini howto - on sunsite in /pub/Linux/docs/HOWTO/mini. You also need to say Y - here if you want to run mrouted in order to do multicast routing as - used on the MBONE (a high bandwidth network on top of the internet - which carries audio and video broadcasts) for example. In this case, - say Y to "IP: multicasting" and "IP: multicast routing" as well. If - unsure, say N. - IP: multicasting CONFIG_IP_MULTICAST This is code for addressing several networked computers at once, @@ -1249,6 +1214,23 @@ all you will need to do is download and install the localtalk driver. +IP-over-DDP support +CONFIG_IPDDP + This allows IP networking for users who only have Appletalk + networking available. It doesn't work yet in 2.1.xx, so you + should say N. + +LocalTalk PC card support +CONFIG_LTPC + This allows you to use the AppleTalk PC card to connect to LocalTalk + networks. The card is also known as the Farallon PhoneNet PC card. + If you are in doubt, this card is the one with the 65C02 chip on it. + You also need version 1.3.3 or later of the netatalk package. + This driver is experimental, which means that it may not work. + In particular the module support is not yet working for the 2.1.xx + kernels, so choose Y or N, but not M for now. + See README.ltpc in the drivers/net directory. + Amateur Radio AX.25 Level 2 CONFIG_AX25 This is the protocol used for computer communication over amateur @@ -2156,14 +2138,6 @@ the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called strip.o. -WIC (Radio IP bridge) -CONFIG_WIC - Support for the WIC parallel port radio bridge. You'll probably want - to say N. If you want to compile this driver as a module though ( = - code which can be inserted in and removed from the running kernel - whenever you want), say M here and read Documentation/modules.txt. - The module will be called wic.o. - CONFIG_LAPBETHER LAPB over Ethernet driver This is a driver for a pseudo device (usually called /dev/lapb0) @@ -2383,6 +2357,75 @@ 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 @@ -2656,6 +2699,20 @@ 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. + +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. diff -u --recursive --new-file v2.1.24/linux/Documentation/filesystems/vfs.txt linux/Documentation/filesystems/vfs.txt --- v2.1.24/linux/Documentation/filesystems/vfs.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/filesystems/vfs.txt Sun Feb 2 15:18:29 1997 @@ -0,0 +1,173 @@ +A Brief Overview of the Virtual File System +=========================================== + by Benjamin LaHaise (blah@dot.superaje.com) + +Noone else seems to be writing this, so here's a quick description of what +I've learned while writing lofs... + +The VFS relatively simple, but it is nice not to have to browse through +pages of code to determine what is expected when writing a filesystem. +Hopefully this helps anyone attempting such a feat, as well as clearing up +a few important points/dependancies. + + +register_filesystem (struct file_system_type *fstype) +===================================================== + +All filesystems are created equal... or at least they start out that way. +A filesystem, be it in module form, or linked into the kernel, needs to add +itself to the table of filesystems by calling register_filesystem with an +initialized file_system_type structure. Any further functions of the +filesystem are accessed through the following function tables... + + +struct file_system_type +======================= + + struct super_block *(*read_super) (struct super_block *sb, void *options, int silent); + + This is the entry point of all filesystems. If the filesystem succeeds + in mounting itself, sb should be returned, otherwise NULL. options is + a pointer to a maximum of PAGE_SIZE-1 bytes of options, typically a zero + terminated string passed from mount. This page is freed after read_super + returns, so do not use any pointers into it. + + This routine _must_ set the s_op member of sb to point to a valid + super_operations structure. + + const char *name; + + Name points to a string that the system will know the filesystem by. + + int requires_dev; + + Set this flag to 1 if the filesystem requires a block device to be mounted + on. + + struct file_system_type * next; + + This field points to the next file_system_type that is present in the system, + and should be initialized to NULL. + +struct super_operations +======================= + +The super_operations structure is found through the s_op member of the +super_block structure. + + void (*read_inode) (struct inode *inode); + [optional - doesn't quite make sense] + read_inode is called by the VFS when iget is called requesting an inode + not already present in the inode table. i_ino is set to the number of the + inode requested. + + The i_op member of inode should be set to a valid inode_operations + structure. Typically filesystems have separate inode_operations for + directories, files and symlinks. i_op can be NULL. + + int (*notify_change) (struct inode *, struct iattr *); + [optional] + void (*write_inode) (struct inode *); + [optional] + + int (*put_inode) (struct inode *inode); + [optional] + put_inode is called by the VFS when the last instance of inode is released + with a call to iput. The only special consideration that should be made + is that iget may reuse inode without calling read_inode unless clear_inode + is called. put_inode MUST return 1 if it called clear_inode on the inode, + otherwise zero. + + void (*put_super) (struct super_block *); + [optional] + void (*write_super) (struct super_block *); + [optional] + void (*statfs) (struct super_block *, struct statfs *, int); + [optional] + int (*remount_fs) (struct super_block *, int *, char *); + [optional] + + +struct inode_operations +======================= + + struct file_operations * default_file_ops; + [mandatory] + All inode_operations structures must have default_file_ops pointing to + a valid file_operations structure. + + int (*create) (struct inode *,const char *,int,int,struct inode **); + [optional] + + int (*lookup) (struct inode *dir, const char *name, int len, struct inode **result); + [optional] + lookup is called when the VFS wishes to have the filesystem resolve a name + into an inode. Dir is a directory on the filesystem that [hopefully] contains + the zero terminated string name (length len). A return value of zero indicates + that there is a valid inode stored in *result. + +*** Note: lofs assumes that any filesystem returns an inode within the filesystem + for all directory inodes. Therefore, __iget(sb,ino,0) should be used to fetch + the inode in a filesystem's lookup routine. + + int (*link) (struct inode *,struct inode *,const char *,int); + [optional] + int (*unlink) (struct inode *,const char *,int); + [optional] + int (*symlink) (struct inode *,const char *,int,const char *); + [optional] + int (*mkdir) (struct inode *,const char *,int,int); + [optional] + int (*rmdir) (struct inode *,const char *,int); + [optional] + int (*mknod) (struct inode *,const char *,int,int,int); + [optional] + int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int); + [optional] + + int (*readlink) (struct inode *inode, char *buf, int len); + [optional] + readlink is called by the VFS to read the contents of a symbolic link. + inode is an inode that meets the S_ISLNK test, and buf points to a buffer + of len bytes. + + int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **); + [optional] + The follow_link function is only nescessary if a filesystem uses a really + twisted form of symbolic links - namely if the symbolic link comes from a + foriegn filesystem that makes no sense.... + I threw this one out - too much redundant code! + + int (*readpage) (struct inode *, struct page *); [optional] + int (*writepage) (struct inode *, struct page *); [mandatory with readpage] + + In order for files to be mmap'd, readpage and writepage are required. + A filesystem can use generic_readpage/writepage if it supports the bmap + function. Otherwise, a custom version must be written. + + int (*bmap) (struct inode *,int); + [optional] + void (*truncate) (struct inode *); + [optional] + int (*permission) (struct inode *, int); + [optional] + int (*smap) (struct inode *,int); + [optional] + +struct file_operations +====================== + + int (*lseek) (struct inode *, struct file *, off_t, int); + int (*read) (struct inode *, struct file *, char *, int); + int (*write) (struct inode *, struct file *, const char *, int); + int (*readdir) (struct inode *, struct file *, void *, filldir_t); + unsigned int (*poll) (struct file *, poll_table *); + int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); + int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); + int (*open) (struct inode *, struct file *); + void (*release) (struct inode *, struct file *); + int (*fsync) (struct inode *, struct file *); + int (*fasync) (struct inode *, struct file *, int); + int (*check_media_change) (kdev_t dev); + int (*revalidate) (kdev_t dev); + diff -u --recursive --new-file v2.1.24/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.1.24/linux/Documentation/ioctl-number.txt Wed Dec 18 15:58:34 1996 +++ linux/Documentation/ioctl-number.txt Sun Feb 2 15:18:29 1997 @@ -81,6 +81,7 @@ '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 diff -u --recursive --new-file v2.1.24/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt --- v2.1.24/linux/Documentation/magic-number.txt Thu May 16 16:35:39 1996 +++ linux/Documentation/magic-number.txt Sun Feb 2 15:18:29 1997 @@ -54,6 +54,7 @@ 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 diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/00-INDEX linux/Documentation/networking/00-INDEX --- v2.1.24/linux/Documentation/networking/00-INDEX Thu Jan 2 15:55:13 1997 +++ linux/Documentation/networking/00-INDEX Sun Feb 2 15:18:29 1997 @@ -30,6 +30,8 @@ - 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 diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/ax25.txt linux/Documentation/networking/ax25.txt --- v2.1.24/linux/Documentation/networking/ax25.txt Thu Dec 12 17:02:39 1996 +++ linux/Documentation/networking/ax25.txt Sun Feb 2 15:18:29 1997 @@ -12,7 +12,7 @@ 1 IP Default Mode 0=DG 1=VC 0 2 AX.25 Default Mode 0=Normal 1=Extended 0 3 Allow Vanilla Connects 0=No 1=Yes 1 -4 Backoff 0=Linear 1=Exponential 1 +4 Backoff 0=None 1=Linear 2=Exponential 1 5 Connected Mode 0=No 1=Yes 1 6 Standard Window 1 <= N <= 7 2 7 Extended Window 1 <= N <= 63 32 diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt --- v2.1.24/linux/Documentation/networking/cs89x0.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/networking/cs89x0.txt Sun Feb 2 15:18:29 1997 @@ -0,0 +1,651 @@ +CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS +Linux Network Interface Driver ver. 1.02 +=============================================================================== + + +TABLE OF CONTENTS + +1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS + 1.1 Product Overview + 1.2 Driver Description + 1.2.1 Driver Name + 1.2.2 File in the Driver Package + 1.3 System Requirements + 1.4 Licensing Information + +2.0 ADAPTER INSTALLATION and CONFIGURATION + 2.1 CS8900-based Adapter Configuration + 2.2 CS8920-based Adapter Configuration + +3.0 LOADING THE DRIVER AS A MODULE + +4.0 COMPILING THE DRIVER + 4.1 Compiling the Driver As a Loadable Module + 4.2 Compiling the Driver Into the Kernel + 4.3 Compiling the Driver for a Linux v1.2.13 Kernel + +5.0 TESTING AND TROUBLESHOOTING + 5.1 Known Defects and Limitations + 5.2 Testing the Adapter + 5.2.1 Diagnostic Self-Test + 5.2.2 Diagnostic Network Test + 5.3 Using the Adapter's LEDs + 5.4 Resolving I/O Conflicts + +6.0 TECHNICAL SUPPORT + 6.1 Contacting Crystal's Technical Support + 6.2 Information Required Before Contacting Technical Support + 6.3 Obtaining the Latest Driver Version + 6.3.1 Crystal's Web Site + 6.3.2 Crystal's Bulletin Board Service + + +8.3 OBTAINING THE LATEST DRIVER VERSION + +You can obtain the latest CS89XX drivers and support software from Crystal's +BBS or Web site. + + +8.3.1 CRYSTAL'S WEB SITE + +Crystal Semiconductor maintains a web page at http://www.crystal.com with the +the latest drivers and technical publications. + + +8.3.2 CRYSTAL'S BULLETIN BOARD SERVICE + + + + +1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS +=============================================================================== + + +1.1 PRODUCT OVERVIEW + +The CS8900-based ISA Ethernet Adapters from Crystal Semiconductor follow +IEEE 802.3 standards and support half or full-duplex operation in ISA bus +computers on 10 Mbps Ethernet networks. The adapters are designed for +operation in 16-bit ISA or EISA bus expansion slots and are available in +10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 +or fiber networks). + +CS8920-based adapters are similar to the CS8900-based adapter with additional +features for Plug and Play (PnP) support and Wakeup Frame recognition. As +such, the configuration procedures differ somewhat between the two types of +adapters. Refer to the "Adapter Configuration" section for details on +configuring both types of adapters. + + +1.2 DRIVER DESCRIPTION + +The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux v1.2.13 +and v2.0 (or greater) kernels. It can be compiled directly into the kernel or +loaded at run-time as a device driver module. + +1.2.1 Driver Name: cs89x0 + +1.2.2 Files in the Driver Archive: + + readme.txt - this file + release.txt - known defects and modifcation log + cs89x0.c - driver C code + cs89x0.h - driver header file + cs89x0.o - pre-compiled module (for v2.0 kernel) + + + +1.3 SYSTEM REQUIREMENTS + +The following hardware is required: + + * Crystal LAN (CS8900/20-based) Ethernet ISA Adapter + + * IBM or IBM-compatible PC with: + * An 80386 or higher processor + * 16 bytes of contiguous IO space available between 210h - 370h + * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). + + * Appropriate cable (and connector for AUI, 10BASE-2) for your network + topology. + +The following software is required: + + * LINUX kernel version 1.2.13 or 2.X + + * CS8900/20 Setup Utility (DOS-based) + + * LINUX kernel sources for your kernel (if compiling into kernel) + + * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel + or a module) + + + +1.4 LICENSING INFORMATION + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, version 1. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +For a full copy of the GNU General Public License, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + +2.0 ADAPTER INSTALLATION and CONFIGURATION +=============================================================================== + +Both the CS8900 and CS8920-based adapters can be configured using parameters +stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup +Utility if you want to change the adapter's configuration in EEPROM. + +When loading the driver as a module, you can specify many of the adapter's +configuration parameters on the command-line to override the EEPROM's settings +or for interface configuration when an EEPROM is not used. (CS8920-based +adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. + +Since the CS8900/20 Setup Utility is a DOS-based application, you must install +and configure the adapter in a DOS-based system using the CS8900/20 Setup +Utility before installation in the target LINUX system. (Not required if +installing a CS8900-based adapter and the default configuration is acceptable.) + + +2.1 CS8900-BASED ADAPTER CONFIGURATION + +CS8900-based adapters shipped from Crystal Semiconductor have been configured +with the following "default" settings: + + Operation Mode: Memory Mode + IRQ: 10 + Base I/O Address: 300 + Memory Base Address: D0000 + Optimization: DOS Client + Transmission Mode: Half-duplex + BootProm: None + Media Type: Autodetect (3-media cards) or + 10BASE-T (10BASE-T only adapter) + +You should only change the default configuration settings if conflicts with +another adapter exists. To change the adapter's configuration, run the +CS8900/20 Setup Utility. + + +2.2 CS8920-BASED ADAPTER CONFIGURATION + +CS8920-based adapters are shipped from Crystal Semiconductor configured as Plug +and Play (PnP) enabled. However, since Linux is not currently a PnP compatible +operating system, you must install the CS8920 adapter in a DOS-based PC and +run the CS8900/20 Setup Utility to disable PnP and configure the adapter before +installation in the target Linux system. Failure to do this will leave the +adapter inactive and the driver will be unable to communicate with the +adapter. + + + **************************************************************** + * CS8920-BASED ADAPTERS: * + * * + * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * + * SCO UNIX IS NOT A PnP OPERATING SYSTEM. THEREFORE, YOU MUST * + * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * + * TO ACTIVATE THE ADAPTER. * + **************************************************************** + + + + +3.0 LOADING THE DRIVER AS A MODULE +=============================================================================== + +If the driver is compiled as a loadable module, you can load the driver module +with the 'insmod' command. Many of the adapter's configuration parameters can +be specified as command-line arguments to the load command. This facility +provides a means to override the EEPROM's settings or for interface +configuration when an EEPROM is not used. + +Example: + + insmod cs89x0.o io=0x200 irq=0xA media=aui + +This exmaple loads the module and configures the adapter to use an IO port base +address of 200h, interrupt 10, and use the AUI media connection. The following +configuration options are available on the command line: + +* io=### - specify IO address (200h-360h) +* irq=## - specify interrupt level +* mmode=##### - specify memory base address +* dma=# - specify dma channel +* media=rj45 - specify media type + or media=2 + or media=aui + or medai=auto +* duplex=f - specify forced half/full/autonegotiate duplex + or duplex=h + or duplex=auto +* debug=# - debug level + +NOTES: +* If an EEPROM is present, any specified command-line parameter will override +the corresponding configuration value stored in EEPROM. + +* If no "io" or "mmode" parameter is specified on the command-line, the driver +will scan for the adapter. When scanning, the driver only reads I/O ports. +This sometimes is not sufficient, (e.g. after a warm boot). If you wish to +allow the driver to perform a more aggressive scan (one write to the IO base +addresses to reset the data port pointer) you can specify an I/O address with +an address value one greater than the configured address. Example, to scan for +an adapter located at IO base 0x300, specify an IO address of 0x301. Only +ports between 200h and 360h at 20h intervals are scanned. + +* The "duplex=auto" parameter is only supported for the CS8920. + +* The minimum command-line configuration required if an EEPROM is not present +is: + + * io or mmode base address + * irq + * media type (no autodetect) + +The following addtional parameters are CS89XX defaults (values used with no +EEPROM or command-line argument). + + * DMA Burst = enabled + * IOCHRDY Enabled = enabled + * UseSA = enabled + * CS8900 defaults to half-duplex if not specified on command-line + * CS8920 defaults to autoneg if not specified on command-line + * Use reset defaults for other config parameters + +* You can use ifconfig to set the adapter's Ethernet address. + + + + +4.0 COMPILING THE DRIVER +=============================================================================== + +The cs89x0 driver can be compiled directly into the kernel or compiled into +a loadable device driver module. + +NOTE: This part of the description relates to adding the driver to a kernel +not containing the cs89x0 driver. This kernel already contains it. + +4.1 COMPILING THE DRIVER AS A LOADABLE MODULE + +To compile the driver into a loadable module, use the following command +(single command line, without quotes): + +"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall +-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS +-c cs89x0.c" + + +4.2 COMPILING THE DRIVER INTO THE KERNEL + +To compile the driver directly into the kernel requires editing four +configuration files, copying the source file to the /linux/drivers/net +directory and then running the make utility to rebuild the kernel. + +1. Edit the following configuration files by adding the statements as +indicated. (When possible, try to locate the added text to the section of the +file containing similar statements). + +a.) In /usr/src/linux/drivers/net/CONFIG, add + +CS89x0_OPTS = + +Example: + + WD_OPTS = #-DWD_SHMEM=0xDD000 + EL2_OPTS = #-DEL2_AUI + CS89x0_OPTS = + NE_OPTS = + HP_OPTS = + PLIP_OPTS = + + +b.) In /usr/src/linux/drivers/net/Config.in, add: + +tristate 'CS89x0 support' CONFIG_CS89x0 + +Example: + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I + fi + + tristate 'CS89x0 support' CONFIG_CS89x0 + + tristate 'NE2000/NE1000 support' CONFIG_NE2000 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'NI5210 support' CONFIG_NI52 + + +c.) In /usr/src/linux/drivers/net/Makefile, add the following lines: + +ifeq ($(CONFIG_CS89x0),y) +L_OBJS += cs89x0.o +else + ifeq ($(CONFIG_CS89x0),m) + M_OBJS += cs89x0.o + endif +endif + + +d.) In /linux/drivers/net/Space.c file, add the line: + +extern int cs89x0_probe(struct device *dev); + + +Example: + + extern int ultra_probe(struct device *dev); + extern int wd_probe(struct device *dev); + extern int el2_probe(struct device *dev); + + extern int cs89x0_probe(struct device *dev); + + extern int ne_probe(struct device *dev); + extern int hp_probe(struct device *dev); + extern int hp_plus_probe(struct device *dev); + + +Also add: + + #ifdef CONFIG_CS89x0 + && cs89x0_probe(dev) + #endif + + +2.) Copy the driver source files (cs89x0.c and cs89x0.h) and this README file +into the /usr/src/linux/drivers/net directory. + + +3.) Run 'make config' followed by 'make dep' and finally 'make' to rebuild +the kernel. + + +4.3 COMPILING THE DRIVER FOR A LINUX v1.2.13 KERNEL + +To compile the driver for Linux v1.2.13 (into the kernel or as a module), +change the "SUPPORTS" define at the beginning of the cs89x0.c file. +Example: + +#define SUPPORTS_1_2_13 1 /* supports Linux kernel v1.2.13 */ + or +#define SUPPORTS_1_2_13 0 /* supports Linux kernel v2.0 (default) */ + + + +5.0 TESTING AND TROUBLESHOOTING +=============================================================================== + +5.1 KNOWN DEFECTS and LIMITATIONS + +Refer to the RELEASE.TXT file distributed as part of this archive for a list of +know defects, driver limitations, and work arounds. + + +5.2 TESTING THE ADAPTER + +Once the adapter has been installed and configured, the diagnostic option of +the CS8900/20 Setup Utility can be used to test the functionality of the +adapter and its network connection. Use the diagnostics 'Self Test' option to +test the functionality of the adapter with the hardware configuration you have +assigned. You can use the diagnostics 'Network Test' to test the ability of the +adapter to communicate across the Ethernet with another PC equipped with a +CS8900/20-based adapter card (it must also be running the CS8900/20 Setup +Utility). + + NOTE: The Setup Utility's diagnostics are designed to run in a + DOS-only operating system environment. DO NOT run the diagnostics + from a DOS or command prompt session under Windows 95, Windows NT, + OS/2, or other operating system. + + [AC - Question : Do they work in DOSEMU ?] + +To run the diagnostics tests on the CS8900/20 adapter: + + 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. + + 2.) The adapter's current configuration is displayed. Hit the ENTER key to + get to the main menu. + + 4.) Select 'Diagnostics' (ALT-G) from the main menu. + * Select 'Self-Test' to test the adapter's basic functionality. + * Select 'Network Test' to test the network connection and cabling. + + +5.2.1 DIAGNOSTIC SELF-TEST + +The diagnostic self-test checks the adapter's basic functionality as well as +its ability to communicate across the ISA bus based on the system resources +assigned during hardware configuration. The following tests are performed: + + * IO Register Read/Write Test + The IO Register Read/Write test insures that the CS8900/20 can be + accessed in IO mode, and that the IO base address is correct. + + * Shared Memory Test + The Shared Memory test insures the CS8900/20 can be accessed in memory + mode and that the range of memory addresses assigned does not conflict + with other devices in the system. + + * Interrupt Test + The Interrupt test insures there are no conflicts with the assigned IRQ + signal. + + * EEPROM Test + The EEPROM test insures the EEPROM can be read. + + * Chip RAM Test + The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + working properly. + + * Internal Loop-back Test + The Internal Loop Back test insures the adapter's transmitter and + receiver are operating properly. If this test fails, make sure the + adapter's cable is connected to the network (check for LED activity for + example). + + * Boot PROM Test + The Boot PROM test insures the Boot PROM is present, and can be read. + Failure indicates the Boot PROM was not successfully read due to a + hardware problem or due to a conflicts on the Boot PROM address + assignment. (Test only applies if the adapter is configured to use the + Boot PROM option.) + +Failure of a test item indicates a possible system resource conflict with +another device on the ISA bus. In this case, you should use the Manual Setup +option to reconfigure the adapter by selecting a different value for the system +resource that failed. + + +5.2.2 DIAGNOSTIC NETWORK TEST + +The Diagnostic Network Test verifies a working network connection by +transferring data between two CS8900/20 adapters installed in different PCs +on the same network. (Note: the diagnostic network test should not be run +between two nodes across a router.) + +This test requires that each of the two PCs have a CS8900/20-based adapter +installed and have the CS8900/20 Setup Utility running. The first PC is +configured as a Responder and the other PC is configured as an Initiator. +Once the Initiator is started, it sends data frames to the Responder which +returns the frames to the Initiator. + +The total number of frames received and transmitted are displayed on the +Initiator's display, along with a count of the number of frames received and +transmitted OK or in error. The test can be terminated anytime by the user at +either PC. + +To setup the Diagnostic Network Test: + + 1.) Select a PC with a CS8900/20-based adapter and a known working network + connection to act as the Responder. Run the CS8900/20 Setup Utility + and select 'Diagnostics -> Network Test -> Responder' from the main + menu. Hit ENTER to start the Responder. + + 2.) Return to the PC with the CS8900/20-based adapter you want to test and + start the CS8900/20 Setup Utility. + + 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. + Hit ENTER to start the test. + +You may stop the test on the Initiator at any time while allowing the Responder +to continue running. In this manner, you can move to additional PCs and test +them by starting the Initiator on another PC without having to stop/start the +Responder. + + + +5.3 USING THE ADAPTER'S LEDs + +The 2 and 3-media adapters have two LEDs visible on the back end of the board +located near the 10Base-T connector. + +Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T +connection. (Only applies to 10Base-T. The green LED has no significance for +a 10Base-2 or AUI connection.) + +TX/RX LED: The yellow LED lights briefly each time the adapter transmits or +receives data. (The yellow LED will appear to "flicker" on a typical network.) + + +5.4 RESOLVING I/O CONFLICTS + +An IO conflict occurs when two or more adapter use the same ISA resource (IO +address, memory address or IRQ). You can usually detect an IO conflict in one +of four ways after installing and or configuring the CS8900/20-based adapter: + + 1.) The system does not boot properly (or at all). + + 2.) The driver can not communicate with the adapter, reporting an "Adapter + not found" error message. + + 3.) You cannot connect to the network or the driver will not load. + + 4.) If you have configured the adapter to run in memory mode but the driver + reports it is using IO mode when loading, this is an indication of a + memory address conflict. + +If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a +diagnostic self-test. Normally, the ISA resource in conflict will fail the +self-test. If so, reconfigure the adapter selecting another choice for the +resource in conflict. Run the diagnostics again to check for further IO +conflicts. + +In some cases, such as when the PC will not boot, it may be necessary to remove +the adapter and reconfigure it by installing it in another PC to run the +CS8900/20 Setup Utility. Once reinstalled in the target system, run the +diagnostics self-test to ensure the new configuration is free of conflicts +before loading the driver again. + +When manually configuring the adapter, keep in mind the typical ISA system +resource usage as indicated in the tables below. + +I/O Address Device IRQ Device +----------- -------- --- -------- + 200-20F Game I/O adapter 3 COM2, Bus Mouse + 230-23F Bus Mouse 4 COM1 + 270-27F LPT3: third parallel port 5 LPT2 + 2F0-2FF COM2: second serial port 6 Floppy Disk controller + 320-32F Fixed disk controller 7 LPT1 + 8 Real-time Clock + 9 EGA/VGA display adapter + 12 Mouse (PS/2) +Memory Address Device 13 Math Coprocessor +-------------- --------------------- 14 Hard Disk controller +A000-BFFF EGA Graphics Adpater +A000-C7FF VGA Graphics Adpater +B000-BFFF Mono Graphics Adapter +B800-BFFF Color Graphics Adapter +E000-FFFF AT BIOS + + + + +6.0 TECHNICAL SUPPORT +=============================================================================== + +6.1 CONTACTING CRYSTAL'S TECHNICAL SUPPORT + +Crystal's CS89XX Technical Application Support can be reached at: + +Telephone :(800) 888-5016 (from inside U.S. and Canada) + :(512) 442-7555 (from outside the U.S. and Canada) +Fax :(512) 912-3871 +Email :ethernet@crystal.cirrus.com +WWW :http://www.crystal.com + + +6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT + +Before contacting Crystal for technical support, be prepared to provide as much +of the following information as possible. + +1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) + +2.) Adapter configuration + + * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel + * Plug and Play enabled/disabled (CS8920-based adapters only) + * Configured for media auto-detect or specific media type (which type). + +3.) PC System's Configuration + + * Plug and Play system (yes/no) + * BIOS (make and version) + * System make and model + * CPU (type and speed) + * System RAM + * SCSI Adapter + +4.) Software + + * CS89XX driver and version + * Your network operating system and version + * Your system's OS version + * Version of all protocol support files + +5.) Any Error Message displayed. + + + +6.3 OBTAINING THE LATEST DRIVER VERSION + +You can obtain the latest CS89XX drivers and support software from Crystal's +BBS or Web site. You can also contact Crystal's Technical Support (email: +ethernet@crystal.cirrus.com) and request that you be registered for automatic +software-update notification. + + +6.3.1 CRYSTAL'S WEB SITE + +Crystal Semiconductor maintains a web page at http://www.crystal.com with the +the latest drivers and technical publications. + + +6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE + +Access to the BBS is available 24 hours a day, seven days a week. Baud +rates from 300K to 14.4K are supported as well as most common file transfer +protocols. + +To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, +and no parity. Dial (512) 441-3265 and press after connection is made. +Login using your account name and password. (If you do not have an account, +you may login as "GUEST". No password is required for the Guest account.) + +From the main system menu, select the "Enter Public File Area" menu option. +From the Public File Area menu, select the "LAN (Local Area Network)" file +area. A list of the latest drivers and support utilities available for the +CS89XX ISA Ethernet adapter will be presented along with the option to download +the file(s) of your choice. + + diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt --- v2.1.24/linux/Documentation/networking/wan-router.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/networking/wan-router.txt Sun Feb 2 15:18:29 1997 @@ -0,0 +1,130 @@ +------------------------------------------------------------------------------ +WAN Router for Linux Operating System +------------------------------------------------------------------------------ +Version 1.0.0 +December 31, 1996 +Author: Gene Kozin +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 and his implementation +of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). + +Special thanks to all the WANPIPE users who performed field-testing, reported +bugs and made valuable comments and suggestions that help us to improve this +product. + + + +REVISION HISTORY + +1.0.0 December 31, 1996 +-------------------------- + o Initial version. + +>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff -u --recursive --new-file v2.1.24/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt --- v2.1.24/linux/Documentation/serial-console.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/serial-console.txt Sun Feb 2 15:18:29 1997 @@ -0,0 +1,78 @@ + Linux Serial Console + +These examples are valid if you want to use /dev/ttyS1 (COM2) +as the serial console. Replace as needed. + +1. Tell LILO to use the serial port. + In lilo.conf (global section): + + serial = 1,9600n8 (ttyS1, 9600 bd, no parity, 8 bits) + +2. Adjust to kernel flags for the new kernel, + again in lilo.conf (kernel section) + + append = "console=1,9600,n8" + + (Note the extra comma needed if you want to supply parity/framing + information.) + +3. Link /dev/console to the serial port. + + Your probably want to save your old /dev/console (the "master" virtual + console). Check if it is a symbolic link first. If not, `mv' it to + `/dev/tty0': + + ls -l /dev/console + mv /dev/console /dev/tty0 + + Now link the serial port you are going to use as the console to + /dev/console, for example ttyS1: + + ln -s /dev/ttyS1 /dev/console + + On some systems you might want to edit your bootup scripts to make sure + they don't reset this arrangement on boot. (On Debian, check + /etc/rc.boot/console and /etc/default/console). You probably also want + to put a getty on either /dev/console or /dev/ttyS1. + +4. Init and /dev/console. + Sysvinit will open /dev/console on boot. If this does not point + to the serial console device, the startup messages will be printed + to the wrong device. The kernel also passes the environment variable + "CONSOLE" to the init program. sysvinit-2.64 reckognizes this, and + opens that device instead. Boot scripts as mentioned in (3) can + also check this variable to see what device the system console is. + If CONSOLE is not set you can assume the console is /dev/tty0. + + Sysvinit remembers its stty settings in a file in /etc, called + `/etc/ioctl.save'. REMOVE THIS FILE before using the serial + console for the first time, because otherwise init will probably + set the baudrate to 38400 (bausdrate of the virtual console). + +5. /dev/console and X + Programs that want to do something with the virtual console usually + open /dev/console. XF86 does this, and probably SVGALIB as well. + IMO this is wrong; they should open /dev/tty0. + I have binary patched /usr/bin/X11/XF86_SVGA to use "tty0" + instead of "console". + +6. Notes. + + If you compile the next little program, you will be able + to really "halt" the system. It will enter a little + monitor :) + + main() { reboot(0xfee1dead, 672274793, 0xCDEF0123); } + + This is just a call to the new "halt" function that later + kernels have. This is included the "halt" command of + the recent sysvinit versions. + + The monitor will also be entered at a kernel panic, or + when you press "break". That last function does not + work at the moment I think, but it would be useful for + kernel debugging. You don't have alt-scrollock on a serial + console to find out the current EIP... + +Miquel van Smoorenburg , 21-Jun-1996 +Stephen C. Tweedie , 23-Dec-1996 diff -u --recursive --new-file v2.1.24/linux/Documentation/smp linux/Documentation/smp --- v2.1.24/linux/Documentation/smp Thu Jan 1 02:00:00 1970 +++ linux/Documentation/smp Sun Feb 2 15:18:29 1997 @@ -0,0 +1,23 @@ +To set up SMP + +Edit linux/Makefile and uncomment SMP=1, then compile and install +as usual. + +If you are using LILO, it is handy to have both SMP and non-SMP +kernel images on hand. Edit /etc/lilo.conf to create an entry +for another kernel image called "linux-smp" or something. + +The next time you compile the kernel, when running a SMP kernel, +edit linux/Makefile and change "MAKE=make" "MAKE=make -jN" +(where N = number of CPU + 1, or if you have tons of memory/swap + you can just use "-j" without a number). Feel free to experiment +with this one. + +Of course you should time how long each build takes :-) +Example: + make config + time -v sh -c 'make dep ; make clean install modules modules_install' + +If you are using some Compaq MP compliant machines you will need to set +the operating system in the BIOS settings to "Unixware" - don't ask me +why Compaq's dont work otherwise. diff -u --recursive --new-file v2.1.24/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt --- v2.1.24/linux/Documentation/watchdog.txt Thu Jan 23 21:06:45 1997 +++ linux/Documentation/watchdog.txt Sun Feb 2 15:18:30 1997 @@ -87,6 +87,8 @@ 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. diff -u --recursive --new-file v2.1.24/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.24/linux/MAINTAINERS Sun Feb 2 15:46:19 1997 +++ linux/MAINTAINERS Sun Feb 2 15:18:30 1997 @@ -277,6 +277,13 @@ 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 diff -u --recursive --new-file v2.1.24/linux/Makefile linux/Makefile --- v2.1.24/linux/Makefile Sun Feb 2 15:46:19 1997 +++ linux/Makefile Wed Jan 29 13:32:27 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 24 +SUBLEVEL = 25 ARCH = i386 diff -u --recursive --new-file v2.1.24/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.24/linux/arch/alpha/kernel/bios32.c Tue Jan 28 18:49:45 1997 +++ linux/arch/alpha/kernel/bios32.c Sun Feb 2 15:00:34 1997 @@ -24,6 +24,7 @@ * within the United States, $35 abroad. */ #include +#include #include #include @@ -50,7 +51,6 @@ #else /* CONFIG_PCI */ -#include #include #include #include diff -u --recursive --new-file v2.1.24/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.1.24/linux/arch/alpha/kernel/traps.c Tue Jan 28 18:49:46 1997 +++ linux/arch/alpha/kernel/traps.c Sun Feb 2 15:00:46 1997 @@ -426,13 +426,13 @@ 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); diff -u --recursive --new-file v2.1.24/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.1.24/linux/arch/i386/boot/setup.S Thu Jan 23 21:06:46 1997 +++ linux/arch/i386/boot/setup.S Sun Feb 2 15:18:30 1997 @@ -240,6 +240,16 @@ push ax push cx push dx + ! which bootloader ? + seg cs + mov al,byte ptr type_of_loader + and al,#0xf0 + cmp al,#0x10 + jne try_xe801 ! not Loadlin + seg cs + cmp byte ptr type_of_loader,#0x16 + jbe oldstylemem ! Loadlin <= 1.6 don't like that +try_xe801: mov ax,#0xe801 int 0x15 jc oldstylemem @@ -257,6 +267,9 @@ 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 diff -u --recursive --new-file v2.1.24/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.24/linux/arch/i386/kernel/setup.c Thu Jan 23 21:06:46 1997 +++ linux/arch/i386/kernel/setup.c Sun Feb 2 15:18:30 1997 @@ -235,7 +235,8 @@ 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]; diff -u --recursive --new-file v2.1.24/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.24/linux/arch/i386/kernel/smp.c Sun Feb 2 15:46:19 1997 +++ linux/arch/i386/kernel/smp.c Sun Feb 2 15:18:30 1997 @@ -22,6 +22,7 @@ * Matthias Sattler : Changes for 2.1 kernel map. * Michel Lespinasse : Changes for 2.1 kernel map. * Michael Chastain : Change trampoline.S to gnu as. + * Alan Cox : Dumb bug: 'B' step PPro's are fine * */ @@ -573,8 +574,11 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.1.24/linux/arch/i386/kernel/vm86.c Tue Jan 28 18:49:47 1997 +++ linux/arch/i386/kernel/vm86.c Sun Feb 2 15:18:30 1997 @@ -427,34 +427,26 @@ return_to_32bit(regs, VM86_INTx + (i << 8)); } - - +/* This must be called with the kernel lock held. */ int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno) { - int ret; - - lock_kernel(); if (VMPI.is_vm86pus) { if ( (trapno==3) || (trapno==1) ) return_to_32bit(regs, VM86_TRAP + (trapno << 8)); do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs)); - ret = 1; - goto out; + return 1; } - ret = 0; if (trapno !=1) - goto out; /* we let this handle by the calling routine */ + return 0; /* we let this handle by the calling routine */ if (current->flags & PF_PTRACED) current->blocked &= ~(1 << (SIGTRAP-1)); send_sig(SIGTRAP, current, 1); current->tss.trap_no = trapno; current->tss.error_code = error_code; -out: - unlock_kernel(); - return ret; + return 0; } - +/* This must be called with the kernel lock held. */ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) { unsigned char *csp, *ssp; @@ -466,9 +458,8 @@ #define VM86_FAULT_RETURN \ if (VMPI.force_return_for_pic && (VEFLAGS & IF_MASK)) \ return_to_32bit(regs, VM86_PICRETURN); \ - goto out; + return; - lock_kernel(); csp = (unsigned char *) (regs->cs << 4); ssp = (unsigned char *) (regs->ss << 4); sp = SP(regs); @@ -532,7 +523,7 @@ return_to_32bit(regs, VM86_INTx + (intno << 8)); } do_int(regs, intno, ssp, sp); - goto out; + return; } /* iret */ @@ -565,8 +556,6 @@ default: return_to_32bit(regs, VM86_UNKNOWN); } -out: - unlock_kernel(); } /* ---------------- vm86 special IRQ passing stuff ----------------- */ diff -u --recursive --new-file v2.1.24/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c --- v2.1.24/linux/arch/i386/lib/checksum.c Thu Dec 12 19:36:58 1996 +++ linux/arch/i386/lib/checksum.c Sun Feb 2 15:18:30 1997 @@ -11,6 +11,9 @@ * Lots of code moved from tcp.c and ip.c; see those files * for more names. * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -86,7 +89,7 @@ shll $16,%%ecx 5: movb (%%esi),%%cl 6: addl %%ecx,%%eax - adcl $0, %%eax + adcl $0, %%eax 7: " : "=a"(sum) : "0"(sum), "c"(len), "S"(buff) @@ -94,96 +97,228 @@ 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; } + diff -u --recursive --new-file v2.1.24/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c --- v2.1.24/linux/drivers/cdrom/isp16.c Mon Dec 30 15:39:05 1996 +++ linux/drivers/cdrom/isp16.c Sun Feb 2 15:18:30 1997 @@ -62,12 +62,12 @@ 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 diff -u --recursive --new-file v2.1.24/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c --- v2.1.24/linux/drivers/cdrom/sjcd.c Tue Jan 28 18:49:58 1997 +++ linux/drivers/cdrom/sjcd.c Sun Feb 2 15:18:30 1997 @@ -106,7 +106,10 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v2.1.24/linux/drivers/char/apm_bios.c Tue Jan 28 18:49:59 1997 +++ linux/drivers/char/apm_bios.c Wed Jan 29 13:32:58 1997 @@ -59,6 +59,7 @@ #include #include +#include #include #include diff -u --recursive --new-file v2.1.24/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.24/linux/drivers/char/console.c Tue Jan 28 18:50:01 1997 +++ linux/drivers/char/console.c Sun Feb 2 15:52:22 1997 @@ -60,6 +60,7 @@ * User-defined bell sound, new setterm control sequences and printk * redirection by Martin Mares 19-Nov-95 * + * APM screenblank bug fixed Takashi Manabe */ #define BLANK 0x0020 @@ -2194,12 +2195,14 @@ 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) diff -u --recursive --new-file v2.1.24/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.1.24/linux/drivers/char/softdog.c Sun Feb 2 15:46:19 1997 +++ linux/drivers/char/softdog.c Sun Feb 2 15:18:35 1997 @@ -46,7 +46,6 @@ struct timer_list watchdog_ticktock; static int timer_alive = 0; -static int in_use = 0; /* @@ -71,9 +70,8 @@ static int softdog_open(struct inode *inode, struct file *file) { - if(in_use) + if(timer_alive) return -EBUSY; - in_use = 1; MOD_INC_USE_COUNT; /* * Activate timer @@ -81,7 +79,7 @@ del_timer(&watchdog_ticktock); watchdog_ticktock.expires=jiffies + (soft_margin * HZ); add_timer(&watchdog_ticktock); - timer_alive++; + timer_alive=1; return 0; } @@ -94,9 +92,8 @@ #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) diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v2.1.24/linux/drivers/net/3c501.c Tue Dec 31 21:41:01 1996 +++ linux/drivers/net/3c501.c Sun Feb 2 15:18:35 1997 @@ -123,7 +123,7 @@ static void el_receive(struct device *dev); static void el_reset(struct device *dev); static int el1_close(struct device *dev); -static struct enet_statistics *el1_get_stats(struct device *dev); +static struct net_device_stats *el1_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); #define EL1_IO_EXTENT 16 @@ -139,7 +139,7 @@ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; int tx_pkt_start; /* The length of the current Tx packet. */ int collisions; /* Tx collisions this packet */ int loading; /* Spot buffer load collisions */ @@ -398,12 +398,6 @@ dev->trans_start = jiffies; } - if (skb == NULL) - { - dev_tint(dev); - return 0; - } - save_flags(flags); /* @@ -432,6 +426,8 @@ lp->tx_pkt_start = gp_start; lp->collisions = 0; + lp->stats.tx_bytes += skb->len; + /* * Command mode with status cleared should [in theory] * mean no more interrupts can be pending on the card. @@ -769,7 +765,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.1.24/linux/drivers/net/3c505.c Tue Dec 31 21:41:01 1996 +++ linux/drivers/net/3c505.c Sun Feb 2 15:18:35 1997 @@ -1034,6 +1034,9 @@ } adapter = dev->priv; + + adapter->stats.tx_bytes+=nlen; + /* * send the adapter a transmit packet command. Ignore segment and offset * and make sure the length is even @@ -1111,15 +1114,6 @@ adapter->stats.tx_dropped++; } - /* Some upper layer thinks we've missed a tx-done interrupt */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - if (skb->len <= 0) - return 0; - if (elp_debug >= 3) printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len); @@ -1156,7 +1150,7 @@ * ******************************************************/ -static struct enet_statistics *elp_get_stats(struct device *dev) +static struct net_device_stats *elp_get_stats(struct device *dev) { elp_device *adapter = (elp_device *) dev->priv; @@ -1329,7 +1323,7 @@ /* * 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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c505.h linux/drivers/net/3c505.h --- v2.1.24/linux/drivers/net/3c505.h Wed Oct 16 10:48:17 1996 +++ linux/drivers/net/3c505.h Sun Feb 2 15:18:35 1997 @@ -264,7 +264,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.1.24/linux/drivers/net/3c507.c Tue Dec 31 21:41:02 1996 +++ linux/drivers/net/3c507.c Sun Feb 2 15:18:35 1997 @@ -115,7 +115,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; int last_restart; ushort rx_head; ushort rx_tail; @@ -283,7 +283,7 @@ static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void el16_rx(struct device *dev); static int el16_close(struct device *dev); -static struct enet_statistics *el16_get_stats(struct device *dev); +static struct net_device_stats *el16_get_stats(struct device *dev); static void hardware_send_packet(struct device *dev, void *buf, short length); void init_82586_mem(struct device *dev); @@ -300,8 +300,8 @@ If dev->base_addr == 2, (detachable devices only) allocate space for the device and return success. */ -int -el16_probe(struct device *dev) + +int el16_probe(struct device *dev) { int base_addr = dev ? dev->base_addr : 0; int i; @@ -428,10 +428,7 @@ return 0; } - - -static int -el16_open(struct device *dev) +static int el16_open(struct device *dev) { irq2dev_map[dev->irq] = dev; @@ -447,14 +444,14 @@ return 0; } -static int -el16_send_packet(struct sk_buff *skb, struct device *dev) +static int el16_send_packet(struct sk_buff *skb, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; short *shmem = (short*)dev->mem_start; - if (dev->tbusy) { + if (dev->tbusy) + { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; @@ -480,21 +477,15 @@ dev->trans_start = jiffies; } - /* If some higher layer thinks we've missed an tx-done interrupt - we are passed NULL. Caution: dev_tint() handles the cli()/sti() - itself. */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } - /* Block a timer-based transmit from overlapping. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); - else { + else + { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; + lp->stats.tx_bytes+=length; /* Disable the 82586's input to the interrupt line. */ outb(0x80, ioaddr + MISC_CTRL); hardware_send_packet(dev, buf, length); @@ -509,11 +500,10 @@ return 0; } - + /* The typical workload of the driver: Handle the network interface interrupts. */ -static void -el16_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; @@ -588,8 +578,9 @@ ack_cmd |= CUC_RESUME; } - if ((status & 0x0070) != 0x0040 && dev->start) { - static void init_rx_bufs(struct device *); + if ((status & 0x0070) != 0x0040 && dev->start) + { + static void init_rx_bufs(struct device *); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ if (net_debug) @@ -612,8 +603,7 @@ return; } -static int -el16_close(struct device *dev) +static int el16_close(struct device *dev) { int ioaddr = dev->base_addr; ushort *shmem = (short*)dev->mem_start; @@ -642,8 +632,7 @@ /* Get the current statistics. This may be called with the card open or closed. */ -static struct enet_statistics * -el16_get_stats(struct device *dev) +static struct net_device_stats *el16_get_stats(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; @@ -653,8 +642,7 @@ } /* Initialize the Rx-block list. */ -static void -init_rx_bufs(struct device *dev) +static void init_rx_bufs(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; unsigned short *write_ptr; @@ -699,8 +687,7 @@ } -void -init_82586_mem(struct device *dev) +void init_82586_mem(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; @@ -758,8 +745,7 @@ return; } -static void -hardware_send_packet(struct device *dev, void *buf, short length) +static void hardware_send_packet(struct device *dev, void *buf, short length) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; @@ -804,8 +790,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.1.24/linux/drivers/net/3c509.c Tue Dec 31 21:41:02 1996 +++ linux/drivers/net/3c509.c Sun Feb 2 15:18:35 1997 @@ -110,7 +110,7 @@ #define SKB_QUEUE_SIZE 64 struct el3_private { - struct enet_statistics stats; + struct net_device_stats stats; /* skb send-queue */ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; @@ -123,7 +123,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void update_stats(int addr, struct device *dev); -static struct enet_statistics *el3_get_stats(struct device *dev); +static struct net_device_stats *el3_get_stats(struct device *dev); static int el3_rx(struct device *dev); static int el3_close(struct device *dev); #ifdef HAVE_MULTICAST @@ -421,8 +421,7 @@ return 0; /* Always succeed */ } -static int -el3_start_xmit(struct sk_buff *skb, struct device *dev) +static int el3_start_xmit(struct sk_buff *skb, struct device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; int ioaddr = dev->base_addr; @@ -444,14 +443,6 @@ dev->tbusy = 0; } - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - if (skb->len <= 0) - return 0; - if (el3_debug > 4) { printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", dev->name, skb->len, inw(ioaddr + EL3_STATUS)); @@ -479,6 +470,7 @@ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { + lp->stats.tx_bytes+=skb->len; /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); outw(0x00, ioaddr + TX_FIFO); @@ -589,8 +581,7 @@ } -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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.1.24/linux/drivers/net/3c523.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/3c523.c Sun Feb 2 15:18:35 1997 @@ -170,7 +170,7 @@ static int elmc_open(struct device *dev); static int elmc_close(struct device *dev); static int elmc_send_packet(struct sk_buff *,struct device *); -static struct enet_statistics *elmc_get_stats(struct device *dev); +static struct net_device_stats *elmc_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); /* helper-functions */ @@ -183,25 +183,26 @@ static void elmc_xmt_int(struct device *dev); static void elmc_rnr_int(struct device *dev); -struct priv { - struct enet_statistics stats; - unsigned long base; - char *memtop; - volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; - volatile struct scp_struct *scp; /* volatile is important */ - volatile struct iscp_struct *iscp; /* volatile is important */ - volatile struct scb_struct *scb; /* volatile is important */ - volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; - volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; +struct priv +{ + struct net_device_stats stats; + unsigned long base; + char *memtop; + volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; + volatile struct scp_struct *scp; /* volatile is important */ + volatile struct iscp_struct *iscp; /* volatile is important */ + volatile struct scb_struct *scb; /* volatile is important */ + volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; + volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; #if (NUM_XMIT_BUFFS == 1) - volatile struct nop_cmd_struct *nop_cmds[2]; + volatile struct nop_cmd_struct *nop_cmds[2]; #else - volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; + volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; #endif - volatile int nop_point,num_recv_buffs; - volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; - volatile int xmit_count,xmit_last; - volatile int slot; + volatile int nop_point,num_recv_buffs; + volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; + volatile int xmit_count,xmit_last; + volatile int slot; }; #define elmc_attn586() {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);} @@ -1208,9 +1209,8 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.24/linux/drivers/net/3c59x.c Sun Nov 10 20:12:11 1996 +++ linux/drivers/net/3c59x.c Sun Feb 2 15:18:35 1997 @@ -233,7 +233,7 @@ char devname[8]; /* "ethN" string, also for kernel debug. */ const char *product_name; struct device *next_module; - struct enet_statistics stats; + struct net_device_stats stats; struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ struct timer_list timer; /* Media selection timer. */ int options; /* User-settable misc. driver options. */ @@ -276,7 +276,7 @@ static 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); @@ -1067,8 +1067,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.1.24/linux/drivers/net/8390.c Thu Dec 12 19:37:04 1996 +++ linux/drivers/net/8390.c Sun Feb 2 15:18:35 1997 @@ -179,17 +179,7 @@ dev->trans_start = jiffies; } - /* Sending a NULL skb means some higher layer thinks we've missed an - tx-done interrupt. Caution: dev_tint() handles the cli()/sti() - itself. */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } - length = skb->len; - if (skb->len <= 0) - return 0; /* Mask interrupts from the ethercard. */ outb_p(0x00, e8390_base + EN0_IMR); @@ -202,6 +192,8 @@ send_length = ETH_ZLEN < length ? length : ETH_ZLEN; + ei_local->stat.tx_bytes+=send_length; + #ifdef EI_PINGPONG /* @@ -560,6 +552,7 @@ skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); + ei_local->stat.rx_bytes+=skb->len; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); ei_local->stat.rx_packets++; @@ -663,7 +656,7 @@ } -static 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/8390.h linux/drivers/net/8390.h --- v2.1.24/linux/drivers/net/8390.h Thu Dec 12 19:37:04 1996 +++ linux/drivers/net/8390.h Sun Feb 2 15:18:35 1997 @@ -75,7 +75,7 @@ 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. */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/CONFIG linux/drivers/net/CONFIG --- v2.1.24/linux/drivers/net/CONFIG Tue Nov 19 15:53:54 1996 +++ linux/drivers/net/CONFIG Sun Feb 2 15:18:35 1997 @@ -99,3 +99,4 @@ DEFXX_OPTS = ELP_OPTS = TULIP_OPTS = +CS89x0_OPTS = diff -u --recursive --new-file v2.1.24/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.24/linux/drivers/net/Config.in Thu Jan 2 15:55:16 1997 +++ linux/drivers/net/Config.in Sun Feb 2 15:18:35 1997 @@ -76,7 +76,8 @@ tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT - tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5 + tristate 'CS89x0 support' CONFIG_CS89x0 + tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -104,6 +105,15 @@ dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI fi +# +# LocalTalk +# +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_ATALK" != "n" ]; then + tristate 'LocalTalk PC support' CONFIG_LTPC + fi +fi + tristate 'PLIP (parallel port) support' CONFIG_PLIP tristate 'PPP (point-to-point) support' CONFIG_PPP @@ -137,11 +147,6 @@ 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 @@ -158,5 +163,24 @@ 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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.24/linux/drivers/net/Makefile Tue Jan 28 18:50:02 1997 +++ linux/drivers/net/Makefile Sun Feb 2 15:18:36 1997 @@ -77,14 +77,6 @@ endif endif -ifeq ($(CONFIG_WIC),y) -L_OBJS += wic.o -else - ifeq ($(CONFIG_WIC),m) - M_OBJS += wic.o - endif -endif - ifeq ($(CONFIG_SMC9194),y) L_OBJS += smc9194.o else @@ -630,6 +622,22 @@ endif endif +ifeq ($(CONFIG_CS89x0),y) +L_OBJS += cs89x0.o +else + ifeq ($(CONFIG_CS89x0),m) + M_OBJS += cs89x0.o + endif +endif + +ifeq ($(CONFIG_LTPC),y) +L_OBJS += ltpc.o +else + ifeq ($(CONFIG_LTPC),m) + M_OBJS += ltpc.o + endif +endif + ifeq ($(CONFIG_BAYCOM),y) L_OBJS += baycom.o CONFIG_HDLCDRV_BUILTIN = y @@ -661,6 +669,21 @@ endif +ifeq ($(CONFIG_VENDOR_SANGOMA),y) + M_OBJS += sdladrv.o + M_OBJS += wanpipe.o + WANPIPE_OBJS = sdlamain.o + ifeq ($(CONFIG_WANPIPE_X25),y) + WANPIPE_OBJS += sdla_x25.o + endif + ifeq ($(CONFIG_WANPIPE_FR),y) + WANPIPE_OBJS += sdla_fr.o + endif + ifeq ($(CONFIG_WANPIPE_PPP),y) + WANPIPE_OBJS += sdla_ppp.o + endif +endif + include $(TOPDIR)/Rules.make clean: @@ -725,7 +748,24 @@ 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 $< diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.de4x5 linux/drivers/net/README.de4x5 --- v2.1.24/linux/drivers/net/README.de4x5 Tue May 2 07:10:16 1995 +++ linux/drivers/net/README.de4x5 Sun Feb 2 15:02:05 1997 @@ -1,20 +1,22 @@ -The de425/de434/de435/de500 driver in this distribution is designed to work -with the Digital Equipment Corporation series of PCI/EISA ethernet cards -(DE425, DE434, DE435, DE500) and with all kernels that support PCI. +This driver has been upgraded to include generic DECchip support through the +use of the on-board SROM that is found on all DECchip cards except for the +DC21040. The driver will work with the following set of cards and probably +more: + + KINGSTON + Linksys + ZNYX342 + SMC8432 + SMC9332 (w/new SROM) + ZNYX31[45] + DIGITAL EtherWORKS PCI/EISA (DE425, DE434, DE435, DE450, DE500) Auto media detection is provided so that the media choice isn't compiled in -and is flexible enough to be able to reconfigure on-the-fly. This feature -hasn't been included for the DE500 unfortunately, due to a potential patent -dispute. When I get around to implementing the autosense algorithm by myself -(which could legally be difficult to prove since I'm part of the group that -has implemented the patented algorithm) you'll have an auto speed selection -for the de500. If you want the auto speed feature yell at Digital. If enough -of you do things might change. - -The ability to load this driver as a loadable module has been included, -although I don't recommend its use with PCI, since PCI dynamically allocates -where the card will go at boot time (i.e. the card would have to be present -in the system at boot time for its address/IRQ to be assigned). +and is flexible enough to be able to reconfigure on-the-fly. + +The ability to load this driver as a loadable module has been included and +will now load (and unload) as many DECchip cards as it can find and +configure with just one invocation of 'insmod'. The performance we've achieved so far has been measured through the 'ttcp' tool at 1.06MB/s for TCP and 1.17MB/s for UDP. This measures the total @@ -32,16 +34,8 @@ measurement. Their error is approx +/-20k on a quiet (private) network and also depend on what load the CPU has, CPU speed etc. -ZYNX and SMC cards, which use the PCI DECchip DC21040, are not specifically -supported in this driver because - -a) I have no information on them. -b) I cannot test them with the driver. -c) Donald Becker's 'tulip.c' driver works with them....well one person says - they do and another says they do not, so take your pick! - -This driver can be made to work with the ZYNX (and may be the SMC) card by -setting a compile time flag (IS_NOT_DEC) in linux/drivers/net/CONFIG +I've had reports that Alphas can get 80+Mb/s when using 100BASE-TX and +similar figures for 133MHz Pentium Pros. Enjoy! diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.ltpc linux/drivers/net/README.ltpc --- v2.1.24/linux/drivers/net/README.ltpc Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/README.ltpc Sun Feb 2 15:18:36 1997 @@ -0,0 +1,98 @@ +This is the ALPHA version of the ltpc driver. + +In order to use it, you will need at least version 1.3.3 of the +netatalk package, and the Apple or Farallon Localtalk PC card. +There are a number of different Localtalk cards for the PC; this +driver applies only to the one with the 65c02 processor chip on it. + +To include it in the kernel, select the CONFIG_LTPC switch in the +configuration dialog; at this time (kernel 2.1.23) compiling it as +a module will not work. + +Before starting up the netatalk demons (perhaps in rc.local), you +need to add a line such as: + +/sbin/ifconfig ltalk0 127.0.0.42 + + +The driver will autoprobe, and you should see a message like: +"LocalTalk card found at 240, IR9, DMA1." +at bootup. + +The appropriate netatalk configuration depends on whether you are +attached to a network that includes appletalk routers or not. If, +like me, you are simply connecting to your home Macintoshes and +printers, you need to set up netatalk to "seed". The way I do this +is to have the lines + +dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033" +ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033" + +in my atalkd.conf. What is going on here is that I need to fool +netatalk into thinking that there are two appletalk interfaces +present -- otherwise it refuses to seed. This is a hack, and a +more permanent solution would be to alter the netatalk code. +Note that the dummy driver needs to accept multicasts also -- earlier +versions of dummy.c may need to be patched. + + +If you are attached to an extended appletalk network, with routers on +it, then you don't need to fool around with this -- the appropriate +line in atalkd.conf is + +ltalk0 -phase 1 + +-------------------------------------- + +Card Configuration: + +The interrupts and so forth are configured via the dipswitch on the +board. Set the switches so as not to conflict with other hardware. + + Interrupts -- set at most one. If none are set, the driver uses + polled mode. Because the card was developed in the XT era, the + original documentation refers to IRQ2. Since you'll be running + this on an AT (or later) class machine, that really means IRQ9. + + SW1 IRQ 4 + SW2 IRQ 3 + SW3 IRQ 9 (2 in original card documentation only applies to XT) + + + DMA -- choose DMA 1 or 3, and set both corresponding switches. + + SW4 DMA 3 + SW5 DMA 1 + SW6 DMA 3 + SW7 DMA 1 + + + I/O address -- choose one. + + SW8 220 / 240 + +-------------------------------------- + +IP: + Many people are interested in this driver in order to use IP +when Localtalk, but no Ethernet, is available. While the code to do +this is not strictly speaking part of this driver, an experimental +version is available which seems to work under kernel 2.0.xx. It is +not yet functional in the 2.1.xx kernels. + +-------------------------------------- + +BUGS: + +2.0.xx: + +2.1.xx: The module support doesn't work yet. + +______________________________________ + +THANKS: + Thanks to Alan Cox for helpful discussions early on in this +work, and to Denis Hainsworth for doing the bleeding-edge testing. + +-- Bradford Johnson + diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.multicast linux/drivers/net/README.multicast --- v2.1.24/linux/drivers/net/README.multicast Tue Jan 28 18:50:02 1997 +++ linux/drivers/net/README.multicast Sun Feb 2 15:18:36 1997 @@ -25,6 +25,7 @@ arcnet NO NO NO N/A at1700 PROMISC PROMISC YES Software atp PROMISC PROMISC YES Software +cs89x0 YES YES YES Software de4x5 YES NO YES Hardware de600 NO NO NO N/A de620 PROMISC PROMISC YES Software diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.wanpipe linux/drivers/net/README.wanpipe --- v2.1.24/linux/drivers/net/README.wanpipe Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/README.wanpipe Sun Feb 2 15:18:36 1997 @@ -0,0 +1,142 @@ +------------------------------------------------------------------------------ +WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router +------------------------------------------------------------------------------ +Release 3.0.0 +December 31, 1996 +Author: Gene Kozin +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 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + diff -u --recursive --new-file v2.1.24/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.24/linux/drivers/net/Space.c Tue Jan 28 18:50:02 1997 +++ linux/drivers/net/Space.c Sun Feb 2 15:18:36 1997 @@ -84,14 +84,14 @@ extern int a2065_probe(struct device *); extern int ariadne_probe(struct device *); extern int hydra_probe(struct device *); +extern int cs89x0_probe(struct device *dev); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); extern int de600_probe(struct device *); extern int de620_probe(struct device *); -static int -ethif_probe(struct device *dev) +static int ethif_probe(struct device *dev) { u_long base_addr = dev->base_addr; @@ -150,6 +150,9 @@ #ifdef CONFIG_AT1500 && at1500_probe(dev) #endif +#ifdef CONFIG_CS89x0 + && cs89x0_probe(dev) +#endif #ifdef CONFIG_AT1700 && at1700_probe(dev) #endif @@ -269,6 +272,17 @@ # undef NEXT_DEV # define NEXT_DEV (&arcnet_dev) #endif + +#if defined(CONFIG_LTPC) + extern int ltpc_probe(struct device *); + static struct device dev_ltpc = { + "ltalk0\0 ", + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NEXT_DEV, ltpc_probe }; +# undef NEXT_DEV +# define NEXT_DEV (&dev_ltpc) +#endif /* LTPC */ /* The first device defaults to I/O base '0', which means autoprobe. */ #ifndef ETH0_ADDR diff -u --recursive --new-file v2.1.24/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.1.24/linux/drivers/net/a2065.c Sun Dec 22 16:37:31 1996 +++ linux/drivers/net/a2065.c Sun Feb 2 15:18:36 1997 @@ -122,7 +122,7 @@ int lance_log_rx_bufs, lance_log_tx_bufs; int rx_ring_mod_mask, tx_ring_mod_mask; - struct enet_statistics stats; + struct net_device_stats stats; int tpe; /* cable-selection is TPE */ int auto_select; /* cable-selection by carrier */ unsigned short busmaster_regval; @@ -645,7 +645,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/apricot.c linux/drivers/net/apricot.c --- v2.1.24/linux/drivers/net/apricot.c Tue Dec 31 21:41:02 1996 +++ linux/drivers/net/apricot.c Sun Feb 2 15:18:36 1997 @@ -162,7 +162,7 @@ struct i596_cmd *cmd_head; int cmd_backlog; unsigned long last_cmd; - struct enet_statistics stats; + struct net_device_stats stats; }; char init_setup[] = { @@ -185,7 +185,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct device *dev); static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int i596_close(struct device *dev); -static struct enet_statistics *i596_get_stats(struct device *dev); +static struct net_device_stats *i596_get_stats(struct device *dev); static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd); static void print_eth(char *); static void set_multicast_list(struct device *dev); @@ -942,7 +942,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.1.24/linux/drivers/net/arcnet.c Thu Jan 2 15:55:16 1997 +++ linux/drivers/net/arcnet.c Sun Feb 2 15:18:36 1997 @@ -535,7 +535,7 @@ /* Information that needs to be kept for each board. */ struct arcnet_local { - struct enet_statistics stats; + struct net_device_stats stats; u_short sequence; /* sequence number (incs with each packet) */ u_char stationid, /* our 8-bit station address */ recbuf, /* receive buffer # (0 or 1) */ @@ -609,7 +609,7 @@ static void arcnetA_rx(struct device *dev,u_char *buf, int length,u_char saddr, u_char daddr); -static struct enet_statistics *arcnet_get_stats(struct device *dev); +static struct net_device_stats *arcnet_get_stats(struct device *dev); int arcnetA_header(struct sk_buff *skb,struct device *dev, unsigned short type,void *daddr,void *saddr,unsigned len); @@ -2580,8 +2580,7 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.1.24/linux/drivers/net/ariadne.c Sun Dec 22 16:37:31 1996 +++ linux/drivers/net/ariadne.c Sun Feb 2 15:18:36 1997 @@ -103,7 +103,7 @@ u_short *rx_buff[RX_RING_SIZE]; int cur_tx, cur_rx; /* The next free ring entry */ int dirty_tx; /* The ring entries to be free()ed. */ - struct enet_statistics stats; + struct net_device_stats stats; char tx_full; unsigned long lock; int key; @@ -128,7 +128,7 @@ static int ariadne_rx(struct device *dev); static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp); static int ariadne_close(struct device *dev); -static struct enet_statistics *ariadne_get_stats(struct device *dev); +static struct net_device_stats *ariadne_get_stats(struct device *dev); #ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev); #endif @@ -782,7 +782,7 @@ } -static 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.1.24/linux/drivers/net/at1700.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/at1700.c Sun Feb 2 15:18:36 1997 @@ -67,7 +67,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; uint tx_started:1; /* Number of packet on the Tx queue. */ uchar tx_queue; /* Number of packet on the Tx queue. */ ushort tx_queue_len; /* Current length of the Tx queue. */ @@ -120,7 +120,7 @@ static 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); @@ -592,8 +592,8 @@ /* 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c --- v2.1.24/linux/drivers/net/atari_bionet.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/atari_bionet.c Sun Feb 2 15:18:36 1997 @@ -136,7 +136,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; long open_time; /* for debugging */ int poll_time; /* polling time varies with net load */ }; @@ -157,7 +157,7 @@ static int bionet_send_packet(struct sk_buff *skb, struct device *dev); static void bionet_poll_rx(struct device *); static int bionet_close(struct device *dev); -static struct enet_statistics *net_get_stats(struct device *dev); +static struct net_device_stats *net_get_stats(struct device *dev); static void bionet_tick(unsigned long); static struct timer_list bionet_timer = { NULL, NULL, 0, 0, bionet_tick }; @@ -594,8 +594,8 @@ /* 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; } diff -u --recursive --new-file v2.1.24/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c --- v2.1.24/linux/drivers/net/atari_pamsnet.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/atari_pamsnet.c Sun Feb 2 15:18:36 1997 @@ -134,7 +134,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; long open_time; /* for debugging */ int poll_time; /* polling time varies with net load */ }; @@ -167,7 +167,7 @@ static int pamsnet_send_packet(struct sk_buff *skb, struct device *dev); static void pamsnet_poll_rx(struct device *); static int pamsnet_close(struct device *dev); -static struct enet_statistics *net_get_stats(struct device *dev); +static struct net_device_stats *net_get_stats(struct device *dev); static void pamsnet_tick(unsigned long); static void pamsnet_intr(int irq, void *data, struct pt_regs *fp); @@ -866,8 +866,8 @@ /* 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; } diff -u --recursive --new-file v2.1.24/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c --- v2.1.24/linux/drivers/net/atarilance.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/atarilance.c Sun Feb 2 15:18:36 1997 @@ -223,7 +223,7 @@ int dirty_tx; /* Ring entries to be freed. */ /* copy function */ void *(*memcpy_f)( void *, const void *, size_t ); - struct enet_statistics stats; + struct net_device_stats stats; /* These two must be ints for set_bit() */ int tx_full; int lock; @@ -346,7 +346,7 @@ static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp ); static int lance_rx( struct device *dev ); static int lance_close( struct device *dev ); -static struct enet_statistics *lance_get_stats( struct device *dev ); +static struct net_device_stats *lance_get_stats( struct device *dev ); static void set_multicast_list( struct device *dev ); static int lance_set_mac_address( struct device *dev, void *addr ); @@ -1072,7 +1072,7 @@ } -static 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.1.24/linux/drivers/net/atp.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/atp.c Sun Feb 2 15:18:36 1997 @@ -139,7 +139,7 @@ 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); @@ -747,8 +747,7 @@ /* 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/atp.h linux/drivers/net/atp.h --- v2.1.24/linux/drivers/net/atp.h Tue Oct 10 15:03:24 1995 +++ linux/drivers/net/atp.h Sun Feb 2 15:18:36 1997 @@ -2,12 +2,13 @@ #include #include -struct net_local { +struct net_local +{ #ifdef __KERNEL__ - struct enet_statistics stats; + struct net_device_stats stats; #endif - ushort saved_tx_size; - unsigned char + ushort saved_tx_size; + unsigned char re_tx, /* Number of packet retransmissions. */ tx_unit_busy, addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ @@ -15,10 +16,10 @@ }; struct rx_header { - ushort pad; /* The first read is always corrupted. */ - ushort rx_count; - ushort rx_status; /* Unknown bit assignments :-<. */ - ushort cur_addr; /* Apparently the current buffer address(?) */ + ushort pad; /* The first read is always corrupted. */ + ushort rx_count; + ushort rx_status; /* Unknown bit assignments :-<. */ + ushort cur_addr; /* Apparently the current buffer address(?) */ }; #define PAR_DATA 0 @@ -40,15 +41,16 @@ enum page0_regs { - /* The first six registers hold the ethernet physical station address. */ - PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, - TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ - TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ - ISR = 10, IMR = 11, /* Interrupt status and mask. */ - CMR1 = 12, /* Command register 1. */ - CMR2 = 13, /* Command register 2. */ - MAR = 14, /* Memory address register. */ - CMR2_h = 0x1d, }; + /* The first six registers hold the ethernet physical station address. */ + PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, + TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ + TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ + ISR = 10, IMR = 11, /* Interrupt status and mask. */ + CMR1 = 12, /* Command register 1. */ + CMR2 = 13, /* Command register 2. */ + MAR = 14, /* Memory address register. */ + CMR2_h = 0x1d, +}; enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ @@ -81,135 +83,139 @@ /* 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); + 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; + 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; + 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); + 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; + 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); + 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; + 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); + 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. */ + 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); + 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); + 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); + 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. */ + outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ } /* @@ -219,30 +225,32 @@ * 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. */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/bpqether.c linux/drivers/net/bpqether.c --- v2.1.24/linux/drivers/net/bpqether.c Thu Jan 2 15:55:17 1997 +++ linux/drivers/net/bpqether.c Sun Feb 2 15:18:36 1997 @@ -122,7 +122,7 @@ char ethname[14]; /* ether device name */ struct device *ethdev; /* link to ethernet device */ struct device axdev; /* bpq device (bpq#) */ - struct enet_statistics stats; /* some statistics */ + struct net_device_stats stats; /* some statistics */ char dest_addr[6]; /* ether destination address */ char acpt_addr[6]; /* accept ether frames from this address only */ } *bpq_devices = NULL; @@ -331,7 +331,7 @@ /* * Statistics */ -static struct enet_statistics *bpq_get_stats(struct device *dev) +static struct net_device_stats *bpq_get_stats(struct device *dev) { struct bpqdev *bpq; diff -u --recursive --new-file v2.1.24/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.1.24/linux/drivers/net/cs89x0.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/cs89x0.c Sun Feb 2 15:18:36 1997 @@ -0,0 +1,1182 @@ +/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* + Written 1996 by Russell Nelson, with reference to skeleton.c + written 1993-1994 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + The author may be reached at nelson@crynwr.com, Crynwr + Software, 11 Grant St., Potsdam, NY 13676 + + Changelog: + + Mike Cruse : mcruse@cti-ltd.com + : Changes for Linux 2.0 compatibility. + : Added dev_id parameter in net_interrupt(), + : request_irq() and free_irq(). Just NULL for now. + + Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros + : in net_open() and net_close() so kerneld would know + : that the module is in use and wouldn't eject the + : driver prematurely. + + Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c + : as an example. Disabled autoprobing in init_module(), + : not a good thing to do to other devices while Linux + : is running from all accounts. +*/ + +static char *version = +"cs89x0.c:v1.02 11/26/96 Russell Nelson \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 +#ifdef MODULE +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#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 + + +/* 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; +} + + + +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) + ; +} + + +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; +} + + +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; +} + +/* 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 */ + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS -c cs89x0.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * diff -u --recursive --new-file v2.1.24/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h --- v2.1.24/linux/drivers/net/cs89x0.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/cs89x0.h Sun Feb 2 15:18:36 1997 @@ -0,0 +1,456 @@ +/* Copyright, 1988-1992, Russell Nelson, Crynwr Software + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 1. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ + /* offset 2h -> Model/Product Number */ + /* offset 3h -> Chip Revision Number */ + +#define PP_ISAIOB 0x0020 /* IO base address */ +#define PP_CS8900_ISAINT 0x0022 /* ISA interrupt select */ +#define PP_CS8920_ISAINT 0x0370 /* ISA interrupt select */ +#define PP_CS8900_ISADMA 0x0024 /* ISA Rec DMA channel */ +#define PP_CS8920_ISADMA 0x0374 /* ISA Rec DMA channel */ +#define PP_ISASOF 0x0026 /* ISA DMA offset */ +#define PP_DmaFrameCnt 0x0028 /* ISA DMA Frame count */ +#define PP_DmaByteCnt 0x002A /* ISA DMA Byte count */ +#define PP_CS8900_ISAMemB 0x002C /* Memory base */ +#define PP_CS8920_ISAMemB 0x0348 /* */ + +#define PP_ISABootBase 0x0030 /* Boot Prom base */ +#define PP_ISABootMask 0x0034 /* Boot Prom Mask */ + +/* EEPROM data and command registers */ +#define PP_EECMD 0x0040 /* NVR Interface Command register */ +#define PP_EEData 0x0042 /* NVR Interface Data Register */ +#define PP_DebugReg 0x0044 /* Debug Register */ + +#define PP_RxCFG 0x0102 /* Rx Bus config */ +#define PP_RxCTL 0x0104 /* Receive Control Register */ +#define PP_TxCFG 0x0106 /* Transmit Config Register */ +#define PP_TxCMD 0x0108 /* Transmit Command Register */ +#define PP_BufCFG 0x010A /* Bus configuration Register */ +#define PP_LineCTL 0x0112 /* Line Config Register */ +#define PP_SelfCTL 0x0114 /* Self Command Register */ +#define PP_BusCTL 0x0116 /* ISA bus control Register */ +#define PP_TestCTL 0x0118 /* Test Register */ +#define PP_AutoNegCTL 0x011C /* Auto Negotiation Ctrl */ + +#define PP_ISQ 0x0120 /* Interrupt Status */ +#define PP_RxEvent 0x0124 /* Rx Event Register */ +#define PP_TxEvent 0x0128 /* Tx Event Register */ +#define PP_BufEvent 0x012C /* Bus Event Register */ +#define PP_RxMiss 0x0130 /* Receive Miss Count */ +#define PP_TxCol 0x0132 /* Transmit Collision Count */ +#define PP_LineST 0x0134 /* Line State Register */ +#define PP_SelfST 0x0136 /* Self State register */ +#define PP_BusST 0x0138 /* Bus Status */ +#define PP_TDR 0x013C /* Time Domain Reflectometry */ +#define PP_AutoNegST 0x013E /* Auto Neg Status */ +#define PP_TxCommand 0x0144 /* Tx Command */ +#define PP_TxLength 0x0146 /* Tx Length */ +#define PP_LAF 0x0150 /* Hash Table */ +#define PP_IA 0x0158 /* Physical Address Register */ + +#define PP_RxStatus 0x0400 /* Receive start of frame */ +#define PP_RxLength 0x0402 /* Receive Length of frame */ +#define PP_RxFrame 0x0404 /* Receive frame pointer */ +#define PP_TxFrame 0x0A00 /* Transmit frame pointer */ + +/* Primary I/O Base Address. If no I/O base is supplied by the user, then this */ +/* can be used as the default I/O base to access the PacketPage Area. */ +#define DEFAULTIOBASE 0x0300 +#define FIRST_IO 0x020C /* First I/O port to check */ +#define LAST_IO 0x037C /* Last I/O port to check (+10h) */ +#define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */ +#define ADD_SIG 0x3000 /* Expected ID signature */ + +#define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */ + +#ifdef IBMEIPKT +#define EISA_ID_SIG 0x4D24 /* IBM */ +#define PART_NO_SIG 0x1010 /* IBM */ +#define MONGOOSE_BIT 0x0000 /* IBM */ +#else +#define EISA_ID_SIG 0x630E /* PnP Vendor ID (same as chip id for Crystal board) */ +#define PART_NO_SIG 0x4000 /* ID code CS8920 board (PnP Vendor Product code) */ +#define MONGOOSE_BIT 0x2000 /* PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */ +#endif + +#define PRODUCT_ID_ADD 0x0002 /* Address of product ID */ + +/* Mask to find out the types of registers */ +#define REG_TYPE_MASK 0x001F + +/* Eeprom Commands */ +#define ERSE_WR_ENBL 0x00F0 +#define ERSE_WR_DISABLE 0x0000 + +/* Defines Control/Config register quintuplet numbers */ +#define RX_BUF_CFG 0x0003 +#define RX_CONTROL 0x0005 +#define TX_CFG 0x0007 +#define TX_COMMAND 0x0009 +#define BUF_CFG 0x000B +#define LINE_CONTROL 0x0013 +#define SELF_CONTROL 0x0015 +#define BUS_CONTROL 0x0017 +#define TEST_CONTROL 0x0019 + +/* Defines Status/Count registers quintuplet numbers */ +#define RX_EVENT 0x0004 +#define TX_EVENT 0x0008 +#define BUF_EVENT 0x000C +#define RX_MISS_COUNT 0x0010 +#define TX_COL_COUNT 0x0012 +#define LINE_STATUS 0x0014 +#define SELF_STATUS 0x0016 +#define BUS_STATUS 0x0018 +#define TDR 0x001C + +/* PP_RxCFG - Receive Configuration and Interrupt Mask bit definition - Read/write */ +#define SKIP_1 0x0040 +#define RX_STREAM_ENBL 0x0080 +#define RX_OK_ENBL 0x0100 +#define RX_DMA_ONLY 0x0200 +#define AUTO_RX_DMA 0x0400 +#define BUFFER_CRC 0x0800 +#define RX_CRC_ERROR_ENBL 0x1000 +#define RX_RUNT_ENBL 0x2000 +#define RX_EXTRA_DATA_ENBL 0x4000 + +/* PP_RxCTL - Receive Control bit definition - Read/write */ +#define RX_IA_HASH_ACCEPT 0x0040 +#define RX_PROM_ACCEPT 0x0080 +#define RX_OK_ACCEPT 0x0100 +#define RX_MULTCAST_ACCEPT 0x0200 +#define RX_IA_ACCEPT 0x0400 +#define RX_BROADCAST_ACCEPT 0x0800 +#define RX_BAD_CRC_ACCEPT 0x1000 +#define RX_RUNT_ACCEPT 0x2000 +#define RX_EXTRA_DATA_ACCEPT 0x4000 +#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT) +/* Default receive mode - individually addressed, broadcast, and error free */ +#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT) + +/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */ +#define TX_LOST_CRS_ENBL 0x0040 +#define TX_SQE_ERROR_ENBL 0x0080 +#define TX_OK_ENBL 0x0100 +#define TX_LATE_COL_ENBL 0x0200 +#define TX_JBR_ENBL 0x0400 +#define TX_ANY_COL_ENBL 0x0800 +#define TX_16_COL_ENBL 0x8000 + +/* PP_TxCMD - Transmit Command bit definition - Read-only */ +#define TX_START_4_BYTES 0x0000 +#define TX_START_64_BYTES 0x0040 +#define TX_START_128_BYTES 0x0080 +#define TX_START_ALL_BYTES 0x00C0 +#define TX_FORCE 0x0100 +#define TX_ONE_COL 0x0200 +#define TX_TWO_PART_DEFF_DISABLE 0x0400 +#define TX_NO_CRC 0x1000 +#define TX_RUNT 0x2000 + +/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */ +#define GENERATE_SW_INTERRUPT 0x0040 +#define RX_DMA_ENBL 0x0080 +#define READY_FOR_TX_ENBL 0x0100 +#define TX_UNDERRUN_ENBL 0x0200 +#define RX_MISS_ENBL 0x0400 +#define RX_128_BYTE_ENBL 0x0800 +#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000 +#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000 +#define RX_DEST_MATCH_ENBL 0x8000 + +/* PP_LineCTL - Line Control bit definition - Read/write */ +#define SERIAL_RX_ON 0x0040 +#define SERIAL_TX_ON 0x0080 +#define AUI_ONLY 0x0100 +#define AUTO_AUI_10BASET 0x0200 +#define MODIFIED_BACKOFF 0x0800 +#define NO_AUTO_POLARITY 0x1000 +#define TWO_PART_DEFDIS 0x2000 +#define LOW_RX_SQUELCH 0x4000 + +/* PP_SelfCTL - Software Self Control bit definition - Read/write */ +#define POWER_ON_RESET 0x0040 +#define SW_STOP 0x0100 +#define SLEEP_ON 0x0200 +#define AUTO_WAKEUP 0x0400 +#define HCB0_ENBL 0x1000 +#define HCB1_ENBL 0x2000 +#define HCB0 0x4000 +#define HCB1 0x8000 + +/* PP_BusCTL - ISA Bus Control bit definition - Read/write */ +#define RESET_RX_DMA 0x0040 +#define MEMORY_ON 0x0400 +#define DMA_BURST_MODE 0x0800 +#define IO_CHANNEL_READY_ON 0x1000 +#define RX_DMA_SIZE_64K 0x2000 +#define ENABLE_IRQ 0x8000 + +/* PP_TestCTL - Test Control bit definition - Read/write */ +#define LINK_OFF 0x0080 +#define ENDEC_LOOPBACK 0x0200 +#define AUI_LOOPBACK 0x0400 +#define BACKOFF_OFF 0x0800 +#define FAST_TEST 0x8000 + +/* PP_RxEvent - Receive Event Bit definition - Read-only */ +#define RX_IA_HASHED 0x0040 +#define RX_DRIBBLE 0x0080 +#define RX_OK 0x0100 +#define RX_HASHED 0x0200 +#define RX_IA 0x0400 +#define RX_BROADCAST 0x0800 +#define RX_CRC_ERROR 0x1000 +#define RX_RUNT 0x2000 +#define RX_EXTRA_DATA 0x4000 + +#define HASH_INDEX_MASK 0x0FC00 + +/* PP_TxEvent - Transmit Event Bit definition - Read-only */ +#define TX_LOST_CRS 0x0040 +#define TX_SQE_ERROR 0x0080 +#define TX_OK 0x0100 +#define TX_LATE_COL 0x0200 +#define TX_JBR 0x0400 +#define TX_16_COL 0x8000 +#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS) +#define TX_COL_COUNT_MASK 0x7800 + +/* PP_BufEvent - Buffer Event Bit definition - Read-only */ +#define SW_INTERRUPT 0x0040 +#define RX_DMA 0x0080 +#define READY_FOR_TX 0x0100 +#define TX_UNDERRUN 0x0200 +#define RX_MISS 0x0400 +#define RX_128_BYTE 0x0800 +#define TX_COL_OVRFLW 0x1000 +#define RX_MISS_OVRFLW 0x2000 +#define RX_DEST_MATCH 0x8000 + +/* PP_LineST - Ethernet Line Status bit definition - Read-only */ +#define LINK_OK 0x0080 +#define AUI_ON 0x0100 +#define TENBASET_ON 0x0200 +#define POLARITY_OK 0x1000 +#define CRS_OK 0x4000 + +/* PP_SelfST - Chip Software Status bit definition */ +#define ACTIVE_33V 0x0040 +#define INIT_DONE 0x0080 +#define SI_BUSY 0x0100 +#define EEPROM_PRESENT 0x0200 +#define EEPROM_OK 0x0400 +#define EL_PRESENT 0x0800 +#define EE_SIZE_64 0x1000 + +/* PP_BusST - ISA Bus Status bit definition */ +#define TX_BID_ERROR 0x0080 +#define READY_FOR_TX_NOW 0x0100 + +/* PP_AutoNegCTL - Auto Negotiation Control bit definition */ +#define RE_NEG_NOW 0x0040 +#define ALLOW_FDX 0x0080 +#define AUTO_NEG_ENABLE 0x0100 +#define NLP_ENABLE 0x0200 +#define FORCE_FDX 0x8000 +#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE) +#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW) + +/* PP_AutoNegST - Auto Negotiation Status bit definition */ +#define AUTO_NEG_BUSY 0x0080 +#define FLP_LINK 0x0100 +#define FLP_LINK_GOOD 0x0800 +#define LINK_FAULT 0x1000 +#define HDX_ACTIVE 0x4000 +#define FDX_ACTIVE 0x8000 + +/* The following block defines the ISQ event types */ +#define ISQ_RECEIVER_EVENT 0x04 +#define ISQ_TRANSMITTER_EVENT 0x08 +#define ISQ_BUFFER_EVENT 0x0c +#define ISQ_RX_MISS_EVENT 0x10 +#define ISQ_TX_COL_EVENT 0x12 + +#define ISQ_EVENT_MASK 0x003F /* ISQ mask to find out type of event */ +#define ISQ_HIST 16 /* small history buffer */ +#define AUTOINCREMENT 0x8000 /* Bit mask to set bit-15 for autoincrement */ + +#define TXRXBUFSIZE 0x0600 +#define RXDMABUFSIZE 0x8000 +#define RXDMASIZE 0x4000 +#define TXRX_LENGTH_MASK 0x07FF + +/* rx options bits */ +#define RCV_WITH_RXON 1 /* Set SerRx ON */ +#define RCV_COUNTS 2 /* Use Framecnt1 */ +#define RCV_PONG 4 /* Pong respondent */ +#define RCV_DONG 8 /* Dong operation */ +#define RCV_POLLING 0x10 /* Poll RxEvent */ +#define RCV_ISQ 0x20 /* Use ISQ, int */ +#define RCV_AUTO_DMA 0x100 /* Set AutoRxDMAE */ +#define RCV_DMA 0x200 /* Set RxDMA only */ +#define RCV_DMA_ALL 0x400 /* Copy all DMA'ed */ +#define RCV_FIXED_DATA 0x800 /* Every frame same */ +#define RCV_IO 0x1000 /* Use ISA IO only */ +#define RCV_MEMORY 0x2000 /* Use ISA Memory */ + +#define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ +#define PKT_START PP_TxFrame /* Start of packet RAM */ + +#define RX_FRAME_PORT 0x0000 +#define TX_FRAME_PORT RX_FRAME_PORT +#define TX_CMD_PORT 0x0004 +#define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ +#define TX_AFTER_381 0x0020 /* Tx packet after 381 bytes copied */ +#define TX_AFTER_ALL 0x0060 /* Tx packet after all bytes copied */ +#define TX_LEN_PORT 0x0006 +#define ISQ_PORT 0x0008 +#define ADD_PORT 0x000A +#define DATA_PORT 0x000C + +#define EEPROM_WRITE_EN 0x00F0 +#define EEPROM_WRITE_DIS 0x0000 +#define EEPROM_WRITE_CMD 0x0100 +#define EEPROM_READ_CMD 0x0200 + +/* Receive Header */ +/* Description of header of each packet in receive area of memory */ +#define RBUF_EVENT_LOW 0 /* Low byte of RxEvent - status of received frame */ +#define RBUF_EVENT_HIGH 1 /* High byte of RxEvent - status of received frame */ +#define RBUF_LEN_LOW 2 /* Length of received data - low byte */ +#define RBUF_LEN_HI 3 /* Length of received data - high byte */ +#define RBUF_HEAD_LEN 4 /* Length of this header */ + +#define CHIP_READ 0x1 /* Used to mark state of the repins code (chip or dma) */ +#define DMA_READ 0x2 /* Used to mark state of the repins code (chip or dma) */ + +/* for bios scan */ +/* */ +#ifdef CSDEBUG +/* use these values for debugging bios scan */ +#define BIOS_START_SEG 0x00000 +#define BIOS_OFFSET_INC 0x0010 +#else +#define BIOS_START_SEG 0x0c000 +#define BIOS_OFFSET_INC 0x0200 +#endif + +#define BIOS_LAST_OFFSET 0x0fc00 + +/* Byte offsets into the EEPROM configuration buffer */ +#define ISA_CNF_OFFSET 0x6 +#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8) /* 8900 eeprom */ +#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8) /* 8920 eeprom */ + + /* the assumption here is that the bits in the eeprom are generally */ + /* in the same position as those in the autonegctl register. */ + /* Of course the IMM bit is not in that register so it must be */ + /* masked out */ +#define EE_FORCE_FDX 0x8000 +#define EE_NLP_ENABLE 0x0200 +#define EE_AUTO_NEG_ENABLE 0x0100 +#define EE_ALLOW_FDX 0x0080 +#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX) + +#define IMM_BIT 0x0040 /* ignore missing media */ + +#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2) +#define A_CNF_10B_T 0x0001 +#define A_CNF_AUI 0x0002 +#define A_CNF_10B_2 0x0004 +#define A_CNF_MEDIA_TYPE 0x0060 +#define A_CNF_MEDIA_AUTO 0x0000 +#define A_CNF_MEDIA_10B_T 0x0020 +#define A_CNF_MEDIA_AUI 0x0040 +#define A_CNF_MEDIA_10B_2 0x0060 +#define A_CNF_DC_DC_POLARITY 0x0080 +#define A_CNF_NO_AUTO_POLARITY 0x2000 +#define A_CNF_LOW_RX_SQUELCH 0x4000 +#define A_CNF_EXTND_10B_2 0x8000 + +#define PACKET_PAGE_OFFSET 0x8 + +/* Bit definitions for the ISA configuration word from the EEPROM */ +#define INT_NO_MASK 0x000F +#define DMA_NO_MASK 0x0070 +#define ISA_DMA_SIZE 0x0200 +#define ISA_AUTO_RxDMA 0x0400 +#define ISA_RxDMA 0x0800 +#define DMA_BURST 0x1000 +#define STREAM_TRANSFER 0x2000 +#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA) + +/* DMA controller registers */ +#define DMA_BASE 0x00 /* DMA controller base */ +#define DMA_BASE_2 0x0C0 /* DMA controller base */ + +#define DMA_STAT 0x0D0 /* DMA controller status register */ +#define DMA_MASK 0x0D4 /* DMA controller mask register */ +#define DMA_MODE 0x0D6 /* DMA controller mode register */ +#define DMA_RESETFF 0x0D8 /* DMA controller first/last flip flop */ + +/* DMA data */ +#define DMA_DISABLE 0x04 /* Disable channel n */ +#define DMA_ENABLE 0x00 /* Enable channel n */ +/* Demand transfers, incr. address, auto init, writes, ch. n */ +#define DMA_RX_MODE 0x14 +/* Demand transfers, incr. address, auto init, reads, ch. n */ +#define DMA_TX_MODE 0x18 + +#define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */ + +#define CS8900 0x0000 +#define CS8920 0x4000 +#define CS8920M 0x6000 +#define REVISON_BITS 0x1F00 +#define EEVER_NUMBER 0x12 +#define CHKSUM_LEN 0x14 +#define CHKSUM_VAL 0x0000 +#define START_EEPROM_DATA 0x001c /* Offset into eeprom for start of data */ +#define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */ +#define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */ +#define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */ +#define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */ + +#define CS8920_NO_INTS 0x0F /* Max CS8920 interrupt select # */ + +#define PNP_ADD_PORT 0x0279 +#define PNP_WRITE_PORT 0x0A79 + +#define GET_PNP_ISA_STRUCT 0x40 +#define PNP_ISA_STRUCT_LEN 0x06 +#define PNP_CSN_CNT_OFF 0x01 +#define PNP_RD_PORT_OFF 0x02 +#define PNP_FUNCTION_OK 0x00 +#define PNP_WAKE 0x03 +#define PNP_RSRC_DATA 0x04 +#define PNP_RSRC_READY 0x01 +#define PNP_STATUS 0x05 +#define PNP_ACTIVATE 0x30 +#define PNP_CNF_IO_H 0x60 +#define PNP_CNF_IO_L 0x61 +#define PNP_CNF_INT 0x70 +#define PNP_CNF_DMA 0x74 +#define PNP_CNF_MEM 0x48 + +#define BIT0 1 +#define BIT15 0x8000 + diff -u --recursive --new-file v2.1.24/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.24/linux/drivers/net/de4x5.c Thu Jan 2 15:55:18 1997 +++ linux/drivers/net/de4x5.c Sun Feb 2 15:18:37 1997 @@ -1,12 +1,13 @@ -/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE450/DE500 ethernet driver for Linux. +/* de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500 + ethernet driver for Linux. Copyright 1994, 1995 Digital Equipment Corporation. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. - This driver is written for the Digital Equipment Corporation series - of EtherWORKS ethernet cards: + Originally, this driver was written for the Digital Equipment + Corporation series of EtherWORKS ethernet cards: DE425 TP/COAX EISA DE434 TP PCI @@ -14,6 +15,24 @@ 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: @@ -32,9 +51,11 @@ 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 @@ -46,49 +67,42 @@ 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 @@ -99,13 +113,7 @@ 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 @@ -126,6 +134,17 @@ 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 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: ------ @@ -134,7 +153,7 @@ ---------------- 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. @@ -143,7 +162,7 @@ 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 . @@ -172,7 +191,7 @@ 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 : @@ -199,30 +218,40 @@ 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 and + reported by and . Add cache locks to prevent a race condition as - reported by and + reported by and . Upgraded alloc_device() code. 0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion with 0.44 13-Aug-96 Fix RX overflow bug in 2114[023] chips. Fix EISA probe bugs reported by - and + and . 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 - 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 . 0.451 28-Dec-96 Added fix to allow autoprobe for modules after - suggestion from + suggestion from . + 0.5 30-Jan-97 Added SROM decoding functions. + Updated debug flags. + Fix sleep/wakeup calls for PCI cards, bug reported + by . + Added multi-MAC, one SROM feature from discussion + with . + 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 @@ -280,6 +309,12 @@ int value; } spd; int addr; /* MII address for the PHY */ + u_char *gep; /* Start of GEP sequence block in SROM */ + u_char *rst; /* Start of reset sequence in SROM */ + u_int mc; /* Media Capabilities */ + u_int ana; /* NWay Advertisement */ + u_int fdx; /* Full DupleX capabilites for each media */ + u_int ttm; /* Transmit Threshold Mode for each media */ }; #define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */ @@ -306,11 +341,23 @@ #define SMC 1 #define ACCTON 2 +/* +** SROM Repair definitions. If a broken SROM is detected a card may +** use this information to help figure out what to do. This is a +** "stab in the dark" and so far for SMC9332's only. +*/ +static c_char srom_repair_info[][100] = { + {0x00,0x1e,0x00,0x00,0x00,0x08, /* SMC9332 */ + 0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02, + 0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50, + 0x00,0x18,} +}; + #ifdef DE4X5_DEBUG static int de4x5_debug = DE4X5_DEBUG; #else -static int de4x5_debug = 1; +static int de4x5_debug = (0); #endif #ifdef DE4X5_AUTOSENSE /* Should be done on a per adapter basis */ @@ -374,7 +421,7 @@ ** Memory Alignment. Each descriptor is 4 longwords long. To force a ** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and ** DESC_ALIGN. ALIGN aligns the start address of the private memory area -** and hence the RX descriptor ring's first entry. +** and hence the RX descriptor ring's first entry. */ #define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ #define ALIGN8 ((u_long)8 - 1) /* 2 longword align */ @@ -455,7 +502,7 @@ char id_block_crc; char reserved2; char version; - char num_adapters; + char num_controllers; char ieee_addr[6]; char info[100]; short chksum; @@ -500,7 +547,7 @@ int tx_new, tx_old; /* TX descriptor ring pointers */ char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */ char frame[64]; /* Min sized packet for loopback*/ - struct enet_statistics stats; /* Public stats */ + struct net_device_stats stats; /* Public stats */ struct { u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */ u_int unicast; @@ -518,16 +565,17 @@ char txRingSize; int bus; /* EISA or PCI */ int bus_num; /* PCI Bus number */ + int device; /* Device number on PCI bus */ int state; /* Adapter OPENED or CLOSED */ int chipset; /* DC21040, DC21041 or DC21140 */ s32 irq_mask; /* Interrupt Mask (Enable) bits */ s32 irq_en; /* Summary interrupt bits */ int media; /* Media (eg TP), mode (eg 100B)*/ int c_media; /* Remember the last media conn */ + int fdx; /* media full duplex flag */ int linkOK; /* Link is OK */ int autosense; /* Allow/disallow autosensing */ int tx_enable; /* Enable descriptor polling */ - int lostMedia; /* Possibly lost media */ int setup_f; /* Setup frame filtering type */ int local_state; /* State within a 'media' state */ struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */ @@ -543,13 +591,31 @@ s32 csr0; /* Saved Bus Mode Register */ s32 csr6; /* Saved Operating Mode Reg. */ s32 csr7; /* Saved IRQ Mask Register */ + s32 gep; /* Saved General Purpose Reg. */ + s32 gepc; /* Control info for GEP */ s32 csr13; /* Saved SIA Connectivity Reg. */ s32 csr14; /* Saved SIA TX/RX Register */ s32 csr15; /* Saved SIA General Register */ int save_cnt; /* Flag if state already saved */ struct sk_buff *skb; /* Save the (re-ordered) skb's */ } cache; + struct de4x5_srom srom; /* A copy of the SROM */ + struct device *next_module; /* Link to the next module */ int rx_ovf; /* Check for 'RX overflow' tag */ + int useSROM; /* For non-DEC card use SROM */ + int useMII; /* Infoblock using the MII */ + int asBitValid; /* Autosense bits in GEP? */ + int asPolarity; /* 0 => asserted high */ + int asBit; /* Autosense bit number in GEP */ + int defMedium; /* SROM default medium */ + int tcount; /* Last infoblock number */ + int infoblock_init; /* Initialised this infoblock? */ + int infoleaf_offset; /* SROM infoleaf for controller */ + s32 infoblock_csr6; /* csr6 value in SROM infoblock */ + int infoblock_media; /* infoblock media */ + int (*infoleaf_fn)(struct device *); /* Pointer to infoleaf function */ + u_char *rst; /* Pointer to Type 5 reset info */ + u_char ibn; /* Infoblock number */ }; /* @@ -564,9 +630,29 @@ 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: ** tx_old = tx_new Empty ring @@ -586,7 +672,7 @@ static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev); static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int de4x5_close(struct device *dev); -static struct enet_statistics *de4x5_get_stats(struct device *dev); +static struct net_device_stats *de4x5_get_stats(struct device *dev); static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len); static void set_multicast_list(struct device *dev); static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd); @@ -611,6 +697,7 @@ static int dc21040_autoconf(struct device *dev); static int dc21041_autoconf(struct device *dev); static int dc21140m_autoconf(struct device *dev); +static int srom_autoconf(struct device *dev); static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *)); static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int)); static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec); @@ -648,6 +735,10 @@ /*static void srom_busy(u_int command, u_long address);*/ static void sendto_srom(u_int command, u_long addr); static int getfrom_srom(u_long addr); +static void srom_map_media(struct device *dev); +static int srom_infoleaf_info(struct device *dev); +static void srom_init(struct device *dev); +static void srom_exec(struct device *dev, u_char *p); static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr); static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr); static int mii_rdata(u_long ioaddr); @@ -661,6 +752,8 @@ static int mii_get_phy(struct device *dev); static void SetMulticastFilter(struct device *dev); static int get_hw_addr(struct device *dev); +static void srom_repair(struct device *dev, int card); +static int test_bad_enet(struct device *dev, int status); static void eisa_probe(struct device *dev, u_long iobase); static void pci_probe(struct device *dev, u_long iobase); @@ -670,16 +763,29 @@ static char *build_setup_frame(struct device *dev, int mode); static void disable_ast(struct device *dev); static void enable_ast(struct device *dev, u32 time_out); -static long de4x5_switch_to_srl(struct device *dev); -static long de4x5_switch_to_mii(struct device *dev); +static long de4x5_switch_mac_port(struct device *dev); static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec); +static void yawn(struct device *dev, int state); static int de4x5_dev_index(char *s); +static void link_modules(struct device *dev, struct device *tmp); +static struct device *unlink_modules(struct device *p); static void de4x5_dbg_open(struct device *dev); static void de4x5_dbg_mii(struct device *dev, int k); static void de4x5_dbg_media(struct device *dev); static void de4x5_dbg_srom(struct de4x5_srom *p); static void de4x5_dbg_rx(struct sk_buff *skb, int len); static int de4x5_strncmp(char *a, char *b, int n); +static int dc21041_infoleaf(struct device *dev); +static int dc21140_infoleaf(struct device *dev); +static int dc21142_infoleaf(struct device *dev); +static int dc21143_infoleaf(struct device *dev); +static int type0_infoblock(struct device *dev, u_char count, u_char *p); +static int type1_infoblock(struct device *dev, u_char count, u_char *p); +static int type2_infoblock(struct device *dev, u_char count, u_char *p); +static int type3_infoblock(struct device *dev, u_char count, u_char *p); +static int type4_infoblock(struct device *dev, u_char count, u_char *p); +static int type5_infoblock(struct device *dev, u_char count, u_char *p); +static int compact_infoblock(struct device *dev, u_char count, u_char *p); #ifdef MODULE int init_module(void); @@ -692,7 +798,37 @@ static char name[DE4X5_NAME_LENGTH + 1]; static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; static int num_de4x5s = 0, num_eth = 0; -static int cfrv = 0; +static int cfrv = 0, useSROM = 0; + +/* +** List the SROM infoleaf functions and chipsets +*/ +struct InfoLeaf { + int chipset; + int (*fn)(struct device *); +}; +struct InfoLeaf infoleaf_array[] = { + {DC21041, dc21041_infoleaf}, + {DC21140, dc21140_infoleaf}, + {DC21142, dc21142_infoleaf}, + {DC21143, dc21143_infoleaf} +}; +#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *))) + +/* +** List the SROM info block functions +*/ +static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = { + type0_infoblock, + type1_infoblock, + type2_infoblock, + type3_infoblock, + type4_infoblock, + type5_infoblock, + compact_infoblock +}; + +#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1) /* ** Miscellaneous defines... @@ -709,6 +845,13 @@ 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 */\ +} + /* ** Autoprobing in modules is allowed here. See the top of the file for @@ -718,23 +861,18 @@ int de4x5_probe(struct device *dev) { - int tmp = num_de4x5s, status = -ENODEV; + int status = -ENODEV; u_long iobase = dev->base_addr; eisa_probe(dev, iobase); pci_probe(dev, iobase); - - if ((tmp == num_de4x5s) && (iobase != 0) && loading_module) { - printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name, - iobase); - } - + /* ** Walk the device list to check that at least one device ** initialised OK */ for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); - + if (dev->priv) status = 0; if (iobase == 0) autoprobed = 1; @@ -745,70 +883,70 @@ de4x5_hw_init(struct device *dev, u_long iobase) { struct bus_type *lp = &bus; - int tmpbus, tmpchs, status=0; - int i, media = *((char *)&(lp->srom) + *((char *)&(lp->srom) + 19) * 3); + int i, status=0; char *tmp; - + /* Ensure we're not sleeping */ - if (lp->chipset == DC21041) { - outl(0, PCI_CFDA); - de4x5_ms_delay(10); + if (lp->bus == EISA) { + outb(WAKEUP, PCI_CFPM); + } else { + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, WAKEUP); } - + de4x5_ms_delay(10); + RESET_DE4X5; - + if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) { return -ENXIO; /* Hardware could not reset */ } - - /* + + /* ** Now find out what kind of DC21040/DC21041/DC21140 board we have. */ + useSROM = FALSE; if (lp->bus == PCI) { PCI_signature(name, lp); } else { EISA_signature(name, EISA_ID0); } - + if (*name == '\0') { /* Not found a board signature */ return -ENXIO; } - + dev->base_addr = iobase; if (lp->bus == EISA) { - printk("%s: %s at 0x%04lx (EISA slot %ld)", + printk("%s: %s at 0x%04lx (EISA slot %ld)", dev->name, name, iobase, ((iobase>>12)&0x0f)); } else { /* PCI port address */ printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name, iobase, lp->bus_num, lp->device); } - + printk(", h/w address "); status = get_hw_addr(dev); for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ printk("%2.2x:", dev->dev_addr[i]); } printk("%2.2x,\n", dev->dev_addr[i]); - - tmpbus = lp->bus; - tmpchs = lp->chipset; - + if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; } else { struct de4x5_private *lp; - - /* + + /* ** Reserve a section of kernel memory for the adapter ** private area and the TX/RX descriptor rings. */ - dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, + dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, GFP_KERNEL); if (dev->priv == NULL) { return -ENOMEM; } - + /* ** Align to a longword boundary */ @@ -816,26 +954,20 @@ dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN); lp = (struct de4x5_private *)dev->priv; memset(dev->priv, 0, sizeof(struct de4x5_private)); - lp->bus = tmpbus; - lp->chipset = tmpchs; + lp->bus = bus.bus; + lp->bus_num = bus.bus_num; + lp->device = bus.device; + lp->chipset = bus.chipset; lp->cache.priv = tmp; - - /* - ** Check for an MII interface - */ - if (media & MEDIA_MII) { /* MII interface? */ - if (!mii_get_phy(dev)) { - printk("%s: MII search failed, no device found when one was expected\n", dev->name); - return -ENXIO; - } - } else { - mii_get_phy(dev); /* Search the MII anyway! */ - } + lp->cache.gepc = GEP_INIT; + lp->timeout = -1; + lp->useSROM = useSROM; + memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom)); /* ** Choose correct autosensing in case someone messed up */ - if (de4x5_autosense & AUTO) { + if ((de4x5_autosense & AUTO) || lp->useSROM) { lp->autosense = AUTO; } else { if (lp->chipset != DC21140) { @@ -850,12 +982,12 @@ 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; icache.priv); return -ENOMEM; @@ -885,22 +1017,22 @@ #endif barrier(); - + request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE), + DE4X5_EISA_TOTAL_SIZE), lp->adapter_name); - + lp->rxRingSize = NUM_RX_DESC; lp->txRingSize = NUM_TX_DESC; - + /* Write the end of list marker to the descriptor lists */ lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER); lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER); - + /* Tell the adapter where the TX/RX rings are located. */ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - + /* Initialise the IRQ mask and Enable/Disable */ lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM; lp->irq_en = IMR_NIM | IMR_AIM; @@ -909,23 +1041,40 @@ create_packet(dev, lp->frame, sizeof(lp->frame)); /* Check if the RX overflow bug needs testing for */ - tmpchs = cfrv & 0x000000fe; - if ((lp->chipset == DC21140) && (tmpchs == 0x20)) { + i = cfrv & 0x000000fe; + if ((lp->chipset == DC21140) && (i == 0x20)) { lp->rx_ovf = 1; } - /* Initialise the adapter state */ + /* Initialise the SROM pointers if possible */ + if (lp->useSROM) { + lp->state = INITIALISED; + de4x5_dbg_srom((struct de4x5_srom *)&lp->srom); + if (srom_infoleaf_info(dev)) { + return -ENXIO; + } + srom_init(dev); + } + lp->state = CLOSED; + /* + ** Check for an MII interface + */ + if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) { + mii_get_phy(dev); + } + printk(" and requires IRQ%d (provided by %s).\n", dev->irq, ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); + printk("INFOLEAF_SIZE: %d\nCOMPACT: %d\n", INFOLEAF_SIZE, COMPACT); } - - if (de4x5_debug > 1) { + + if (de4x5_debug & DEBUG_VERSION) { printk(version); } - + /* The DE4X5-specific entries in the device structure. */ dev->open = &de4x5_open; dev->hard_start_xmit = &de4x5_queue_pkt; @@ -933,18 +1082,15 @@ dev->get_stats = &de4x5_get_stats; dev->set_multicast_list = &set_multicast_list; dev->do_ioctl = &de4x5_ioctl; - + dev->mem_start = 0; - - /* Fill in the generic field of the device structure. */ + + /* Fill in the generic fields of the device structure. */ ether_setup(dev); - + /* Let the adapter sleep to save power */ - if (lp->chipset == DC21041) { - outl(0, DE4X5_SICR); - outl(CFDA_PSM, PCI_CFDA); - } - + yawn(dev, SLEEP); + return status; } @@ -956,7 +1102,7 @@ u_long iobase = dev->base_addr; int i, status = 0; s32 omr; - + /* Allocate the RX buffers */ for (i=0; irxRingSize; i++) { if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) { @@ -968,35 +1114,32 @@ /* ** Wake up the adapter */ - if (lp->chipset == DC21041) { - outl(0, PCI_CFDA); - de4x5_ms_delay(10); - } + yawn(dev, WAKEUP); - /* - ** Re-initialize the DE4X5... + /* + ** Re-initialize the DE4X5... */ status = de4x5_init(dev); - + lp->state = OPEN; de4x5_dbg_open(dev); - - if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, + + if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, lp->adapter_name, dev)) { printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq); status = -EAGAIN; } else { - dev->tbusy = 0; + dev->tbusy = 0; dev->start = 1; dev->interrupt = UNMASK_INTERRUPTS; dev->trans_start = jiffies; - + START_DE4X5; - + de4x5_setup_intr(dev); } - - if (de4x5_debug > 1) { + + if (de4x5_debug & DEBUG_OPEN) { printk("\tsts: 0x%08x\n", inl(DE4X5_STS)); printk("\tbmr: 0x%08x\n", inl(DE4X5_BMR)); printk("\timr: 0x%08x\n", inl(DE4X5_IMR)); @@ -1006,9 +1149,9 @@ printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR)); printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR)); } - + MOD_INC_USE_COUNT; - + return status; } @@ -1022,15 +1165,15 @@ */ static int de4x5_init(struct device *dev) -{ +{ /* Lock out other processes whilst setting up the hardware */ set_bit(0, (void *)&dev->tbusy); - + de4x5_sw_reset(dev); - + /* Autoconfigure the connected port */ autoconf_media(dev); - + return 0; } @@ -1041,22 +1184,25 @@ u_long iobase = dev->base_addr; int i, j, status = 0; s32 bmr, omr; - + /* Select the MII or SRL port now and RESET the MAC */ - if (lp->phy[lp->active].id == 0) { - de4x5_switch_to_srl(dev); - } else { - de4x5_switch_to_mii(dev); + if (!lp->useSROM) { + if (lp->phy[lp->active].id != 0) { + lp->infoblock_csr6 = OMR_PS | OMR_HBD; + } else { + lp->infoblock_csr6 = OMR_TTM; + } + de4x5_switch_mac_port(dev); } - /* + /* ** Set the programmable burst length to 8 longwords for all the DC21140 ** Fasternet chips and 4 longwords for all others: DMA errors result ** without these values. Cache align 16 long. */ bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN; outl(bmr, DE4X5_BMR); - + omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn off promiscuous mode */ if (lp->chipset == DC21140) { omr |= (OMR_SDP | OMR_SB); @@ -1064,26 +1210,26 @@ lp->setup_f = PERFECT; outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - + lp->rx_new = lp->rx_old = 0; lp->tx_new = lp->tx_old = 0; - + for (i = 0; i < lp->rxRingSize; i++) { lp->rx_ring[i].status = cpu_to_le32(R_OWN); } - + for (i = 0; i < lp->txRingSize; i++) { lp->tx_ring[i].status = cpu_to_le32(0); } - + barrier(); - + /* Build the setup frame depending on filtering mode */ SetMulticastFilter(dev); - + load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL); outl(omr|OMR_ST, DE4X5_OMR); - + /* Poll for setup frame completion (adapter interrupts are disabled now) */ sti(); /* Ensure timer interrupts */ for (j=0, i=0;(i<500) && (j==0);i++) { /* Upto 500ms delay */ @@ -1091,20 +1237,20 @@ if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1; } outl(omr, DE4X5_OMR); /* Stop everything! */ - + if (j == 0) { - printk("%s: Setup frame timed out, status %08x\n", dev->name, + printk("%s: Setup frame timed out, status %08x\n", dev->name, inl(DE4X5_STS)); status = -EIO; } - + lp->tx_new = (++lp->tx_new) % lp->txRingSize; lp->tx_old = lp->tx_new; - + return status; } -/* +/* ** Writes a socket buffer address to the next available transmit descriptor */ static int @@ -1121,9 +1267,9 @@ set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */ if (lp->tx_enable == NO) { /* Cannot send for now */ - return -1; + return -1; } - + /* ** Clean out the TX ring asynchronously to interrupts - sometimes the ** interrupts are lost by delayed descriptor status updates relative to @@ -1143,8 +1289,8 @@ } else { de4x5_put_cache(dev, skb); } - if (de4x5_debug > 1) { - printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n lostMedia:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); + if (de4x5_debug & DEBUG_TX) { + printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); } } else if (skb->len > 0) { /* If we already have stuff queued locally, use that first */ @@ -1158,10 +1304,10 @@ set_bit(0, (void*)&dev->tbusy); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ - + lp->tx_new = (++lp->tx_new) % lp->txRingSize; dev->trans_start = jiffies; - + if (TX_BUFFS_AVAIL) { dev->tbusy = 0; /* Another pkt may be queued */ } @@ -1170,15 +1316,15 @@ } if (skb) de4x5_putb_cache(dev, skb); } - + lp->cache.lock = 0; return status; } /* -** The DE4X5 interrupt handler. -** +** The DE4X5 interrupt handler. +** ** I/O Read/Writes through intermediate PCI bridges are never 'posted', ** so that the asserted interrupt always has some real data to work with - ** if these I/O accesses are ever changed to memory accesses, ensure the @@ -1194,41 +1340,40 @@ struct de4x5_private *lp; s32 imr, omr, sts, limit; u_long iobase; - + if (dev == NULL) { printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq); return; } lp = (struct de4x5_private *)dev->priv; iobase = dev->base_addr; - + if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); - + DISABLE_IRQs; /* Ensure non re-entrancy */ dev->interrupt = MASK_INTERRUPTS; - + for (limit=0; limit<8; limit++) { sts = inl(DE4X5_STS); /* Read IRQ status */ outl(sts, DE4X5_STS); /* Reset the board interrupts */ - + if (!(sts & lp->irq_mask)) break;/* All done */ - + if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */ de4x5_rx(dev); - + if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */ - de4x5_tx(dev); - + de4x5_tx(dev); + if (sts & STS_LNF) { /* TP Link has failed */ - lp->lostMedia = LOST_MEDIA_THRESHOLD + 1; lp->irq_mask &= ~IMR_LFM; } - + if (sts & STS_UNF) { /* Transmit underrun */ de4x5_txur(dev); } - + if (sts & STS_SE) { /* Bus Error */ STOP_DE4X5; printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n", @@ -1247,7 +1392,7 @@ dev->interrupt = UNMASK_INTERRUPTS; ENABLE_IRQs; - + return; } @@ -1258,11 +1403,11 @@ u_long iobase = dev->base_addr; int entry; s32 status; - + for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0; entry=lp->rx_new) { status = (s32)le32_to_cpu(lp->rx_ring[entry].status); - + if (lp->rx_ovf) { if (inl(DE4X5_MFC) & MFC_FOCM) { de4x5_rx_ovfc(dev); @@ -1273,9 +1418,9 @@ if (status & RD_FS) { /* Remember the start of frame */ lp->rx_old = entry; } - + if (status & RD_LS) { /* Valid frame status */ - lp->linkOK++; + if (lp->tx_enable) lp->linkOK++; if (status & RD_ES) { /* There was an error. */ lp->stats.rx_errors++; /* Update the error stats. */ if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++; @@ -1290,9 +1435,9 @@ struct sk_buff *skb; short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status) >> 16) - 4; - + if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { - printk("%s: Insufficient memory; nuking packet.\n", + printk("%s: Insufficient memory; nuking packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; @@ -1302,12 +1447,12 @@ /* Push up the protocol stack */ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - + /* Update stats */ lp->stats.rx_packets++; de4x5_local_stats(dev, skb->data, pkt_len); } - + /* Change buffer ownership for this frame, back to the adapter */ for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) { lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN); @@ -1316,13 +1461,13 @@ lp->rx_ring[entry].status = cpu_to_le32(R_OWN); barrier(); } - + /* ** Update entry information */ lp->rx_new = (++lp->rx_new) % lp->rxRingSize; } - + return 0; } @@ -1336,33 +1481,29 @@ u_long iobase = dev->base_addr; int entry; s32 status; - + for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) { status = (s32)le32_to_cpu(lp->tx_ring[entry].status); if (status < 0) { /* Buffer not sent yet */ break; } else if (status != 0x7fffffff) { /* Not setup frame */ if (status & TD_ES) { /* An error happened */ - lp->stats.tx_errors++; + lp->stats.tx_errors++; if (status & TD_NC) lp->stats.tx_carrier_errors++; if (status & TD_LC) lp->stats.tx_window_errors++; if (status & TD_UF) lp->stats.tx_fifo_errors++; if (status & TD_EC) lp->pktStats.excessive_collisions++; if (status & TD_DE) lp->stats.tx_aborted_errors++; - - if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) { - lp->lostMedia++; - } + if (TX_PKT_PENDING) { outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */ } } else { /* Packet sent */ lp->stats.tx_packets++; - lp->lostMedia = 0; /* Remove transient problem */ - lp->linkOK++; + if (lp->tx_enable) lp->linkOK++; } /* Update the collision counter */ - lp->stats.collisions += ((status & TD_EC) ? 16 : + lp->stats.collisions += ((status & TD_EC) ? 16 : ((status & TD_CC) >> 3)); /* Free the buffer. */ @@ -1371,7 +1512,7 @@ lp->tx_skb[entry] = NULL; } } - + /* Update all the pointers */ lp->tx_old = (++lp->tx_old) % lp->txRingSize; } @@ -1380,7 +1521,7 @@ dev->tbusy = 0; /* Clear TX busy flag */ if (dev->interrupt) mark_bh(NET_BH); } - + return 0; } @@ -1389,10 +1530,12 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int next_tick = DE4X5_AUTOSENSE_MS; - + disable_ast(dev); - - if (lp->chipset == DC21140) { + + if (lp->useSROM) { + next_tick = srom_autoconf(dev); + } else if (lp->chipset == DC21140) { next_tick = dc21140m_autoconf(dev); } else if (lp->chipset == DC21041) { next_tick = dc21041_autoconf(dev); @@ -1401,7 +1544,7 @@ } lp->linkOK = 0; enable_ast(dev, next_tick); - + return 0; } @@ -1424,11 +1567,11 @@ } outl(omr | OMR_ST | OMR_SR, DE4X5_OMR); } - + return 0; } -static int +static int de4x5_rx_ovfc(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; @@ -1445,7 +1588,7 @@ } outl(omr, DE4X5_OMR); - + return 0; } @@ -1455,22 +1598,22 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; s32 imr, omr; - + disable_ast(dev); dev->start = 0; dev->tbusy = 1; - - if (de4x5_debug > 1) { + + if (de4x5_debug & DEBUG_CLOSE) { printk("%s: Shutting down ethercard, status was %8.8x.\n", dev->name, inl(DE4X5_STS)); } - - /* + + /* ** We stop the DE4X5 here... mask interrupts and stop TX & RX */ DISABLE_IRQs; STOP_DE4X5; - + /* Free the associated irq */ free_irq(dev->irq, dev); lp->state = CLOSED; @@ -1478,26 +1621,22 @@ /* Free any socket buffers */ de4x5_free_rx_buffs(dev); de4x5_free_tx_buffs(dev); - + MOD_DEC_USE_COUNT; - + /* Put the adapter to sleep to save power */ - if (lp->chipset == DC21041) { - outl(0, DE4X5_SICR); - outl(CFDA_PSM, PCI_CFDA); - } - + yawn(dev, SLEEP); + return 0; } -static struct enet_statistics * -de4x5_get_stats(struct device *dev) +static struct net_device_stats *de4x5_get_stats(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - + lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR)); - + return &lp->stats; } @@ -1523,7 +1662,7 @@ (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { lp->pktStats.unicast++; } - + lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ if (lp->pktStats.bins[0] == 0) { /* Reset counters */ memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats)); @@ -1536,7 +1675,7 @@ load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - + lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf)); lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER); lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags); @@ -1544,7 +1683,7 @@ barrier(); lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN); barrier(); - + return; } @@ -1564,17 +1703,17 @@ omr = inl(DE4X5_OMR); omr |= OMR_PR; outl(omr, DE4X5_OMR); - } else { + } else { SetMulticastFilter(dev); - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); - + lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ dev->trans_start = jiffies; } } - + return; } @@ -1598,26 +1737,26 @@ 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;imc_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>=1) { crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); } } hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ - + byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */ - + byte <<= 1; /* calc offset into setup frame */ if (byte & 0x02) { byte -= 1; @@ -1629,14 +1768,14 @@ for (j=0; jmc_count; j++) { addrs=dmi->dmi_addr; dmi=dmi->next; - for (i=0; ibus = EISA; - + if (ioaddr == 0) { /* Autoprobing */ iobase = EISA_SLOT_INC; /* Get the first slot address */ i = 1; @@ -1668,31 +1807,33 @@ i = (ioaddr >> 12); maxSlots = i + 1; } - - for (status = -ENODEV; - (i> 16); + cfid = (u32) inl(PCI_CFID); + cfrv = (u_short) inl(PCI_CFRV); + device = (cfid >> 8) & 0x00ffff00; vendor = (u_short) cfid; - + /* Read the EISA Configuration Registers */ dev->irq = inb(EISA_REG0); dev->irq = de4x5_irq[(dev->irq >> 1) & 0x03]; + if (is_DC2114x) device |= (cfrv & 0x00f0); lp->chipset = device; DevicePresent(DE4X5_APROM); /* Write the PCI Configuration Registers */ outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); outl(0x00006000, PCI_CFLT); outl(iobase, PCI_CBIO); - + if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { if ((tmp = alloc_device(dev, iobase)) != NULL) { if ((status = de4x5_hw_init(tmp, iobase)) == 0) { num_de4x5s++; + if (loading_module) link_modules(dev, tmp); + } else if (loading_module && (tmp != dev)) { + kfree(tmp); } } } else if (autoprobed) { @@ -1700,7 +1841,7 @@ } } } - + return; } @@ -1724,18 +1865,18 @@ { u_char irq; u_char pb, pbus, dev_num, dnum, dev_fn; - u_short vendor, device, index, status; + u_short vendor, index, status; u_int class = DE4X5_CLASS_CODE; - u_int iobase; + u_int device, iobase; struct bus_type *lp = &bus; struct device *tmp; - if ((!ioaddr || !loading_module) && autoprobed) return; - + if (autoprobed) return; + if (!pcibios_present()) return; /* No PCI bus in this machine! */ - + lp->bus = PCI; - + if ((ioaddr < 0x1000) && loading_module) { pbus = (u_short)(ioaddr >> 8); dnum = (u_short)(ioaddr & 0xff); @@ -1744,26 +1885,35 @@ dnum = 0; } - for (index=0; - (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND) && - (!loading_module || (num_de4x5s == 0)); + for (index=0; + (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { dev_num = PCI_SLOT(dev_fn); if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { + device = 0; pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device); - if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue; + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device); + device <<= 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { + continue; + } + + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); /* Set the device number information */ lp->device = dev_num; lp->bus_num = pb; - + /* Set the chipset information */ + if (is_DC2114x) device |= (cfrv & 0x00f0); lp->chipset = device; - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + if (is_DC21142 || is_DC21143) { + printk("de4x5: Detected a %s chip. Currently this is unsupported in this driver.\nPlease email the author to request its inclusion!\n", (is_DC21142?"DC21142":"DC21143")); + continue; + } /* Get the board I/O address */ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase); @@ -1772,7 +1922,7 @@ /* Fetch the IRQ to be used */ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq); if ((irq == 0) || (irq == (u_char) 0xff)) continue; - + /* Check if I/O accesses and Bus Mastering are enabled */ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); if (!(status & PCI_COMMAND_IO)) continue; @@ -1789,15 +1939,18 @@ tmp->irq = irq; if ((status = de4x5_hw_init(tmp, iobase)) == 0) { num_de4x5s++; + if (loading_module) link_modules(dev, tmp); + } else if (loading_module && (tmp != dev)) { + kfree(tmp); } } } else if (autoprobed) { - printk("%s: region already allocated at 0x%04x.\n", dev->name, + printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase); } } } - + return; } @@ -1813,8 +1966,16 @@ struct device *adev = NULL; int fixed = 0, new_dev = 0; + if (!dev) return dev; num_eth = de4x5_dev_index(dev->name); - if (loading_module) return dev; + + if (loading_module) { + if (dev->priv) { + dev = insert_device(dev, iobase, de4x5_probe); + } + num_eth++; + return dev; + } while (1) { if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) { @@ -1838,13 +1999,13 @@ new_dev = 0; } - if (((dev->next == NULL) && + if (((dev->next == NULL) && ((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) || new_dev) { num_eth++; /* New device */ dev = insert_device(dev, iobase, de4x5_probe); } - + return dev; } @@ -1862,20 +2023,22 @@ printk("eth%d: Device not initialised, insufficient memory\n",num_eth); return NULL; } else { - new->next = dev->next; - dev->next = new; - dev = dev->next; /* point to the new device */ - dev->name = (char *)(dev + 1); - if (num_eth > 9999) { - sprintf(dev->name,"eth????");/* New device name */ - } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ + memset((char *)new, 0, sizeof(struct device)+8); + new->name = (char *)(new + 1); + new->base_addr = iobase; /* assign the io address */ + new->init = init; /* initialisation routine */ + if (!loading_module) { + new->next = dev->next; + dev->next = new; + if (num_eth > 9999) { + sprintf(new->name,"eth????");/* New device name */ + } else { + sprintf(new->name,"eth%d", num_eth);/* New device name */ + } } - dev->base_addr = iobase; /* assign the io address */ - dev->init = init; /* initialisation routine */ } - return dev; + return new; } static int @@ -1893,11 +2056,54 @@ return i; } +static void +link_modules(struct device *dev, struct device *tmp) +{ + struct device *p=dev; + + if (p) { + while (((struct de4x5_private *)(p->priv))->next_module) { + p = ((struct de4x5_private *)(p->priv))->next_module; + } + + if (dev != tmp) { + ((struct de4x5_private *)(p->priv))->next_module = tmp; + } else { + ((struct de4x5_private *)(p->priv))->next_module = NULL; + } + } + + return; +} + +static struct device * +unlink_modules(struct device *p) +{ + struct device *next = NULL; + + if (p->priv) { /* Private areas allocated? */ + struct de4x5_private *lp = (struct de4x5_private *)p->priv; + + next = lp->next_module; + if (lp->cache.buf) { /* MAC buffers allocated? */ + kfree(lp->cache.buf); /* Free the MAC buffers */ + } + kfree(lp->cache.priv); /* Free the private area */ + release_region(p->base_addr, (lp->bus == PCI ? + DE4X5_PCI_TOTAL_SIZE : + DE4X5_EISA_TOTAL_SIZE)); + } + unregister_netdev(p); + kfree(p); /* Free the device structure */ + + return next; +} + /* ** Auto configure the media here rather than setting the port at compile ** time. This routine is called by de4x5_init() and when a loss of media is ** detected (excessive collisions, loss of carrier, no carrier or link fail -** [TP] or no recent receive activity) to check whether the user has been +** [TP] or no recent receive activity) to check whether the user has been ** sneaky and changed the port on us. */ static int @@ -1906,21 +2112,24 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS;; - + lp->linkOK = 0; lp->c_media = AUTO; /* Bogus last media */ disable_ast(dev); inl(DE4X5_MFC); /* Zero the lost frames counter */ lp->media = INIT; - if (lp->chipset == DC21040) { + if (lp->useSROM) { + next_tick = srom_autoconf(dev); + } else if (lp->chipset == DC21040) { next_tick = dc21040_autoconf(dev); } else if (lp->chipset == DC21041) { next_tick = dc21041_autoconf(dev); } else if (lp->chipset == DC21140) { next_tick = dc21140m_autoconf(dev); } - enable_ast(dev, next_tick); + enable_ast(dev, next_tick); + return (lp->media); } @@ -1943,7 +2152,7 @@ u_long iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS; s32 imr; - + switch (lp->media) { case INIT: DISABLE_IRQs; @@ -1962,36 +2171,36 @@ lp->local_state = 0; next_tick = dc21040_autoconf(dev); break; - + case TP: - next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, + next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, TP_SUSPECT, test_tp); break; - + case TP_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf); break; - + case BNC: case AUI: case BNC_AUI: - next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, + next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, BNC_AUI_SUSPECT, ping_media); break; - + case BNC_AUI_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf); break; - + case EXT_SIA: - next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, + next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, NC, EXT_SIA_SUSPECT, ping_media); break; - + case EXT_SIA_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf); break; - + case NC: /* default to TP for all */ reset_init_sia(dev, 0x8f01, 0xffff, 0x0000); @@ -2003,13 +2212,13 @@ lp->tx_enable = NO; break; } - + return next_tick; } static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, - int next_state, int suspect_state, + int next_state, int suspect_state, int (*fn)(struct device *, int)) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; @@ -2022,7 +2231,7 @@ lp->local_state++; next_tick = 500; break; - + case 1: if (!lp->tx_enable) { linkBad = fn(dev, timeout); @@ -2042,7 +2251,7 @@ } break; } - + return next_tick; } @@ -2057,7 +2266,7 @@ switch (lp->local_state) { case 1: - if (lp->linkOK && !LOST_MEDIA) { + if (lp->linkOK) { lp->media = prev_state; } else { lp->local_state++; @@ -2096,7 +2305,7 @@ u_long iobase = dev->base_addr; s32 sts, irqs, irq_mask, imr, omr; int next_tick = DE4X5_AUTOSENSE_MS; - + switch (lp->media) { case INIT: DISABLE_IRQs; @@ -2117,11 +2326,11 @@ lp->local_state = 0; next_tick = dc21041_autoconf(dev); break; - + case TP_NW: if (lp->timeout < 0) { omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */ - outl(omr | OMR_FD, DE4X5_OMR); + outl(omr | OMR_FDX, DE4X5_OMR); } irqs = STS_LNF | STS_LNP; irq_mask = IMR_LFM | IMR_LPM; @@ -2137,7 +2346,7 @@ next_tick = dc21041_autoconf(dev); } break; - + case ANS: if (!lp->tx_enable) { irqs = STS_LNP; @@ -2159,16 +2368,16 @@ next_tick = 3000; } break; - + case ANS_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf); break; - + case TP: if (!lp->tx_enable) { if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for TP */ - outl(omr & ~OMR_FD, DE4X5_OMR); + outl(omr & ~OMR_FDX, DE4X5_OMR); } irqs = STS_LNF | STS_LNP; irq_mask = IMR_LFM | IMR_LPM; @@ -2193,16 +2402,16 @@ next_tick = 3000; } break; - + case TP_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf); break; - + case AUI: if (!lp->tx_enable) { if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ - outl(omr & ~OMR_FD, DE4X5_OMR); + outl(omr & ~OMR_FDX, DE4X5_OMR); } irqs = 0; irq_mask = 0; @@ -2223,17 +2432,17 @@ next_tick = 3000; } break; - + case AUI_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf); break; - + case BNC: switch (lp->local_state) { case 0: if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ - outl(omr & ~OMR_FD, DE4X5_OMR); + outl(omr & ~OMR_FDX, DE4X5_OMR); } irqs = 0; irq_mask = 0; @@ -2245,7 +2454,7 @@ next_tick = dc21041_autoconf(dev); } break; - + case 1: if (!lp->tx_enable) { if ((sts = ping_media(dev, 3000)) < 0) { @@ -2265,14 +2474,14 @@ break; } break; - + case BNC_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf); break; - + case NC: omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */ - outl(omr | OMR_FD, DE4X5_OMR); + outl(omr | OMR_FDX, DE4X5_OMR); reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */ if (lp->media != lp->c_media) { de4x5_dbg_media(dev); @@ -2282,7 +2491,7 @@ lp->tx_enable = NO; break; } - + return next_tick; } @@ -2300,38 +2509,43 @@ u_long imr, omr; switch(lp->media) { - case INIT: + case INIT: DISABLE_IRQs; lp->tx_enable = FALSE; - lp->timeout = -1; + lp->linkOK = 0; +/* lp->timeout = -1;*/ if ((next_tick = de4x5_reset_phy(dev)) < 0) { next_tick &= ~TIMER_CB; } else { de4x5_save_skbs(dev); /* Save non transmitted skb's */ - lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ - SET_10Mb; - if (lp->autosense == _100Mb) { - lp->media = _100Mb; - } else if (lp->autosense == _10Mb) { - lp->media = _10Mb; - } else if ((lp->autosense == AUTO) && - ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { - ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); - ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM); - mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - lp->media = ANS; - } else if (lp->autosense == AUTO) { - lp->media = SPD_DET; - } else if (is_spd_100(dev) && is_100_up(dev)) { - lp->media = _100Mb; + if (lp->useSROM) { + srom_map_media(dev); } else { - lp->media = NC; + lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ + SET_10Mb; + if (lp->autosense == _100Mb) { + lp->media = _100Mb; + } else if (lp->autosense == _10Mb) { + lp->media = _10Mb; + } else if ((lp->autosense == AUTO) && + ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { + ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); + ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM); + mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + lp->media = ANS; + } else if (lp->autosense == AUTO) { + lp->media = SPD_DET; + } else if (is_spd_100(dev) && is_100_up(dev)) { + lp->media = _100Mb; + } else { + lp->media = NC; + } } lp->local_state = 0; next_tick = dc21140m_autoconf(dev); } break; - + case ANS: switch (lp->local_state) { case 0: @@ -2351,7 +2565,7 @@ next_tick = dc21140m_autoconf(dev); } break; - + case 1: if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { next_tick = sr & ~TIMER_CB; @@ -2362,13 +2576,13 @@ lp->tmp = MII_SR_ASSC; anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII); ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - if (!(anlpa & MII_ANLPA_RF) && + if (!(anlpa & MII_ANLPA_RF) && (cap = anlpa & MII_ANLPA_TAF & ana)) { if (cap & MII_ANA_100M) { - de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); + lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); lp->media = _100Mb; } else if (cap & MII_ANA_10M) { - de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); + lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); lp->media = _10Mb; } @@ -2379,7 +2593,7 @@ break; } break; - + case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ if (lp->timeout < 0) { lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : @@ -2399,9 +2613,9 @@ next_tick = dc21140m_autoconf(dev); } break; - + case _100Mb: /* Set 100Mb/s */ - next_tick = 3000; + next_tick = 3000; if (!lp->tx_enable) { SET_100Mb; de4x5_init_connection(dev); @@ -2409,14 +2623,15 @@ if (!lp->linkOK && (lp->autosense == AUTO)) { if (!(is_spd_100(dev) && is_100_up(dev))) { lp->media = INIT; + lp->tcount++; next_tick = DE4X5_AUTOSENSE_MS; } } } break; - + case _10Mb: /* Set 10Mb/s */ - next_tick = 3000; + next_tick = 3000; if (!lp->tx_enable) { SET_10Mb; de4x5_init_connection(dev); @@ -2424,12 +2639,13 @@ if (!lp->linkOK && (lp->autosense == AUTO)) { if (!(!is_spd_100(dev) && is_10_up(dev))) { lp->media = INIT; + lp->tcount++; next_tick = DE4X5_AUTOSENSE_MS; } } } break; - + case NC: if (lp->media != lp->c_media) { de4x5_dbg_media(dev); @@ -2439,10 +2655,76 @@ lp->tx_enable = FALSE; break; } - + return next_tick; } +static int +srom_autoconf(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + + return lp->infoleaf_fn(dev); +} + +/* +** This mapping keeps the original media codes and FDX flag unchanged. +** While it isn't strictly necessary, it helps me for the moment... +*/ +static void +srom_map_media(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + + lp->fdx = 0; + switch(lp->infoblock_media) { + case SROM_10BASETF: + lp->fdx = TRUE; + case SROM_10BASET: + if (lp->chipset == DC21140) { + lp->media = _10Mb; + } else { + lp->media = TP; + } + break; + + case SROM_10BASE2: + lp->media = BNC; + break; + + case SROM_10BASE5: + lp->media = AUI; + break; + + case SROM_100BASETF: + lp->fdx = TRUE; + case SROM_100BASET: + lp->media = _100Mb; + break; + + case SROM_100BASET4: + lp->media = _100Mb; + break; + + case SROM_100BASEFF: + lp->fdx = TRUE; + case SROM_100BASEF: + lp->media = _100Mb; + break; + + case ANS: + lp->media = ANS; + break; + + default: + printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, + lp->infoblock_media); + break; + } + + return; +} + static void de4x5_init_connection(struct device *dev) { @@ -2457,7 +2739,6 @@ cli(); de4x5_rx(dev); de4x5_setup_intr(dev); - lp->lostMedia = 0; lp->tx_enable = YES; dev->tbusy = 0; sti(); @@ -2467,6 +2748,9 @@ return; } +/* +** General PHY reset function. +*/ static int de4x5_reset_phy(struct device *dev) { @@ -2474,15 +2758,26 @@ u_long iobase = dev->base_addr; int next_tick = 0; - if (lp->phy[lp->active].id) { + if ((lp->useSROM) || (lp->phy[lp->active].id)) { if (lp->timeout < 0) { - outl(GEP_HRST, DE4X5_GEP); /* Hard RESET the PHY dev. */ - udelay(1000); /* Assert for 1ms */ - outl(0x00, DE4X5_GEP); - udelay(2000); /* Wait for 2ms */ - mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); + if (lp->useSROM) { + if (lp->phy[lp->active].rst) { /* MII device specific reset */ + srom_exec(dev, lp->phy[lp->active].rst); + } else if (lp->rst) { /* Type 5 infoblock reset */ + srom_exec(dev, lp->rst); + } + } else { + PHY_HARD_RESET; + } + if (lp->useMII) { + mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); + } + } + if (lp->useMII) { + next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500); } - next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500); + } else if (lp->chipset == DC21140) { + PHY_HARD_RESET; } return next_tick; @@ -2494,7 +2789,7 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; s32 sts, csr12; - + if (lp->timeout < 0) { lp->timeout = msec/100; reset_init_sia(dev, csr13, csr14, csr15); @@ -2505,22 +2800,22 @@ /* clear all pending interrupts */ sts = inl(DE4X5_STS); outl(sts, DE4X5_STS); - + /* clear csr12 NRA and SRA bits */ if (lp->chipset == DC21041) { csr12 = inl(DE4X5_SISR); outl(csr12, DE4X5_SISR); } } - + sts = inl(DE4X5_STS) & ~TIMER_CB; - + if (!(sts & irqs) && --lp->timeout) { sts = 100 | TIMER_CB; } else { lp->timeout = -1; } - + return sts; } @@ -2530,11 +2825,11 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; int sisr; - + if (lp->timeout < 0) { lp->timeout = msec/100; } - + sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR); if (sisr && --lp->timeout) { @@ -2542,7 +2837,7 @@ } else { lp->timeout = -1; } - + return sisr; } @@ -2552,12 +2847,12 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int iobase = dev->base_addr; int gep = 0; - + if (lp->timeout < 0) { lp->timeout = msec/100; } - - if (lp->phy[lp->active].id) { + + if (lp->phy[lp->active].id || lp->useSROM) { gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0); } else { gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP)); @@ -2567,7 +2862,7 @@ } else { lp->timeout = -1; } - + return gep; } @@ -2580,21 +2875,21 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int test, iobase = dev->base_addr; - + if (lp->timeout < 0) { lp->timeout = msec/100; } - + if (pol) pol = ~0; reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask; test = (reg ^ pol) & mask; - + if (test && --lp->timeout) { reg = 100 | TIMER_CB; } else { lp->timeout = -1; } - + return reg; } @@ -2604,15 +2899,19 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; int spd; - - if (lp->phy[lp->active].id) { + + if (lp->useSROM && !lp->useMII) { + spd = (lp->asBitValid & + (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) | + (lp->linkOK & ~lp->asBitValid); + } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII); spd = ~(spd ^ lp->phy[lp->active].spd.value); spd &= lp->phy[lp->active].spd.mask; } else { spd = ((~inl(DE4X5_GEP)) & GEP_SLNK); } - + return spd; } @@ -2621,8 +2920,12 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - - if (lp->phy[lp->active].id) { + + if (lp->useSROM && !lp->useMII) { + return ((lp->asBitValid & + (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) | + (lp->linkOK & ~lp->asBitValid)); + } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { /* Double read for sticky bits & temporary drops */ mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII); return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS); @@ -2636,8 +2939,12 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - - if (lp->phy[lp->active].id) { + + if (lp->useSROM && !lp->useMII) { + return ((lp->asBitValid & + (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) | + (lp->linkOK & ~lp->asBitValid)); + } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { /* Double read for sticky bits & temporary drops */ mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII); return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS); @@ -2651,8 +2958,8 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - - if (lp->phy[lp->active].id) { + + if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII)); } else { return 0; @@ -2669,24 +2976,24 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; int sisr; - + if (lp->timeout < 0) { lp->timeout = msec/100; - + lp->tmp = lp->tx_new; /* Remember the ring position */ load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); } - + sisr = inl(DE4X5_SISR); - if ((!(sisr & SISR_NCR)) && - ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && + if ((!(sisr & SISR_NCR)) && + ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && (--lp->timeout)) { sisr = 100 | TIMER_CB; } else { - if ((!(sisr & SISR_NCR)) && + if ((!(sisr & SISR_NCR)) && !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) && lp->timeout) { sisr = 0; @@ -2695,7 +3002,7 @@ } lp->timeout = -1; } - + return sisr; } @@ -2742,15 +3049,15 @@ skb_reserve(p, 2); /* Align */ if (index < lp->rx_old) { /* Wrapped buffer */ short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; - memcpy(skb_put(p,tlen), + memcpy(skb_put(p,tlen), bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),tlen); - memcpy(skb_put(p,len-tlen), + memcpy(skb_put(p,len-tlen), bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len-tlen); } else { /* Linear buffer */ - memcpy(skb_put(p,len), + memcpy(skb_put(p,len), bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),len); } - + return p; #endif } @@ -2837,7 +3144,7 @@ lp->cache.save_cnt--; START_DE4X5; } - + return; } @@ -2846,7 +3153,6 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - s32 gep; switch(flag) { case DE4X5_SAVE_STATE: @@ -2865,14 +3171,10 @@ outl(lp->cache.csr6, DE4X5_OMR); outl(lp->cache.csr7, DE4X5_IMR); if (lp->chipset == DC21140) { - outl(GEP_INIT, DE4X5_GEP); - gep = (lp->media == _100Mb ? GEP_MODE : 0); - if (!lp->phy[lp->active].id && !de4x5_full_duplex) { - gep |= GEP_FDXD; - } - outl(gep, DE4X5_GEP); + outl(lp->cache.gepc, DE4X5_GEP); + outl(lp->cache.gep, DE4X5_GEP); } else { - reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, + reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15); } break; @@ -2934,25 +3236,25 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; s32 sts, ans; - + if (lp->timeout < 0) { lp->timeout = msec/100; outl(irq_mask, DE4X5_IMR); - + /* clear all pending interrupts */ sts = inl(DE4X5_STS); outl(sts, DE4X5_STS); } - + ans = inl(DE4X5_SISR) & SISR_ANS; sts = inl(DE4X5_STS) & ~TIMER_CB; - + if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) { sts = 100 | TIMER_CB; } else { lp->timeout = -1; } - + return sts; } @@ -2962,7 +3264,7 @@ struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; s32 imr, sts; - + if (inl(DE4X5_OMR) & OMR_SR) { /* Only unmask if TX/RX is enabled */ imr = 0; UNMASK_IRQs; @@ -2970,7 +3272,7 @@ outl(sts, DE4X5_STS); ENABLE_IRQs; } - + return; } @@ -2982,7 +3284,7 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - + RESET_SIA; outl(sigr, DE4X5_SIGR); outl(strr, DE4X5_STRR); @@ -2992,24 +3294,24 @@ } /* -** 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; idev_addr[i]; } for (i=0; idev_addr[i]; } - + *buf++ = 0; /* Packet length (2 bytes) */ *buf++ = 1; - + return; } @@ -3020,7 +3322,7 @@ de4x5_us_delay(u32 usec) { udelay(usec); - + return; } @@ -3031,11 +3333,11 @@ de4x5_ms_delay(u32 msec) { u_int i; - + for (i=0; i>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;ichipset == 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; ichipset == DC21040) ? "DC21040" : ((lp->chipset == DC21041) ? "DC21041" : - ((lp->chipset == DC21140) ? "DC21140" : "UNKNOWN" - ))))); + ((lp->chipset == DC21140) ? "DC21140" : + ((lp->chipset == DC21142) ? "DC21142" : + ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN" + ))))))); + } + if (lp->chipset != DC21041) { + useSROM = TRUE; /* card is not recognisably DEC */ } } - + return status; } @@ -3121,7 +3425,7 @@ { int i; struct bus_type *lp = &bus; - + if (lp->chipset == DC21040) { outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ } else { /* Read new srom */ @@ -3131,10 +3435,16 @@ } de4x5_dbg_srom((struct de4x5_srom *)&lp->srom); } - + return; } +/* +** For the bad status case and no SROM, then add one to the previous +** address. However, need to add one backwards in case we have 0xff +** as one or more of the bytes. Only the last 3 bytes should be checked +** as the first three are invariant - assigned to an organisation. +*/ static int get_hw_addr(struct device *dev) { @@ -3147,7 +3457,7 @@ for (i=0,k=0,j=0;j<3;j++) { k <<= 1; if (k > 0xffff) k-=0xffff; - + if (lp->bus == PCI) { if (lp->chipset == DC21040) { while ((tmp = inl(DE4X5_APROM)) < 0); @@ -3169,11 +3479,11 @@ k += (u_short) ((tmp = inb(EISA_APROM)) << 8); dev->dev_addr[i++] = (u_char) tmp; } - + if (k > 0xffff) k-=0xffff; } if (k == 0xffff) k=0; - + if (lp->bus == PCI) { if (lp->chipset == DC21040) { while ((tmp = inl(DE4X5_APROM)) < 0); @@ -3188,6 +3498,12 @@ if ((k != chksum) && (dec_only)) status = -1; } + /* If possible, try to fix a broken card - SMC only so far */ + srom_repair(dev, broken); + + /* Test for a bad enet address */ + status = test_bad_enet(dev, status); + return status; } @@ -3227,6 +3543,55 @@ 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; idev_addr[i]; + if ((tmp == 0) || (tmp == 0x5fa)) { + if ((lp->chipset == last.chipset) && + (lp->bus_num == last.bus) && (lp->bus_num > 0)) { + for (i=0; idev_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; idev_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; idev_addr[i]; + } + + return status; +} + /* ** SROM Read */ @@ -3234,11 +3599,11 @@ srom_rd(u_long addr, u_char offset) { sendto_srom(SROM_RD | SROM_SR, addr); - + srom_latch(SROM_RD | SROM_SR | DT_CS, addr); srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr); srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset); - + return srom_data(SROM_RD | SROM_SR | DT_CS, addr); } @@ -3248,7 +3613,7 @@ sendto_srom(command, addr); sendto_srom(command | DT_CLK, addr); sendto_srom(command, addr); - + return; } @@ -3258,7 +3623,7 @@ srom_latch(command, addr); srom_latch(command, addr); srom_latch((command & 0x0000ff00) | DT_CS, addr); - + return; } @@ -3267,18 +3632,18 @@ { int i; char a; - + a = (char)(offset << 2); for (i=0; i<6; i++, a <<= 1) { srom_latch(command | ((a < 0) ? DT_IN : 0), addr); } de4x5_us_delay(1); - + i = (getfrom_srom(addr) >> 3) & 0x01; if (i != 0) { printk("Bad SROM address phase.....\n"); } - + return; } @@ -3288,17 +3653,17 @@ int i; short word = 0; s32 tmp; - + for (i=0; i<16; i++) { sendto_srom(command | DT_CLK, addr); tmp = getfrom_srom(addr); sendto_srom(command, addr); - + word = (word << 1) | ((tmp >> 3) & 0x01); } - + sendto_srom(command & 0x0000ff00, addr); - + return word; } @@ -3307,13 +3672,13 @@ srom_busy(u_int command, u_long addr) { sendto_srom((command & 0x0000ff00) | DT_CS, addr); - + while (!((getfrom_srom(addr) >> 3) & 0x01)) { de4x5_ms_delay(1); } - + sendto_srom(command & 0x0000ff00, addr); - + return; } */ @@ -3323,7 +3688,7 @@ { outl(command, addr); udelay(1); - + return; } @@ -3331,13 +3696,406 @@ 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; ichipset == infoleaf_array[i].chipset) break; + } + if (i == INFOLEAF_SIZE) { + lp->useSROM = FALSE; + printk("%s: Cannot find correct chipset for SROM decoding!\n", + dev->name); + return -ENXIO; + } + + lp->infoleaf_fn = infoleaf_array[i].fn; + + /* Find the information offset that this function should use */ + count = *((u_char *)&lp->srom + 19); + p = (u_char *)&lp->srom + 26; + + if (count > 1) { + for (i=count; i; --i, p+=3) { + if (lp->device == *p) break; + } + if (i == 0) { + lp->useSROM = FALSE; + printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", + dev->name, lp->device); + return -ENXIO; + } + } + + lp->infoleaf_offset = (u_short)*((u_short *)(p+1)); + + return 0; +} + +/* +** This routine loads any type 1 or 3 MII info into the mii device +** struct and executes any type 5 code to reset PHY devices for this +** controller. +** The info for the MII devices will be valid since the index used +** will follow the discovery process from MII address 1-31 then 0. +*/ +static void +srom_init(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; + u_char count; + + if (lp->chipset == DC21140) { + p+=2; + lp->cache.gepc = (*p++ | GEP_CTRL); + outl(lp->cache.gepc, DE4X5_GEP); + } else if (lp->chipset == DC21142) { + p+=2; + } else if (lp->chipset == DC21143) { + p+=2; + } + + /* Block count */ + count = *p++; + + /* Jump the infoblocks to find types */ + for (;count; --count) { + if (*p < 128) { + p += COMPACT_LEN; + } else if (*(p+1) == 5) { + type5_infoblock(dev, 1, p); + p += ((*p & BLOCK_LEN) + 1); + } else if (*(p+1) == 3) { + type3_infoblock(dev, 1, p); + p += ((*p & BLOCK_LEN) + 1); + } else if (*(p+1) == 1) { + type1_infoblock(dev, 1, p); + p += ((*p & BLOCK_LEN) + 1); + } else { + p += ((*p & BLOCK_LEN) + 1); + } + } + + return; +} + +static void +srom_exec(struct device *dev, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + u_char count = *p++; + + while (count--) { + if (lp->chipset == DC21140) { + outl(*p++, DE4X5_GEP); + } + udelay(2000); /* 2ms per action */ + } + + return; +} + +/* +** Basically this function is a NOP since it will never be called, +** unless I implement the DC21041 SROM functions. There's no need +** since the existing code will be satisfactory for all boards. +*/ +static int +dc21041_infoleaf(struct device *dev) +{ + return DE4X5_AUTOSENSE_MS; +} + +static int +dc21140_infoleaf(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_char count = 0; + u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; + int next_tick = DE4X5_AUTOSENSE_MS; + + /* Read the connection type */ + p+=2; + + /* GEP control */ + lp->cache.gepc = (*p++ | GEP_CTRL); + + /* Block count */ + count = *p++; + + /* Recursively figure out the info blocks */ + if (*p < 128) { + next_tick = dc_infoblock[COMPACT](dev, count, p); + } else { + next_tick = dc_infoblock[*(p+1)](dev, count, p); + } + + if (lp->tcount == count) { + lp->media = NC; + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tcount = 0; + lp->tx_enable = FALSE; + } + + return next_tick & ~TIMER_CB; +} + +static int +dc21142_infoleaf(struct device *dev) +{ +printk("dc21142_infoleaf()\n"); + return DE4X5_AUTOSENSE_MS; +} + +static int +dc21143_infoleaf(struct device *dev) +{ +printk("dc21143_infoleaf()\n"); + return DE4X5_AUTOSENSE_MS; +} + +/* +** The compact infoblock is only designed for DC21140[A] chips, so +** we'll reuse the dc21140m_autoconf function. Non MII media only. +*/ +static int +compact_infoblock(struct device *dev, u_char count, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + u_char flags, csr6; + + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+COMPACT_LEN) < 128) { + return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN); + } else { + return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN); + } + } + + if (lp->media == INIT) { + outl(lp->cache.gepc, DE4X5_GEP); + lp->infoblock_media = (*p++) & COMPACT_MC; + lp->cache.gep = *p++; + csr6 = *p++; + flags = *p++; + + lp->asBitValid = (flags & 0x80) ? 0 : -1; + lp->defMedium = (flags & 0x40) ? -1 : 0; + lp->asBit = 1 << ((csr6 >> 1) & 0x07); + lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; + lp->infoblock_csr6 = (csr6 & 0x71) << 18; + lp->useMII = FALSE; + + de4x5_switch_mac_port(dev); + } + + return dc21140m_autoconf(dev); +} + +/* +** This block describes non MII media for the DC21140[A] only. + */ +static int +type0_infoblock(struct device *dev, u_char count, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + u_char flags, csr6, len = (*p & BLOCK_LEN)+1; + + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+len) < 128) { + return dc_infoblock[COMPACT](dev, count, p+len); + } else { + return dc_infoblock[*(p+len+1)](dev, count, p+len); + } + } + + if (lp->media == INIT) { + outl(lp->cache.gepc, DE4X5_GEP); + p+=2; + lp->infoblock_media = (*p++) & BLOCK0_MC; + lp->cache.gep = *p++; + csr6 = *p++; + flags = *p++; + + lp->asBitValid = (flags & 0x80) ? 0 : -1; + lp->defMedium = (flags & 0x40) ? -1 : 0; + lp->asBit = 1 << ((csr6 >> 1) & 0x07); + lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; + lp->infoblock_csr6 = (csr6 & 0x71) << 18; + lp->useMII = FALSE; + + de4x5_switch_mac_port(dev); + } + + return dc21140m_autoconf(dev); +} + +/* These functions are under construction! */ + +static int +type1_infoblock(struct device *dev, u_char count, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + u_char len = (*p & BLOCK_LEN)+1; + int ana; + + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+len) < 128) { + return dc_infoblock[COMPACT](dev, count, p+len); + } else { + return dc_infoblock[*(p+len+1)](dev, count, p+len); + } + } + + if (lp->state == INITIALISED) { + lp->ibn = 1; p += 2; + lp->active = *p++; + lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); + lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); + lp->phy[lp->active].mc = *(u_short *)p; p += 2; + lp->phy[lp->active].ana = *(u_short *)p; p += 2; + lp->phy[lp->active].fdx = *(u_short *)p; p += 2; + lp->phy[lp->active].ttm = *(u_short *)p; + return 0; + } else if (lp->media == INIT) { + if (lp->phy[lp->active].gep) { + srom_exec(dev, lp->phy[lp->active].gep); + } + ana = lp->phy[lp->active].ana | MII_ANA_CSMA; + mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + lp->infoblock_csr6 = OMR_PS | OMR_HBD; + lp->useMII = TRUE; + lp->infoblock_media = ANS; + de4x5_switch_mac_port(dev); + } + + return dc21140m_autoconf(dev); +} + +static int +type2_infoblock(struct device *dev, u_char count, u_char *p) +{ + return DE4X5_AUTOSENSE_MS; +} + +static int +type3_infoblock(struct device *dev, u_char count, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_char flags, csr6, len = (*p & BLOCK_LEN)+1; + + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+len) < 128) { + return dc_infoblock[COMPACT](dev, count, p+len); + } else { + return dc_infoblock[*(p+len+1)](dev, count, p+len); + } + } + + if (lp->state == INITIALISED) { + lp->ibn = 3; p += 2; + lp->active = *p++; + lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); + lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); + lp->phy[lp->active].mc = *(u_short *)p; p += 2; + lp->phy[lp->active].ana = *(u_short *)p; p += 2; + lp->phy[lp->active].fdx = *(u_short *)p; p += 2; + lp->phy[lp->active].ttm = *(u_short *)p; + return 0; + } else if (lp->media == INIT) { + p+=2; + lp->infoblock_media = (*p++) & BLOCK0_MC; + lp->cache.gep = *p++; + csr6 = *p++; + flags = *p++; + + lp->asBitValid = (flags & 0x80) ? 0 : -1; + lp->defMedium = (flags & 0x40) ? -1 : 0; + lp->asBit = 1 << ((csr6 >> 1) & 0x07); + lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; + lp->infoblock_csr6 = (csr6 & 0x71) << 18; + lp->useMII = TRUE; + + de4x5_switch_mac_port(dev); + } + + return dc21140m_autoconf(dev); +} + +static int +type4_infoblock(struct device *dev, u_char count, u_char *p) +{ + return DE4X5_AUTOSENSE_MS; +} + +/* +** This block type provides information for resetting external devices +** (chips) through the General Purpose Register. +*/ +static int +type5_infoblock(struct device *dev, u_char count, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + u_char i, j, len = (*p & BLOCK_LEN)+1; + + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+len) < 128) { + return dc_infoblock[COMPACT](dev, count, p+len); + } else { + return dc_infoblock[*(p+len+1)](dev, count, p+len); + } + } + + /* Must be initializing to run this code */ + if ((lp->state == INITIALISED) || (lp->media == INIT)) { + p+=2; + lp->rst = p; + i = *p++; + for (j=0;i;--i) { + if (lp->chipset == DC21140) { + if (!j) { + outl(*p++ | GEP_CTRL, DE4X5_GEP); + j++; + } + outl(*p++, DE4X5_GEP); + } else if (lp->chipset == DC21142) { + } else if (lp->chipset == DC21143) { + } + } + + } + + return DE4X5_AUTOSENSE_MS; +} + /* ** MII Read/Write */ @@ -3351,7 +4109,7 @@ mii_address(phyaddr, ioaddr); /* PHY address to be accessed */ mii_address(phyreg, ioaddr); /* PHY Register to read */ mii_ta(MII_STRD, ioaddr); /* Turn around time - 2 MDC */ - + return mii_rdata(ioaddr); /* Read data */ } @@ -3366,7 +4124,7 @@ mii_ta(MII_STWR, ioaddr); /* Turn around time - 2 MDC */ data = mii_swap(data, 16); /* Swap data bit ordering */ mii_wdata(data, 16, ioaddr); /* Write data */ - + return; } @@ -3375,12 +4133,12 @@ { int i; s32 tmp = 0; - + for (i=0; i<16; i++) { tmp <<= 1; tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr); } - + return tmp; } @@ -3388,12 +4146,12 @@ mii_wdata(int data, int len, u_long ioaddr) { int i; - + for (i=0; i>= 1; } - + return; } @@ -3401,13 +4159,13 @@ mii_address(u_char addr, u_long ioaddr) { int i; - + addr = mii_swap(addr, 5); for (i=0; i<5; i++) { sendto_mii(MII_MWR | MII_WR, addr, ioaddr); addr >>= 1; } - + return; } @@ -3415,12 +4173,12 @@ mii_ta(u_long rw, u_long ioaddr) { if (rw == MII_STWR) { - sendto_mii(MII_MWR | MII_WR, 1, ioaddr); - sendto_mii(MII_MWR | MII_WR, 0, ioaddr); + sendto_mii(MII_MWR | MII_WR, 1, ioaddr); + sendto_mii(MII_MWR | MII_WR, 0, ioaddr); } else { getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */ } - + return; } @@ -3428,13 +4186,13 @@ mii_swap(int data, int len) { int i, tmp = 0; - + for (i=0; i>= 1; } - + return tmp; } @@ -3442,13 +4200,13 @@ sendto_mii(u32 command, int data, u_long ioaddr) { u32 j; - + j = (data & 1) << 17; outl(command | j, ioaddr); udelay(1); outl(command | MII_MDC | j, ioaddr); udelay(1); - + return; } @@ -3459,7 +4217,7 @@ udelay(1); outl(command | MII_MDC, ioaddr); udelay(1); - + return ((inl(ioaddr) >> 19) & 1); } @@ -3511,24 +4269,26 @@ 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; imii_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; jphy[k].addr = i; lp->mii_cnt++; + lp->active++; } else { i = DE4X5_MAX_MII; /* Stop the search */ j = limit; } } } - if (lp->phy[lp->active].id) { /* Reset the PHY devices */ + lp->active = 0; + if (lp->phy[0].id) { /* Reset the PHY devices */ for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/ mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII); while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST); - + de4x5_dbg_mii(dev, k); } } - + return lp->mii_cnt; } @@ -3562,12 +4324,12 @@ 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; idev_addr[i]; /* Host address */ @@ -3584,7 +4346,7 @@ if (i & 0x01) pa += 4; } } - + return pa; /* Points to the next entry */ } @@ -3592,7 +4354,7 @@ enable_ast(struct device *dev, u32 time_out) { timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out); - + return; } @@ -3600,60 +4362,33 @@ 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); + 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); - } - - /* 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)); - outl(omr, DE4X5_OMR); - - /* Soft Reset */ - RESET_DE4X5; - - /* Restore the GEP */ - if (lp->chipset == DC21140) { - outl(GEP_INIT, DE4X5_GEP); - outl(0, DE4X5_GEP); + outl(lp->cache.gepc, DE4X5_GEP); + outl(lp->cache.gep, DE4X5_GEP); } /* Restore CSR6 */ @@ -3670,19 +4405,67 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int dt; - + /* First, cancel any pending timer events */ del_timer(&lp->timer); - + /* Convert msec to ticks */ dt = (msec * HZ) / 1000; if (dt==0) dt=1; - + /* Set up timer */ lp->timer.expires = jiffies + dt; lp->timer.function = fn; lp->timer.data = data; add_timer(&lp->timer); + + return; +} + +static void +yawn(struct device *dev, int state) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int iobase = dev->base_addr; + + if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return; + + if(lp->bus == EISA) { + switch(state) { + case WAKEUP: + outb(WAKEUP, PCI_CFPM); + de4x5_ms_delay(10); + break; + + case SNOOZE: + outb(SNOOZE, PCI_CFPM); + break; + + case SLEEP: + outl(0, DE4X5_SICR); + outb(SLEEP, PCI_CFPM); + break; + } + } else { + switch(state) { + case WAKEUP: + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, WAKEUP); + de4x5_ms_delay(10); + break; + + case SNOOZE: + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, SNOOZE); + break; + + case SLEEP: + outl(0, DE4X5_SICR); + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, SLEEP); + break; + } + } return; } @@ -3692,8 +4475,8 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int i; - - if (de4x5_debug > 1) { + + if (de4x5_debug & DEBUG_OPEN) { printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq); printk("\tphysical address: "); for (i=0;i<6;i++) { @@ -3730,11 +4513,11 @@ } } printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf)); - printk("Ring size: \nRX: %d\nTX: %d\n", - (short)lp->rxRingSize, - (short)lp->txRingSize); + printk("Ring size: \nRX: %d\nTX: %d\n", + (short)lp->rxRingSize, + (short)lp->txRingSize); } - + return; } @@ -3743,8 +4526,8 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int iobase = dev->base_addr; - - if (de4x5_debug > 2) { + + if (de4x5_debug & DEBUG_MII) { printk("\nMII CR: %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII)); printk("MII SR: %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII)); printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII)); @@ -3761,7 +4544,7 @@ printk("MII 20: %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII)); } } - + return; } @@ -3769,18 +4552,18 @@ de4x5_dbg_media(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - + if (lp->media != lp->c_media) { - if (de4x5_debug > 0) { + if (de4x5_debug & DEBUG_MEDIA) { if (lp->chipset != DC21140) { printk("%s: media is %s\n", dev->name, (lp->media == NC ? "unconnected!" : (lp->media == TP ? "TP." : (lp->media == ANS ? "TP/Nway." : - (lp->media == BNC ? "BNC." : - (lp->media == AUI ? "AUI." : - (lp->media == BNC_AUI ? "BNC/AUI." : - (lp->media == EXT_SIA ? "EXT SIA." : + (lp->media == BNC ? "BNC." : + (lp->media == AUI ? "AUI." : + (lp->media == BNC_AUI ? "BNC/AUI." : + (lp->media == EXT_SIA ? "EXT SIA." : "???." )))))))); } else { @@ -3794,7 +4577,7 @@ } lp->c_media = lp->media; } - + return; } @@ -3803,10 +4586,12 @@ { 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 2) { + if (de4x5_debug & DEBUG_RX) { printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", (u_char)skb->data[0], (u_char)skb->data[1], @@ -3844,7 +4629,7 @@ (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> 1]; u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2]; } tmp; - + switch(ioc->cmd) { case DE4X5_GET_HWADDR: /* Get the hardware address */ ioc->len = ETH_ALEN; @@ -3886,7 +4671,7 @@ tmp.addr[i] = dev->dev_addr[i]; } copy_to_user(ioc->data, tmp.addr, ioc->len); - + break; case DE4X5_SET_HWADDR: /* Set the hardware address */ status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN); @@ -3903,12 +4688,12 @@ build_setup_frame(dev, PHYS_ADDR_ONLY); /* Set up the descriptor and give ownership to the card */ while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/ - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ dev->tbusy = 0; /* Unlock the TX ring */ - + break; case DE4X5_SET_PROM: /* Set Promiscuous Mode */ if (suser()) { @@ -3918,7 +4703,7 @@ } else { status = -EPERM; } - + break; case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ if (suser()) { @@ -3928,19 +4713,19 @@ } else { status = -EPERM; } - + break; case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */ printk("%s: Boo!\n", dev->name); - + break; case DE4X5_GET_MCA: /* Get the multicast address table */ ioc->len = (HASH_TABLE_LEN >> 3); status = verify_area(VERIFY_WRITE, ioc->data, ioc->len); if (!status) { - copy_to_user(ioc->data, lp->setup_frame, ioc->len); + copy_to_user(ioc->data, lp->setup_frame, ioc->len); } - + break; case DE4X5_SET_MCA: /* Set a multicast address */ if (suser()) { @@ -3956,7 +4741,7 @@ } else { status = -EPERM; } - + break; case DE4X5_CLR_MCA: /* Clear all multicast addresses */ if (suser()) { @@ -3965,7 +4750,7 @@ } else { status = -EPERM; } - + break; case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ if (suser()) { @@ -3975,18 +4760,18 @@ } else { status = -EPERM; } - + break; case DE4X5_GET_STATS: /* Get the driver statistics */ ioc->len = sizeof(lp->pktStats); status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len); if (status) break; - + cli(); - copy_to_user(ioc->data, &lp->pktStats, ioc->len); + copy_to_user(ioc->data, &lp->pktStats, ioc->len); sti(); - + break; case DE4X5_CLR_STATS: /* Zero out the driver statistics */ if (suser()) { @@ -3996,14 +4781,14 @@ } else { status = -EPERM; } - + break; case DE4X5_GET_OMR: /* Get the OMR Register contents */ tmp.addr[0] = inl(DE4X5_OMR); if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) { copy_to_user(ioc->data, tmp.addr, 1); } - + break; case DE4X5_SET_OMR: /* Set the OMR Register contents */ if (suser()) { @@ -4014,7 +4799,7 @@ } else { status = -EPERM; } - + break; case DE4X5_GET_REG: /* Get the DE4X5 Registers */ j = 0; @@ -4031,9 +4816,9 @@ copy_to_user(ioc->data, tmp.addr, ioc->len); } break; - + #define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */ - + case DE4X5_DUMP: j = 0; tmp.addr[j++] = dev->irq; @@ -4043,7 +4828,7 @@ 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;irxRingSize-1;i++){ if (i < 3) { tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; @@ -4056,7 +4841,7 @@ } } tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; - + for (i=0;irxRingSize-1;i++){ if (i < 3) { tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4; @@ -4069,14 +4854,14 @@ } } tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4; - + for (i=0;irxRingSize;i++){ tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4; } for (i=0;itxRingSize;i++){ tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4; } - + tmp.lval[j>>2] = inl(DE4X5_BMR); j+=4; tmp.lval[j>>2] = inl(DE4X5_TPD); j+=4; tmp.lval[j>>2] = inl(DE4X5_RPD); j+=4; @@ -4085,18 +4870,18 @@ tmp.lval[j>>2] = inl(DE4X5_STS); j+=4; tmp.lval[j>>2] = inl(DE4X5_OMR); j+=4; tmp.lval[j>>2] = inl(DE4X5_IMR); j+=4; - tmp.lval[j>>2] = lp->chipset; j+=4; + tmp.lval[j>>2] = lp->chipset; j+=4; if (lp->chipset == DC21140) { tmp.lval[j>>2] = inl(DE4X5_GEP); j+=4; } else { tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4; tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4; tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4; - tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; + tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; } - tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; - if (lp->phy[lp->active].id) { - tmp.lval[j>>2] = lp->active; j+=4; + tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; + if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { + tmp.lval[j>>2] = lp->active; j+=4; tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4; tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4; tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4; @@ -4113,20 +4898,20 @@ tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4; } } - + tmp.addr[j++] = lp->txRingSize; tmp.addr[j++] = dev->tbusy; - + ioc->len = j; if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) { copy_to_user(ioc->data, tmp.addr, ioc->len); } - + break; default: status = -EOPNOTSUPP; } - + return status; } @@ -4135,81 +4920,33 @@ ** 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; - } - - 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; + while (mdev != NULL) { + mdev = unlink_modules(mdev); } - unregister_netdev(&thisDE4X5); return; } diff -u --recursive --new-file v2.1.24/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h --- v2.1.24/linux/drivers/net/de4x5.h Tue Aug 20 08:45:26 1996 +++ linux/drivers/net/de4x5.h Sun Feb 2 15:02:05 1997 @@ -62,6 +62,8 @@ #define PCI_CBER iobase+0x0030 /* PCI Expansion ROM Base Address Reg. */ #define PCI_CFIT iobase+0x003c /* PCI Configuration Interrupt Register */ #define PCI_CFDA iobase+0x0040 /* PCI Driver Area Register */ +#define PCI_CFDD iobase+0x0041 /* PCI Driver Dependent Area Register */ +#define PCI_CFPM iobase+0x0043 /* PCI Power Management Area Register */ /* ** EISA Configuration Register 0 bit definitions @@ -95,16 +97,20 @@ #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 @@ -112,10 +118,16 @@ #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) @@ -164,9 +176,14 @@ #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) @@ -298,7 +315,7 @@ #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 */ @@ -478,6 +495,74 @@ #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 FDR_FDACV 0x0000ffff /* Full Duplex Auto Configuration Value */ @@ -501,7 +586,7 @@ #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) @@ -685,6 +770,20 @@ #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 PCI 0 @@ -728,11 +827,16 @@ */ #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 @@ -748,55 +852,68 @@ ** 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);\ }\ } diff -u --recursive --new-file v2.1.24/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.1.24/linux/drivers/net/de600.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/de600.c Sun Feb 2 15:18:37 1997 @@ -88,8 +88,6 @@ #define DE600_DEBUG 0 #define PRINTK(x) /**/ #endif -unsigned int de600_debug = DE600_DEBUG; -MODULE_PARM(de600_debug, "i"); #include @@ -111,12 +109,14 @@ #include #include +unsigned int de600_debug = DE600_DEBUG; +MODULE_PARM(de600_debug, "i"); + #ifdef FAKE_SMALL_MAX static unsigned long de600_rspace(struct sock *sk); #include #endif -#define netstats enet_statistics typedef unsigned char byte; /************************************************** @@ -244,7 +244,7 @@ /* Put in the device structure. */ static int de600_open(struct device *dev); static int de600_close(struct device *dev); -static struct netstats *get_stats(struct device *dev); +static struct net_device_stats *get_stats(struct device *dev); static int de600_start_xmit(struct sk_buff *skb, struct device *dev); /* Dispatch from interrupts. */ @@ -374,10 +374,10 @@ return 0; } -static struct netstats * +static struct net_device_stats * get_stats(struct device *dev) { - return (struct netstats *)(dev->priv); + return (struct net_device_stats *)(dev->priv); } static inline void @@ -556,7 +556,7 @@ if (!(irq_status & TX_FAILED16)) { tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES; ++free_tx_pages; - ((struct netstats *)(dev->priv))->tx_packets++; + ((struct net_device_stats *)(dev->priv))->tx_packets++; dev->tbusy = 0; } @@ -623,7 +623,7 @@ for (i = size; i > 0; --i, ++buffer) *buffer = de600_read_byte(READ_DATA, dev); - ((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */ + ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ skb->protocol=eth_type_trans(skb,dev); @@ -639,8 +639,8 @@ de600_probe(struct device *dev) { int i; - static struct netstats de600_netstats; - /*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/ + static struct net_device_stats de600_netstats; + /*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/ printk("%s: D-Link DE-600 pocket adapter", dev->name); /* Alpha testers must have the version number to report bugs. */ @@ -697,10 +697,9 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v2.1.24/linux/drivers/net/de620.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/de620.c Sun Feb 2 15:18:38 1997 @@ -140,7 +140,6 @@ /* Constant definitions for the DE-620 registers, commands and bits */ #include "de620.h" -#define netstats enet_statistics typedef unsigned char byte; /******************************************************* @@ -212,7 +211,7 @@ /* Put in the device structure. */ static int de620_open(struct device *); static int de620_close(struct device *); -static struct netstats *get_stats(struct device *); +static struct net_device_stats *get_stats(struct device *); static void de620_set_multicast_list(struct device *); static int de620_start_xmit(struct sk_buff *, struct device *); @@ -477,10 +476,9 @@ * Return current statistics * */ -static struct netstats * -get_stats(struct device *dev) +static struct net_device_stats *get_stats(struct device *dev) { - return (struct netstats *)(dev->priv); + return (struct net_device_stats *)(dev->priv); } /********************************************* @@ -590,7 +588,7 @@ dev->trans_start = jiffies; dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */ - ((struct netstats *)(dev->priv))->tx_packets++; + ((struct net_device_stats *)(dev->priv))->tx_packets++; restore_flags(flags); /* interrupts maybe back on */ @@ -681,7 +679,7 @@ printk("%s: Ring overrun? Restoring...\n", dev->name); /* You win some, you loose some. And sometimes plenty... */ adapter_init(dev); - ((struct netstats *)(dev->priv))->rx_over_errors++; + ((struct net_device_stats *)(dev->priv))->rx_over_errors++; return 0; } @@ -701,7 +699,7 @@ next_rx_page = header_buf.Rx_NextPage; /* at least a try... */ de620_send_command(dev, W_DUMMY); de620_set_register(dev, W_NPRF, next_rx_page); - ((struct netstats *)(dev->priv))->rx_over_errors++; + ((struct net_device_stats *)(dev->priv))->rx_over_errors++; return 0; } next_rx_page = pagelink; @@ -715,7 +713,7 @@ if (skb == NULL) { /* Yeah, but no place to put it... */ printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size); - ((struct netstats *)(dev->priv))->rx_dropped++; + ((struct net_device_stats *)(dev->priv))->rx_dropped++; } else { /* Yep! Go get it! */ skb_reserve(skb,2); /* Align */ @@ -729,7 +727,7 @@ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ /* count all receives */ - ((struct netstats *)(dev->priv))->rx_packets++; + ((struct net_device_stats *)(dev->priv))->rx_packets++; } } @@ -838,7 +836,7 @@ int de620_probe(struct device *dev) { - static struct netstats de620_netstats; + static struct net_device_stats de620_netstats; int i; byte checkbyte = 0xa5; @@ -892,10 +890,9 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.1.24/linux/drivers/net/defxx.c Thu Jan 2 15:55:18 1997 +++ linux/drivers/net/defxx.c Sun Feb 2 15:18:39 1997 @@ -247,7 +247,7 @@ static void dfx_int_common(DFX_board_t *bp); static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static struct enet_statistics *dfx_ctl_get_stats(struct device *dev); +static struct net_device_stats *dfx_ctl_get_stats(struct device *dev); static void dfx_ctl_set_multicast_list(struct device *dev); static int dfx_ctl_set_mac_address(struct device *dev, void *addr); static int dfx_ctl_update_cam(DFX_board_t *bp); @@ -1991,7 +1991,7 @@ * None */ -struct enet_statistics *dfx_ctl_get_stats( +struct net_device_stats *dfx_ctl_get_stats( struct device *dev ) @@ -2013,7 +2013,7 @@ bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - return((struct enet_statistics *) &bp->stats); + return((struct net_device_stats *) &bp->stats); /* Fill the bp->stats structure with the SMT MIB object values */ @@ -2114,7 +2114,7 @@ bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - return((struct enet_statistics *) &bp->stats); + return((struct net_device_stats *) &bp->stats); /* Fill the bp->stats structure with the FDDI counter values */ @@ -2130,7 +2130,7 @@ 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); } diff -u --recursive --new-file v2.1.24/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.1.24/linux/drivers/net/depca.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/depca.c Sun Feb 2 15:18:39 1997 @@ -352,7 +352,7 @@ u_long dma_buffs; /* LANCE Rx and Tx buffers start address. */ int rx_new, tx_new; /* The next free ring entry */ int rx_old, tx_old; /* The ring entries to be free()ed. */ - struct enet_statistics stats; + struct net_device_stats stats; struct { /* Private stats counters */ u32 bins[DEPCA_PKT_STAT_SZ]; u32 unicast; @@ -387,7 +387,7 @@ static void depca_interrupt(int irq, void *dev_id, struct pt_regs * regs); static int depca_close(struct device *dev); static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd); -static struct enet_statistics *depca_get_stats(struct device *dev); +static struct net_device_stats *depca_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); /* @@ -1113,7 +1113,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.1.24/linux/drivers/net/dgrs.c Tue Dec 31 21:41:03 1996 +++ linux/drivers/net/dgrs.c Sun Feb 2 15:18:39 1997 @@ -195,7 +195,7 @@ */ char devname[8]; /* "ethN" string */ struct device *next_dev; - struct enet_statistics stats; + struct net_device_stats stats; /* * DGRS specific data @@ -687,8 +687,8 @@ * output port by setting the special "dstchan" member at the * end of the traditional 82596 RFD structure. */ -static int -dgrs_start_xmit(struct sk_buff *skb, struct device *devN) + +static int dgrs_start_xmit(struct sk_buff *skb, struct device *devN) { DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; struct device *dev0; @@ -793,9 +793,9 @@ dev->interrupt = 0; dev->start = 1; - #ifdef MODULE - MOD_INC_USE_COUNT; - #endif +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return (0); } @@ -803,15 +803,14 @@ /* * Close the interface */ -static int -dgrs_close( struct device *dev ) +static int dgrs_close( struct device *dev ) { dev->start = 0; dev->tbusy = 1; - #ifdef MODULE - MOD_DEC_USE_COUNT; - #endif +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif return (0); } @@ -819,8 +818,7 @@ /* * Get statistics */ -static struct enet_statistics * -dgrs_get_stats( struct device *dev ) +static struct net_device_stats *dgrs_get_stats( struct device *dev ) { DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; @@ -830,8 +828,8 @@ /* * Set multicast list and/or promiscuous mode */ -static void -dgrs_set_multicast_list( struct device *dev) + +static void dgrs_set_multicast_list( struct device *dev) { DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; @@ -841,63 +839,60 @@ /* * 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; + 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; - privN->bcomm->bc_filter_port = ioc.port; - privN->bcomm->bc_filter_num = ioc.filter; - privN->bcomm->bc_filter_len = ioc.len; + /* Wait for old command to finish */ + for (i = 0; i < 1000; ++i) + { + if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 ) + break; + udelay(1); + } + if (i >= 1000) + return -EIO; - if (ioc.len) - { - COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area), - ioc.data, ioc.len); - privN->bcomm->bc_filter_cmd = BC_FILTER_SET; - } - else - privN->bcomm->bc_filter_cmd = BC_FILTER_CLR; - return(0); - default: - return -EOPNOTSUPP; + privN->bcomm->bc_filter_port = ioc.port; + privN->bcomm->bc_filter_num = ioc.filter; + privN->bcomm->bc_filter_len = ioc.len; + + if (ioc.len) + { + if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area), + ioc.data, ioc.len)) + return -EFAULT; + privN->bcomm->bc_filter_cmd = BC_FILTER_SET; + } + else + privN->bcomm->bc_filter_cmd = BC_FILTER_CLR; + return(0); + default: + return -EOPNOTSUPP; } } @@ -906,8 +901,8 @@ * * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.1.24/linux/drivers/net/dlci.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/dlci.c Sun Feb 2 15:18:39 1997 @@ -5,7 +5,7 @@ * interfaces. Requires 'dlcicfg' program to create usable * interfaces, the initial one, 'dlci' is for IOCTL use only. * - * Version: @(#)dlci.c 0.30 12 Sep 1996 + * Version: @(#)dlci.c 0.35 4 Jan 1997 * * Author: Mike McLagan * @@ -20,6 +20,7 @@ * sent back to Linux for re-transmission * 0.25 Mike McLagan Converted to use SIOC IOCTL calls * 0.30 Jim Freeman Fixed to allow IPX traffic + * 0.35 Michael Elizabeth Fixed incorrect memcpy_fromfs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -55,7 +56,7 @@ #include static const char *devname = "dlci"; -static const char *version = "DLCI driver v0.30, 12 Sep 1996, mike.mclagan@linux.org"; +static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org"; static struct device *open_dev[CONFIG_DLCI_COUNT]; @@ -66,51 +67,51 @@ /* 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;ipriv; - - 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); + 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); + memcpy(dest, &hdr, hlen); - return(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); - - 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; - - case DLCI_RET_ERR: - dlp->stats.tx_errors++; - ret = 0; - 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 */ + if (dev->tbusy) + return(1); + + 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; + + case DLCI_RET_ERR: + dlp->stats.tx_errors++; + ret = 0; + 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 */ - 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); + 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; + } - copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)); - } - - return(0); + 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); - - len = strlen(dlp->slave->name) + 1; - err = verify_area(VERIFY_WRITE, ifr->ifr_slave, len); - if (err) - return err; - - 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); - - return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF)); - break; - - default: - return(-EOPNOTSUPP); - } - return(0); + switch(cmd) + { + case DLCI_GET_SLAVE: + if (!*(short *)(dev->dev_addr)) + return(-EINVAL); + + strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave)); + break; + + 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; + + 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;idevname, 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;iname = 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;idevname, 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;iname = 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;ipriv); - 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; - } + 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); + return(err); } int dlci_init(struct device *dev) { - struct dlci_local *dlp; + 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); + 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;ihard_start_xmit = dummy_xmit; #if DUMMY_STATS - dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct enet_statistics)); + memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = dummy_get_stats; #endif @@ -103,16 +103,12 @@ dummy_xmit(struct sk_buff *skb, struct device *dev) { #if DUMMY_STATS - struct enet_statistics *stats; + struct net_device_stats *stats; #endif - - if (skb == NULL || dev == NULL) - return 0; - dev_kfree_skb(skb, FREE_WRITE); #if DUMMY_STATS - stats = (struct enet_statistics *)dev->priv; + stats = (struct net_device_stats *)dev->priv; stats->tx_packets++; #endif @@ -120,10 +116,9 @@ } #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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.1.24/linux/drivers/net/eepro.c Tue Dec 31 21:41:04 1996 +++ linux/drivers/net/eepro.c Sun Feb 2 15:18:39 1997 @@ -128,7 +128,7 @@ /* Information that need to be kept for each board. */ struct eepro_local { - struct enet_statistics stats; + struct net_device_stats stats; unsigned rx_start; unsigned tx_start; /* start of the transmit chain */ int tx_last; /* pointer to last packet in the transmit chain */ @@ -156,7 +156,7 @@ static void eepro_rx(struct device *dev); static void eepro_transmit_interrupt(struct device *dev); static int eepro_close(struct device *dev); -static struct enet_statistics *eepro_get_stats(struct device *dev); +static struct net_device_stats *eepro_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); static int read_eeprom(int ioaddr, int location); @@ -846,7 +846,7 @@ /* 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.1.24/linux/drivers/net/eexpress.c Tue Dec 31 21:41:04 1996 +++ linux/drivers/net/eexpress.c Sun Feb 2 15:18:39 1997 @@ -103,7 +103,7 @@ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; unsigned long init_time; /* jiffies when eexp_hw_init586 called */ unsigned short rx_first; /* first rx buf, same as RX_BUF_START */ unsigned short rx_last; /* last rx buf */ @@ -189,7 +189,7 @@ extern int express_probe(struct device *dev); static int eexp_open(struct device *dev); static int eexp_close(struct device *dev); -static struct enet_statistics *eexp_stats(struct device *dev); +static struct net_device_stats *eexp_stats(struct device *dev); static int eexp_xmit(struct sk_buff *buf, struct device *dev); static void eexp_irq(int irq, void *dev_addr, struct pt_regs *regs); @@ -358,7 +358,7 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.1.24/linux/drivers/net/eql.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/eql.c Sun Feb 2 15:18:39 1997 @@ -155,7 +155,7 @@ static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd); /* */ static int eql_slave_xmit(struct sk_buff *skb, struct device *dev); /* */ -static struct enet_statistics *eql_get_stats(struct device *dev); /* */ +static struct net_device_stats *eql_get_stats(struct device *dev); /* */ /* ioctl() handlers ---------------- */ @@ -225,14 +225,14 @@ memset (dev->priv, 0, sizeof (equalizer_t)); eql = (equalizer_t *) dev->priv; - eql->stats = kmalloc (sizeof (struct enet_statistics), GFP_KERNEL); + eql->stats = kmalloc (sizeof (struct net_device_stats), GFP_KERNEL); if (eql->stats == NULL) { kfree(dev->priv); dev->priv = NULL; return -ENOMEM; } - memset (eql->stats, 0, sizeof (struct enet_statistics)); + memset (eql->stats, 0, sizeof (struct net_device_stats)); init_timer (&eql->timer); eql->timer.data = (unsigned long) dev->priv; @@ -398,7 +398,7 @@ } -static 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.1.24/linux/drivers/net/eth16i.c Tue Dec 31 21:41:04 1996 +++ linux/drivers/net/eth16i.c Sun Feb 2 15:18:39 1997 @@ -275,21 +275,30 @@ #define RESET ID_ROM_0 /* This is the I/O address list to be probed when seeking the card */ -static unsigned int eth16i_portlist[] = - { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; +static unsigned int eth16i_portlist[] = { + 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 +}; -static unsigned int eth32i_portlist[] = - { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, - 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 }; +static unsigned int eth32i_portlist[] = { + 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, + 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 +}; /* This is the Interrupt lookup table for Eth16i card */ -static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15 }; +static unsigned int eth16i_irqmap[] = { + 9, 10, 5, 15 +}; /* This is the Interrupt lookup table for Eth32i card */ -static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15 }; +static unsigned int eth32i_irqmap[] = { + 3, 5, 7, 9, 10, 11, 12, 15 +}; + #define EISA_IRQ_REG 0xc89 -static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 }; +static unsigned int eth16i_tx_buf_map[] = { + 2048, 2048, 4096, 8192 +}; unsigned int boot = 1; /* Use 0 for production, 1 for verification, >2 for debug */ @@ -299,13 +308,14 @@ static unsigned int eth16i_debug = ETH16I_DEBUG; /* Information for each board */ -struct eth16i_local { - struct enet_statistics stats; - unsigned int tx_started:1; - unsigned char tx_queue; /* Number of packets in transmit buffer */ - unsigned short tx_queue_len; - unsigned int tx_buf_size; - unsigned long open_time; +struct eth16i_local +{ + struct net_device_stats stats; + unsigned int tx_started:1; + unsigned char tx_queue; /* Number of packets in transmit buffer */ + unsigned short tx_queue_len; + unsigned int tx_buf_size; + unsigned long open_time; }; /* Function prototypes */ @@ -330,7 +340,7 @@ static void eth16i_multicast(struct device *dev); static void eth16i_select_regbank(unsigned char regbank, short ioaddr); static void eth16i_initialize(struct device *dev); -static struct enet_statistics *eth16i_get_stats(struct device *dev); +static struct net_device_stats *eth16i_get_stats(struct device *dev); static char *cardname = "ICL EtherTeam 16i/32"; @@ -342,837 +352,845 @@ #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 */ - - /* - 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; - } - - /* 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; - - /* - 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); - - 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( (eth16i_debug & version_printed++) == 0) - printk(version); - - dev->base_addr = ioaddr; - - 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; - } + 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. + */ + + 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 */ + + 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. + */ + + 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 */ + + if(dev == NULL) + dev = init_etherdev(0, sizeof(struct eth16i_local)); + + if( (eth16i_debug & version_printed++) == 0) + printk(version); + + dev->base_addr = ioaddr; + + 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; + } - 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"); - } - } + int i; + int retcode; + unsigned char dummy_packet[64] = { 0 }; - if( eth16i_debug > 1) - printk("Using default port\n"); + /* Powerup the chip */ + outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); - return E_PORT_BNC; -} + BITSET(ioaddr + CONFIG_REG_0, DLC_EN); -static void eth16i_set_port(short ioaddr, int porttype) -{ - unsigned short temp = 0; + 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); + } - eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); - outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG); + dummy_packet[12] = 0x00; + dummy_packet[13] = 0x04; - temp |= DIS_AUTO_PORT_SEL; + eth16i_select_regbank(2, ioaddr); - switch(porttype) { + 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"); + } + } - case E_PORT_BNC : - temp |= AUI_SELECT; - break; + if( eth16i_debug > 1) + printk("Using default port\n"); - case E_PORT_TP : - break; + return E_PORT_BNC; +} - case E_PORT_DIX : - temp |= AUI_SELECT; - BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT); - break; - } - outb(temp, ioaddr + TRANSCEIVER_MODE_REG); +static void eth16i_set_port(short ioaddr, int porttype) +{ + unsigned short temp = 0; + + eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); + outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG); + + temp |= DIS_AUTO_PORT_SEL; + switch(porttype) + { + + case E_PORT_BNC : + temp |= AUI_SELECT; + 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); - 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; - - outb(0xff, ioaddr + TX_STATUS_REG); + int starttime; - outw(l, ioaddr + DATAPORT); - outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1); + outb(0xff, ioaddr + TX_STATUS_REG); - starttime = jiffies; - outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); + outw(l, ioaddr + DATAPORT); + outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1); - while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) { - if( (jiffies - starttime) > TIMEOUT_TICKS) { - break; - } - } + starttime = jiffies; + outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); - 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; + int starttime; - starttime = jiffies; + starttime = jiffies; - while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) { - if( (jiffies - starttime) > TIMEOUT_TICKS) { + 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("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)); - } + 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 */ + 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] == 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( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) + { + creg[2] &= 0x42; + creg[3] &= 0x03; + + 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; - 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; + 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(); - } + 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); + return(data); } static void eth16i_eeprom_cmd(int ioaddr, unsigned char command) { - int i; + 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(); - } + 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; + 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"); - - /* 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)); - - - 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); - - } - - lp->stats.tx_errors++; - - /* Now let's try to restart the adaptor */ - - 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; - - outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - - 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 transmitter from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - - /* 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); - } - } - - 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); + 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. + */ - return 0; -} + 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 */ -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; + 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)); + + + 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); + + } + + lp->stats.tx_errors++; + + /* Now let's try to restart the adaptor */ + + 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; + + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + + dev->tbusy = 0; + dev->trans_start = jiffies; } - 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. - */ + /* Block a timer based transmitter from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if( ioaddr < 0x1000) - insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1); + /* 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 { - unsigned char *buf = skb_put(skb, pkt_len); - unsigned char frag = pkt_len % 4; + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + + outw(length, ioaddr + DATAPORT); - insl(ioaddr + DATAPORT, buf, pkt_len >> 2); + 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; + } - if(frag != 0) { - unsigned short rest[2]; - rest[0] = inw( ioaddr + DATAPORT ); - if(frag == 3) - rest[1] = inw( ioaddr + DATAPORT ); + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag); - } + /* 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++; + return 0; +} - 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"); - } +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 */ + } /* else */ - if(--boguscount <= 0) - break; + if(--boguscount <= 0) + break; - } /* while */ + } /* while */ #if 0 - { - int i; + { + 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); + } - 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); - } + 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++; - - 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); - } - } - } - - if( ( status & 0xff00 ) || - ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) { - eth16i_rx(dev); /* We have packet in receive buffer */ - } + 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; - dev->interrupt = 0; + 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 */ + } - /* Turn interrupts back on */ - outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + dev->interrupt = 0; - return; + /* Turn interrupts back on */ + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + + return; } static void eth16i_multicast(struct device *dev) { - short ioaddr = dev->base_addr; + 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); - } + if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + { + dev->flags|=IFF_PROMISC; /* Must do this */ + outb(3, ioaddr + RECEIVE_MODE_REG); + } else { + outb(2, ioaddr + RECEIVE_MODE_REG); + } } -static struct enet_statistics *eth16i_get_stats(struct device *dev) +static struct net_device_stats *eth16i_get_stats(struct device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = (struct eth16i_local *)dev->priv; - return &lp->stats; + return &lp->stats; } static void eth16i_select_regbank(unsigned char banknbr, short ioaddr) { - unsigned char data; + unsigned char data; - data = inb(ioaddr + CONFIG_REG_1); - outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); + data = inb(ioaddr + CONFIG_REG_1); + outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); } #ifdef MODULE @@ -1181,7 +1199,8 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.1.24/linux/drivers/net/ewrk3.c Tue Dec 31 21:41:04 1996 +++ linux/drivers/net/ewrk3.c Sun Feb 2 15:18:40 1997 @@ -257,7 +257,7 @@ char adapter_name[80]; /* Name exported to /proc/ioports */ u_long shmem_base; /* Shared memory start address */ u_long shmem_length; /* Shared memory window length */ - struct enet_statistics stats; /* Public stats */ + struct net_device_stats stats; /* Public stats */ struct { u32 bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */ u32 unicast; @@ -291,7 +291,7 @@ static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev); static void ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int ewrk3_close(struct device *dev); -static struct enet_statistics *ewrk3_get_stats(struct device *dev); +static struct net_device_stats *ewrk3_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd); @@ -1159,21 +1159,18 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.1.24/linux/drivers/net/fmv18x.c Tue Dec 31 21:41:04 1996 +++ linux/drivers/net/fmv18x.c Sun Feb 2 15:18:40 1997 @@ -70,7 +70,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; long open_time; /* Useless example local info. */ uint tx_started:1; /* Number of packet on the Tx queue. */ uchar tx_queue; /* Number of packet on the Tx queue. */ @@ -113,7 +113,7 @@ static 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); @@ -578,8 +578,7 @@ /* Get the current statistics. This may be called with the card open or closed. */ -static struct enet_statistics * -net_get_stats(struct device *dev) +static struct net_device_stats *net_get_stats(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; @@ -596,8 +595,8 @@ 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)) diff -u --recursive --new-file v2.1.24/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.24/linux/drivers/net/hdlcdrv.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/hdlcdrv.c Sun Feb 2 15:18:40 1997 @@ -518,7 +518,7 @@ /* --------------------------------------------------------------------- */ -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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.1.24/linux/drivers/net/hp100.c Tue Dec 31 21:41:05 1996 +++ linux/drivers/net/hp100.c Sun Feb 2 15:18:40 1997 @@ -151,7 +151,7 @@ int hub_status; /* login to hub was successful? */ u_char mac1_mode; u_char mac2_mode; - struct enet_statistics stats; + struct net_device_stats stats; }; /* @@ -192,7 +192,7 @@ static int hp100_close( struct device *dev ); static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); static void hp100_rx( struct device *dev ); -static struct enet_statistics *hp100_get_stats( struct device *dev ); +static struct net_device_stats *hp100_get_stats( struct device *dev ); static void hp100_update_stats( struct device *dev ); static void hp100_clear_stats( int ioaddr ); static void hp100_set_multicast_list( struct device *dev); @@ -636,14 +636,6 @@ return -EAGAIN; } - if ( skb == NULL ) - { - dev_tint( dev ); - return 0; - } - - if ( skb -> len <= 0 ) return 0; - for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ ) { #ifdef HP100_DEBUG_TX @@ -798,7 +790,7 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v2.1.24/linux/drivers/net/hydra.c Sun Dec 22 16:37:33 1996 +++ linux/drivers/net/hydra.c Sun Feb 2 15:18:40 1997 @@ -47,11 +47,11 @@ #undef HYDRA_DEBUG /* define this for (lots of) debugging information */ #if 0 /* currently hardwired to one transmit buffer */ - #define TX_RING_SIZE 5 - #define RX_RING_SIZE 16 + #define TX_RING_SIZE 5 + #define RX_RING_SIZE 16 #else - #define TX_RING_SIZE 1 - #define RX_RING_SIZE 8 + #define TX_RING_SIZE 1 + #define RX_RING_SIZE 8 #endif #define ETHER_MIN_LEN 64 @@ -65,8 +65,8 @@ * the CIA accesses here are uses to make sure the minimum time * requirement between NIC chip selects is met. */ -#define WRITE_REG(reg, val) (ciaa.pra, ((u_char)(*(nicbase+(reg))=val))) -#define READ_REG(reg) (ciaa.pra, ((u_char)(*(nicbase+(reg))))) +#define WRITE_REG(reg, val) (ciaa.pra, ((u8)(*(nicbase+(reg))=val))) +#define READ_REG(reg) (ciaa.pra, ((u8)(*(nicbase+(reg))))) /* mask value for the interrupts we use */ #define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT) @@ -78,23 +78,23 @@ * Private Device Data */ struct hydra_private - { - u_char *hydra_base; - u_char *hydra_nic_base; - u_short tx_page_start; - u_short rx_page_start; - u_short rx_page_stop; - u_short next_pkt; - struct enet_statistics stats; - int key; - }; +{ + u8 *hydra_base; + u8 *hydra_nic_base; + u16 tx_page_start; + u16 rx_page_start; + u16 rx_page_stop; + u16 next_pkt; + struct net_device_stats stats; + int key; +}; static int hydra_open(struct device *dev); static int hydra_start_xmit(struct sk_buff *skb, struct device *dev); static void hydra_interrupt(int irq, void *data, struct pt_regs *fp); -static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u_char *nicbase); +static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u8 *nicbase); static int hydra_close(struct device *dev); -static struct enet_statistics *hydra_get_stats(struct device *dev); +static struct net_device_stats *hydra_get_stats(struct device *dev); #ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); #endif @@ -106,8 +106,8 @@ #if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM) -static __inline__ void *memcpyw(u_short *dest, u_short *src, int len) - { +static __inline__ void *memcpyw(u16 *dest, u16 *src, int len) +{ __asm__(" move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t" " cmpi.l #2,%/d0 \n\t" "1: bcs.s 2f \n\t" @@ -133,462 +133,460 @@ /* 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 !! */ + /* 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? */ + 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 */ + 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(; len1hydra_base + (priv->tx_page_start<<8) + len1) = 0; -*/ - dev_kfree_skb(skb, FREE_WRITE); - - priv->stats.tx_packets++; - - 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); + /* + * 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; + + 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((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))); + + /* 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(; len1hydra_base + (priv->tx_page_start<<8) + len1) = 0; + dev_kfree_skb(skb, FREE_WRITE); + + priv->stats.tx_packets++; + + 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(); - /* commit the packet to the wire */ - WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP); - sti(); + dev->trans_start = jiffies; - dev->trans_start = jiffies; - - return(0); - } + return(0); +} -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; +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 = (u_short *)(priv->hydra_base + (priv->next_pkt << 8)); + /* remove packet(s) from the ring and commit them to TCP layer */ + WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */ + while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */ + { + board_ram_ptr = (u16 *)(priv->hydra_base + (priv->next_pkt << 8)); #ifdef HYDRA_DEBUG - printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr); + printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr); #endif - /* the following must be done with two steps, or - GCC optimizes it to a byte access to Hydra memory, - which doesn't work... */ - hdr_next_pkt = board_ram_ptr[0]; - hdr_next_pkt >>= 8; + /* the following must be done with two steps, or + GCC optimizes it to a byte access to Hydra memory, + which doesn't work... */ + hdr_next_pkt = board_ram_ptr[0]; + hdr_next_pkt >>= 8; - pkt_len = board_ram_ptr[1]; - pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8)); + pkt_len = board_ram_ptr[1]; + pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8)); #ifdef HYDRA_DEBUG - printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len); + printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len); #endif - if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN) - { - /* note that board_ram_ptr is u_short */ - /* CRC is not included in the packet length */ - - pkt_len -= 4; - skb = dev_alloc_skb(pkt_len+2); - if(skb == NULL) - { - printk("%s: memory squeeze, dropping packet.\n", dev->name); - priv->stats.rx_dropped++; - } - else - { - skb->dev = dev; - skb_reserve(skb, 2); + if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN) + { + /* note that board_ram_ptr is u16 */ + /* CRC is not included in the packet length */ - if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start) - { - /* here, the packet is wrapped */ - len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4; - - memcpyw((u_short *)skb_put(skb, len1), (u_short *)(board_ram_ptr+2), len1); - memcpyw((u_short *)skb_put(skb, pkt_len-len1), (u_short *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1); - + pkt_len -= 4; + skb = dev_alloc_skb(pkt_len+2); + if(skb == NULL) + { + printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped++; + } + else + { + skb->dev = dev; + skb_reserve(skb, 2); + if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start) + { + /* here, the packet is wrapped */ + len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4; + + memcpyw((u16 *)skb_put(skb, len1), (u16 *)(board_ram_ptr+2), len1); + memcpyw((u16 *)skb_put(skb, pkt_len-len1), (u16 *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1); + #ifdef HYDRA_DEBUG - printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1); + printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1); #endif - } /* ... here, packet is not wrapped */ - else memcpyw((u_short *) skb_put(skb, pkt_len), (u_short *)(board_ram_ptr+2), pkt_len); - } - /* if(skb == NULL) ... */ - } - else - { - WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA); - printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR)); + } /* ... here, packet is not wrapped */ + else + memcpyw((u16 *) skb_put(skb, pkt_len), (u16 *)(board_ram_ptr+2), pkt_len); + } + } + else + { + WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA); + printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR)); /* this is the error i kept getting until i switched to 0.9.10. it still doesn't mean that the bug would have gone away - so be alarmed. the packet is likely @@ -596,45 +594,47 @@ 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; - } - - /* 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; - - /* 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); - - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - priv->stats.rx_packets++; + + 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); + + /* 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); + + /* 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++; - } - return; - } + } + return; +} -static struct enet_statistics *hydra_get_stats(struct device *dev) +static struct net_device_stats *hydra_get_stats(struct device *dev) { struct hydra_private *priv = (struct hydra_private *)dev->priv; #if 0 - u_char *board = priv->hydra_base; + u8 *board = priv->hydra_base; short saved_addr; #endif @@ -643,17 +643,15 @@ 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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.1.24/linux/drivers/net/ibmtr.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/ibmtr.c Sun Feb 2 15:18:40 1997 @@ -174,7 +174,7 @@ static int tok_open(struct device *dev); static int tok_close(struct device *dev); static int tok_send_packet(struct sk_buff *skb, struct device *dev); -static struct enet_statistics * tok_get_stats(struct device *dev); +static struct net_device_stats * tok_get_stats(struct device *dev); void tr_readlog(struct device *dev); /* FIXME: Should use init_timer and friends not assume the structure @@ -1561,11 +1561,11 @@ 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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.1.24/linux/drivers/net/lance.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/lance.c Sun Feb 2 15:18:40 1997 @@ -234,7 +234,7 @@ int cur_rx, cur_tx; /* The next free ring entry */ int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ int dma; - struct enet_statistics stats; + struct net_device_stats stats; unsigned char chip_version; /* See lance_chip_type. */ char tx_full; unsigned long lock; @@ -294,7 +294,7 @@ static int lance_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); @@ -777,8 +777,7 @@ outw(csr0_bits, dev->base_addr + LANCE_DATA); } -static int -lance_start_xmit(struct sk_buff *skb, struct device *dev) +static int lance_start_xmit(struct sk_buff *skb, struct device *dev) { struct lance_private *lp = (struct lance_private *)dev->priv; int ioaddr = dev->base_addr; @@ -820,14 +819,6 @@ return 0; } - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - if (skb->len <= 0) - return 0; - if (lance_debug > 3) { outw(0x0000, ioaddr+LANCE_ADDR); printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, @@ -881,7 +872,8 @@ lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000; } lp->cur_tx++; - + lp->stats.tx_bytes+=skb->len; + /* Trigger an immediate send poll. */ outw(0x0000, ioaddr+LANCE_ADDR); outw(0x0048, ioaddr+LANCE_DATA); @@ -1088,9 +1080,10 @@ eth_copy_and_sum(skb, (unsigned char *)bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)), pkt_len,0); + lp->stats.rx_bytes+=skb->len; skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); lp->stats.rx_packets++; + netif_rx(skb); } } /* The docs say that the buffer length isn't touched, but Andrew Boyd @@ -1139,8 +1132,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/lance32.c linux/drivers/net/lance32.c --- v2.1.24/linux/drivers/net/lance32.c Wed Oct 9 08:55:19 1996 +++ linux/drivers/net/lance32.c Sun Feb 2 15:18:40 1997 @@ -132,7 +132,7 @@ int cur_rx, cur_tx; /* The next free ring entry */ int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ int dma; - struct enet_statistics stats; + struct net_device_stats stats; char tx_full; unsigned long lock; }; @@ -143,7 +143,7 @@ static int lance32_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); @@ -785,8 +785,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c --- v2.1.24/linux/drivers/net/lapbether.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/lapbether.c Sun Feb 2 15:18:40 1997 @@ -74,7 +74,7 @@ char ethname[14]; /* ether device name */ struct device *ethdev; /* link to ethernet device */ struct device axdev; /* lapbeth device (lapb#) */ - struct enet_statistics stats; /* some statistics */ + struct net_device_stats stats; /* some statistics */ } *lapbeth_devices = NULL; @@ -330,7 +330,7 @@ /* * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.1.24/linux/drivers/net/loopback.c Thu Jan 2 15:55:18 1997 +++ linux/drivers/net/loopback.c Sun Feb 2 15:18:40 1997 @@ -60,10 +60,14 @@ */ static int loopback_xmit(struct sk_buff *skb, struct device *dev) { - struct enet_statistics *stats = (struct enet_statistics *)dev->priv; - + struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + + /* + * Take this out if the debug says its ok + */ + if (skb == NULL || dev == NULL) - return(0); + printk(KERN_DEBUG "loopback fed NULL data - splat\n"); /* * Optimise so buffers with skb->free=1 are not copied but @@ -96,9 +100,9 @@ return(0); } -static struct enet_statistics *get_stats(struct device *dev) +static struct net_device_stats *get_stats(struct device *dev) { - return (struct enet_statistics *)dev->priv; + return (struct net_device_stats *)dev->priv; } static int loopback_open(struct device *dev) @@ -130,10 +134,10 @@ dev->pa_mask = in_aton("255.0.0.0"); dev->pa_alen = 4; #endif - dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct enet_statistics)); + memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; /* diff -u --recursive --new-file v2.1.24/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.24/linux/drivers/net/ltpc.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ltpc.c Sun Feb 2 15:18:40 1997 @@ -0,0 +1,1281 @@ +/*** ltpc.c -- a driver for the LocalTalk PC card. + * + * Copyright (c) 1995,1996 Bradford W. Johnson + * + * 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 /* for CONFIG_MAX_16M */ + +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +/* 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;icbuf[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;iQWrite) { + 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;ilen;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<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<=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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/ltpc.h linux/drivers/net/ltpc.h --- v2.1.24/linux/drivers/net/ltpc.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ltpc.h Sun Feb 2 15:18:40 1997 @@ -0,0 +1,73 @@ +/*** ltpc.h + * + * + ***/ + +#define LT_GETRESULT 0x00 +#define LT_WRITEMEM 0x01 +#define LT_READMEM 0x02 +#define LT_GETFLAGS 0x04 +#define LT_SETFLAGS 0x05 +#define LT_INIT 0x10 +#define LT_SENDLAP 0x13 +#define LT_RCVLAP 0x14 + +/* the flag that we care about */ +#define LT_FLAG_ALLLAP 0x04 + +struct lt_getresult { + unsigned char command; + unsigned char mailbox; +}; + +struct lt_mem { + unsigned char command; + unsigned char mailbox; + unsigned short addr; /* host order */ + unsigned short length; /* host order */ +}; + +struct lt_setflags { + unsigned char command; + unsigned char mailbox; + unsigned char flags; +}; + +struct lt_getflags { + unsigned char command; + unsigned char mailbox; +}; + +struct lt_init { + unsigned char command; + unsigned char mailbox; + unsigned char hint; +}; + +struct lt_sendlap { + unsigned char command; + unsigned char mailbox; + unsigned char dnode; + unsigned char laptype; + unsigned short length; /* host order */ +}; + +struct lt_rcvlap { + unsigned char command; + unsigned char dnode; + unsigned char snode; + unsigned char laptype; + unsigned short length; /* host order */ +}; + +union lt_command { + struct lt_getresult getresult; + struct lt_mem mem; + struct lt_setflags setflags; + struct lt_getflags getflags; + struct lt_init init; + struct lt_sendlap sendlap; + struct lt_rcvlap rcvlap; +}; +typedef union lt_command lt_command; + diff -u --recursive --new-file v2.1.24/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c --- v2.1.24/linux/drivers/net/mkiss.c Thu Jan 2 15:55:18 1997 +++ linux/drivers/net/mkiss.c Sun Feb 2 15:18:40 1997 @@ -643,12 +643,12 @@ } -static struct enet_statistics *ax_get_stats(struct device *dev) +static struct net_device_stats *ax_get_stats(struct device *dev) { - static struct enet_statistics stats; + static struct net_device_stats stats; struct ax_disp *ax = (struct ax_disp*)dev->priv; - memset(&stats, 0, sizeof(struct enet_statistics)); + memset(&stats, 0, sizeof(struct net_device_stats)); stats.rx_packets = ax->rx_packets; stats.tx_packets = ax->tx_packets; @@ -839,7 +839,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.24/linux/drivers/net/myri_sbus.c Sun Dec 22 16:37:34 1996 +++ linux/drivers/net/myri_sbus.c Sun Feb 2 15:18:40 1997 @@ -819,7 +819,7 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/myri_sbus.h linux/drivers/net/myri_sbus.h --- v2.1.24/linux/drivers/net/myri_sbus.h Sun Dec 22 16:37:34 1996 +++ linux/drivers/net/myri_sbus.h Sun Feb 2 15:18:40 1997 @@ -278,7 +278,7 @@ 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. */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.1.24/linux/drivers/net/net_init.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/net_init.c Sun Feb 2 15:18:40 1997 @@ -39,6 +39,7 @@ #include #include #include +#include /* The network devices currently exist only in the socket namespace, so these entries are unused. The only ones that make sense are @@ -243,6 +244,50 @@ dev->pa_mask = 0; dev->pa_alen = 4; return; +} + +#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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.1.24/linux/drivers/net/ni52.c Tue Dec 31 21:41:05 1996 +++ linux/drivers/net/ni52.c Sun Feb 2 15:18:40 1997 @@ -164,7 +164,8 @@ #define DELAY_18(); { __delay( (loops_per_sec>>18)+1 ); } /* wait for command with timeout: */ -#define WAIT_4_SCB_CMD() { int i; \ +#define WAIT_4_SCB_CMD() +{ int i; \ for(i=0;i<16384;i++) { \ if(!p->scb->cmd_cuc) break; \ DELAY_18(); \ @@ -195,7 +196,7 @@ static int ni52_open(struct device *dev); static int ni52_close(struct device *dev); static int ni52_send_packet(struct sk_buff *,struct device *); -static struct enet_statistics *ni52_get_stats(struct device *dev); +static struct net_device_stats *ni52_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); #if 0 static void ni52_dump(struct device *,void *); @@ -213,24 +214,24 @@ struct priv { - struct enet_statistics stats; - unsigned long base; - char *memtop; - int lock,reseted; - volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; - volatile struct scp_struct *scp; /* volatile is important */ - volatile struct iscp_struct *iscp; /* volatile is important */ - volatile struct scb_struct *scb; /* volatile is important */ - volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; - volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; + struct net_device_stats stats; + unsigned long base; + char *memtop; + int lock,reseted; + volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; + volatile struct scp_struct *scp; /* volatile is important */ + volatile struct iscp_struct *iscp; /* volatile is important */ + volatile struct scb_struct *scb; /* volatile is important */ + volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; + volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; #if (NUM_XMIT_BUFFS == 1) - volatile struct nop_cmd_struct *nop_cmds[2]; + volatile struct nop_cmd_struct *nop_cmds[2]; #else - volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; + volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; #endif - volatile int nop_point,num_recv_buffs; - volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; - volatile int xmit_count,xmit_last; + volatile int nop_point,num_recv_buffs; + volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; + volatile int xmit_count,xmit_last; }; /********************************************** @@ -238,17 +239,17 @@ */ static int ni52_close(struct device *dev) { - free_irq(dev->irq, NULL); - irq2dev_map[dev->irq] = NULL; + free_irq(dev->irq, NULL); + irq2dev_map[dev->irq] = NULL; - ni_reset586(); /* the hard way to stop the receiver */ + ni_reset586(); /* the hard way to stop the receiver */ - dev->start = 0; - dev->tbusy = 0; + dev->start = 0; + dev->tbusy = 0; - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; - return 0; + return 0; } /********************************************** @@ -256,26 +257,26 @@ */ static int ni52_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; + 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; + MOD_INC_USE_COUNT; - return 0; /* most done by init */ + return 0; /* most done by init */ } /********************************************** @@ -283,41 +284,41 @@ */ 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;iscp)[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;iscp)[i]) + return 0; + p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */ + if(p->scp->sysbus != SYSBUSVAL) + return 0; + + iscp_addrs[0] = bus_to_virt((unsigned long)where); + iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct); + + for(i=0;i<2;i++) + { + p->iscp = (struct iscp_struct *) iscp_addrs[i]; + memset((char *)p->iscp,0, sizeof(struct iscp_struct)); + + p->scp->iscp = make24(p->iscp); + p->iscp->busy = 1; + + ni_reset586(); + ni_attn586(); + DELAY(1); /* wait a while... */ + + if(p->iscp->busy) /* i82586 clears 'busy' after successful init */ + return 0; + } + return 1; } /****************************************************************** @@ -325,34 +326,34 @@ */ void alloc586(struct device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = (struct priv *) dev->priv; - ni_reset586(); - DELAY(1); + ni_reset586(); + DELAY(1); - p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); - p->scb = (struct scb_struct *) bus_to_virt(dev->mem_start); - p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct)); + p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); + p->scb = (struct scb_struct *) bus_to_virt(dev->mem_start); + p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct)); - memset((char *) p->iscp,0,sizeof(struct iscp_struct)); - memset((char *) p->scp ,0,sizeof(struct scp_struct)); + memset((char *) p->iscp,0,sizeof(struct iscp_struct)); + memset((char *) p->scp ,0,sizeof(struct scp_struct)); - p->scp->iscp = make24(p->iscp); - p->scp->sysbus = SYSBUSVAL; - p->iscp->scb_offset = make16(p->scb); + p->scp->iscp = make24(p->iscp); + p->scp->sysbus = SYSBUSVAL; + p->iscp->scb_offset = make16(p->scb); - p->iscp->busy = 1; - ni_reset586(); - ni_attn586(); + p->iscp->busy = 1; + ni_reset586(); + ni_attn586(); - DELAY(1); + DELAY(1); - if(p->iscp->busy) - printk("%s: Init-Problems (alloc).\n",dev->name); + if(p->iscp->busy) + printk("%s: Init-Problems (alloc).\n",dev->name); - p->reseted = 0; + p->reseted = 0; - memset((char *)p->scb,0,sizeof(struct scb_struct)); + memset((char *)p->scb,0,sizeof(struct scb_struct)); } /********************************************** @@ -361,172 +362,172 @@ 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;idev_addr[i] = inb(dev->base_addr+i); + for(i=0;idev_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; + 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; + return 0; } /********************************************** @@ -536,230 +537,232 @@ 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;inext) - 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;inext) + 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;inop_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;inop_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 */ + ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */ - /* - * alloc xmit-buffs / init xmit_cmds - */ - for(i=0;ixmit_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])); - } + /* + * alloc xmit-buffs / init xmit_cmds + */ + for(i=0;ixmit_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; + p->xmit_count = 0; + p->xmit_last = 0; #ifndef NO_NOPCOMMANDS - p->nop_point = 0; + p->nop_point = 0; #endif - /* - * 'start transmitter' - */ + /* + * 'start transmitter' + */ #ifndef NO_NOPCOMMANDS - p->scb->cbl_offset = make16(p->nop_cmds[0]); - p->scb->cmd_cuc = CUC_START; - ni_attn586(); - WAIT_4_SCB_CMD(); + p->scb->cbl_offset = make16(p->nop_cmds[0]); + p->scb->cmd_cuc = CUC_START; + ni_attn586(); + WAIT_4_SCB_CMD(); #else - p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]); - p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_SUSPEND | CMD_INT; + p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]); + p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_SUSPEND | CMD_INT; #endif - /* - * ack. interrupts - */ - p->scb->cmd_cuc = p->scb->cus & STAT_MASK; - ni_attn586(); - DELAY_16(); + /* + * ack. interrupts + */ + p->scb->cmd_cuc = p->scb->cus & STAT_MASK; + ni_attn586(); + DELAY_16(); - ni_enaint(); + ni_enaint(); - return 0; + return 0; } /****************************************************** @@ -769,43 +772,43 @@ static 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; - - 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 */ - - ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) ); - - 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)); - - for(i=0;inum_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; - } + 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; + + 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) ); + + 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)); + + for(i=0;inum_recv_buffs;i++) + { + rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs)); + rbd[i].size = RECV_BUFF_SIZE; + rbd[i].buffer = make24(ptr); + ptr = (char *) ptr + RECV_BUFF_SIZE; + } - p->rfd_top = p->rfd_first; - p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd); + p->rfd_top = p->rfd_first; + p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd); - p->scb->rfa_offset = make16(p->rfd_first); - p->rfd_first->rbd_offset = make16(rbd); + p->scb->rfa_offset = make16(p->rfd_first); + p->rfd_first->rbd_offset = make16(rbd); - return ptr; + return ptr; } @@ -815,76 +818,76 @@ static void 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); - } - } + 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); + if(stat & STAT_CX) /* command with I-bit set complete */ + ni52_xmt_int(dev); #ifndef NO_NOPCOMMANDS - if(stat & STAT_CNA) /* CU went 'not ready' */ - { - if(dev->start) - printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus); - } + if(stat & STAT_CNA) /* CU went 'not ready' */ + { + if(dev->start) + printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus); + } #endif - if(debuglevel > 1) - printk("%d",cnt++); + if(debuglevel > 1) + printk("%d",cnt++); - WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */ - if(p->scb->cmd_cuc) /* timed out? */ - { - printk("%s: Acknowledge timed out.\n",dev->name); - ni_disint(); - break; - } - } + WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */ + if(p->scb->cmd_cuc) /* timed out? */ + { + printk("%s: Acknowledge timed out.\n",dev->name); + ni_disint(); + break; + } + } - if(debuglevel > 1) - printk("i"); + if(debuglevel > 1) + printk("i"); - dev->interrupt = 0; + dev->interrupt = 0; } /******************************************************* @@ -893,121 +896,121 @@ static void ni52_rcv_int(struct device *dev) { - int status,cnt=0; - unsigned short totlen; - struct sk_buff *skb; - struct rbd_struct *rbd; - struct priv *p = (struct priv *) dev->priv; - - if(debuglevel > 0) - printk("R"); - - for(;(status = p->rfd_top->stat_high) & RFD_COMPL;) - { - rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); - - if(status & RFD_OK) /* frame received without error? */ - { - if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */ - { - totlen &= RBD_MASK; /* length of this frame */ - rbd->status = 0; - skb = (struct sk_buff *) dev_alloc_skb(totlen+2); - if(skb != NULL) - { - skb->dev = dev; - skb_reserve(skb,2); - skb_put(skb,totlen); - eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - p->stats.rx_packets++; - } - else - p->stats.rx_dropped++; - } - else - { - int rstat; - /* free all RBD's until RBD_LAST is set */ - totlen = 0; - while(!((rstat=rbd->status) & RBD_LAST)) - { - totlen += rstat & RBD_MASK; - if(!rstat) - { - printk("%s: Whoops .. no end mark in RBD list\n",dev->name); - break; - } - rbd->status = 0; - rbd = (struct rbd_struct *) make32(rbd->next); - } - totlen += rstat & RBD_MASK; - rbd->status = 0; - printk("%s: received oversized frame! length: %d\n",dev->name,totlen); - p->stats.rx_dropped++; - } - } - else /* frame !(ok), only with 'save-bad-frames' */ - { - printk("%s: oops! rfd-error-status: %04x\n",dev->name,status); - p->stats.rx_errors++; - } - p->rfd_top->stat_high = 0; - p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */ - p->rfd_top->rbd_offset = 0xffff; - p->rfd_last->last = 0; /* delete RFD_SUSP */ - p->rfd_last = p->rfd_top; - p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ - p->scb->rfa_offset = make16(p->rfd_top); - - if(debuglevel > 0) - printk("%d",cnt++); - } - - if(automatic_resume) - { - WAIT_4_SCB_CMD(); - p->scb->cmd_ruc = RUC_RESUME; - ni_attn586(); - WAIT_4_SCB_CMD_RUC(); - } + int status,cnt=0; + unsigned short totlen; + struct sk_buff *skb; + struct rbd_struct *rbd; + struct priv *p = (struct priv *) dev->priv; + + if(debuglevel > 0) + printk("R"); + + for(;(status = p->rfd_top->stat_high) & RFD_COMPL;) + { + rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); + + if(status & RFD_OK) /* frame received without error? */ + { + if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */ + { + totlen &= RBD_MASK; /* length of this frame */ + rbd->status = 0; + skb = (struct sk_buff *) dev_alloc_skb(totlen+2); + if(skb != NULL) + { + skb->dev = dev; + skb_reserve(skb,2); + skb_put(skb,totlen); + eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + p->stats.rx_packets++; + } + else + p->stats.rx_dropped++; + } + else + { + int rstat; + /* free all RBD's until RBD_LAST is set */ + totlen = 0; + while(!((rstat=rbd->status) & RBD_LAST)) + { + totlen += rstat & RBD_MASK; + if(!rstat) + { + printk("%s: Whoops .. no end mark in RBD list\n",dev->name); + break; + } + rbd->status = 0; + rbd = (struct rbd_struct *) make32(rbd->next); + } + totlen += rstat & RBD_MASK; + rbd->status = 0; + printk("%s: received oversized frame! length: %d\n",dev->name,totlen); + p->stats.rx_dropped++; + } + } + else /* frame !(ok), only with 'save-bad-frames' */ + { + printk("%s: oops! rfd-error-status: %04x\n",dev->name,status); + p->stats.rx_errors++; + } + p->rfd_top->stat_high = 0; + p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */ + p->rfd_top->rbd_offset = 0xffff; + p->rfd_last->last = 0; /* delete RFD_SUSP */ + p->rfd_last = p->rfd_top; + p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ + p->scb->rfa_offset = make16(p->rfd_top); + + if(debuglevel > 0) + printk("%d",cnt++); + } + + if(automatic_resume) + { + WAIT_4_SCB_CMD(); + p->scb->cmd_ruc = RUC_RESUME; + ni_attn586(); + WAIT_4_SCB_CMD_RUC(); + } #ifdef WAIT_4_BUSY - { - int i; - for(i=0;i<1024;i++) - { - if(p->rfd_top->status) - break; - DELAY_16(); - if(i == 1023) - printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name); - } - } + { + int i; + for(i=0;i<1024;i++) + { + if(p->rfd_top->status) + break; + DELAY_16(); + if(i == 1023) + printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name); + } + } #endif #ifdef 0 - if(!at_least_one) - { - int i; - volatile struct rfd_struct *rfds=p->rfd_top; - volatile struct rbd_struct *rbds; - printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least); - for(i=0;i< (p->num_recv_buffs+4);i++) - { - rbds = (struct rbd_struct *) make32(rfds->rbd_offset); - printk("%04x:%04x ",rfds->status,rbds->status); - rfds = (struct rfd_struct *) make32(rfds->next); - } - printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status); - printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus); - } - old_at_least = at_least_one; + if(!at_least_one) + { + int i; + volatile struct rfd_struct *rfds=p->rfd_top; + volatile struct rbd_struct *rbds; + printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least); + for(i=0;i< (p->num_recv_buffs+4);i++) + { + rbds = (struct rbd_struct *) make32(rfds->rbd_offset); + printk("%04x:%04x ",rfds->status,rbds->status); + rfds = (struct rfd_struct *) make32(rfds->next); + } + printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status); + printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus); + } + old_at_least = at_least_one; #endif - if(debuglevel > 0) - printk("r"); + if(debuglevel > 0) + printk("r"); } /********************************************************** @@ -1016,20 +1019,20 @@ static void ni52_rnr_int(struct device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = (struct priv *) dev->priv; - p->stats.rx_errors++; + p->stats.rx_errors++; - WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */ - p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ - ni_attn586(); - WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */ + WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */ + p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ + ni_attn586(); + WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */ - alloc_rfa(dev,(char *)p->rfd_first); + alloc_rfa(dev,(char *)p->rfd_first); /* maybe add a check here, before restarting the RU */ - startrecv586(dev); /* restart RU */ + startrecv586(dev); /* restart RU */ - printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus); + printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus); } @@ -1039,51 +1042,51 @@ static void ni52_xmt_int(struct device *dev) { - int status; - struct priv *p = (struct priv *) dev->priv; + int status; + struct priv *p = (struct priv *) dev->priv; - if(debuglevel > 0) - printk("X"); + 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; - } - } + status = p->xmit_cmds[p->xmit_last]->cmd_status; + if(!(status & STAT_COMPL)) + printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name); + + if(status & STAT_OK) + { + p->stats.tx_packets++; + p->stats.collisions += (status & TCMD_MAXCOLLMASK); + } + else + { + p->stats.tx_errors++; + if(status & TCMD_LATECOLL) { + printk("%s: late collision detected.\n",dev->name); + p->stats.collisions++; + } + else if(status & TCMD_NOCARRIER) { + p->stats.tx_carrier_errors++; + printk("%s: no carrier detected.\n",dev->name); + } + else if(status & TCMD_LOSTCTS) + printk("%s: loss of CTS detected.\n",dev->name); + else if(status & TCMD_UNDERRUN) { + p->stats.tx_fifo_errors++; + printk("%s: DMA underrun detected.\n",dev->name); + } + else if(status & TCMD_MAXCOLL) { + printk("%s: Max. collisions exceeded.\n",dev->name); + p->stats.collisions += 16; + } + } #if (NUM_XMIT_BUFFS > 1) - if( (++p->xmit_last) == NUM_XMIT_BUFFS) - p->xmit_last = 0; + if( (++p->xmit_last) == NUM_XMIT_BUFFS) + p->xmit_last = 0; #endif - dev->tbusy = 0; - mark_bh(NET_BH); + dev->tbusy = 0; + mark_bh(NET_BH); } /*********************************************************** @@ -1092,14 +1095,14 @@ static void startrecv586(struct device *dev) { - struct priv *p = (struct priv *) dev->priv; + 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!!) */ + WAIT_4_SCB_CMD(); + WAIT_4_SCB_CMD_RUC(); + p->scb->rfa_offset = make16(p->rfd_first); + p->scb->cmd_ruc = RUC_START; + ni_attn586(); /* start cmd. */ + WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */ } /****************************************************** @@ -1108,182 +1111,182 @@ static 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[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[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; + 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; + 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; + return &p->stats; } /******************************************************** @@ -1291,35 +1294,35 @@ */ 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; - } - - dev->start = 0; - - ni_disint(); - alloc586(dev); - init586(dev); - startrecv586(dev); - ni_enaint(); + if(!dev->start) + { + printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name); + return; + } + + dev->start = 0; + + ni_disint(); + alloc586(dev); + init586(dev); + startrecv586(dev); + ni_enaint(); - dev->start = 1; + dev->start = 1; } #ifdef MODULE static struct device dev_ni52 = { - " ", /* "ni5210": device name inserted by net_init.c */ - 0, 0, 0, 0, - 0x300, 9, /* I/O address, IRQ */ - 0, 0, 0, NULL, ni52_probe }; + " ", /* "ni5210": device name inserted by net_init.c */ + 0, 0, 0, 0, + 0x300, 9, /* I/O address, IRQ */ + 0, 0, 0, NULL, ni52_probe }; /* set: io,irq,memstart,memend or set it when calling insmod */ int irq=9; int io=0x300; long memstart=0; /* e.g 0xd0000 */ -long memend=0; /* e.g 0xd4000 */ +long memend=0; /* e.g 0xd4000 */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -1328,25 +1331,25 @@ int init_module(void) { - if(io <= 0x0 || !memend || !memstart || irq < 2) { - printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); - return -ENODEV; - } - dev_ni52.irq = irq; - dev_ni52.base_addr = io; - dev_ni52.mem_end = memend; - dev_ni52.mem_start = memstart; - if (register_netdev(&dev_ni52) != 0) - return -EIO; - return 0; + if(io <= 0x0 || !memend || !memstart || irq < 2) { + printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); + return -ENODEV; + } + dev_ni52.irq = irq; + dev_ni52.base_addr = io; + dev_ni52.mem_end = memend; + dev_ni52.mem_start = memstart; + if (register_netdev(&dev_ni52) != 0) + return -EIO; + return 0; } void cleanup_module(void) { - release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); - kfree(dev_ni52.priv); - dev_ni52.priv = NULL; - unregister_netdev(&dev_ni52); + release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); + kfree(dev_ni52.priv); + dev_ni52.priv = NULL; + unregister_netdev(&dev_ni52); } #endif /* MODULE */ @@ -1356,34 +1359,34 @@ */ void 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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.1.24/linux/drivers/net/ni65.c Tue Dec 31 21:41:05 1996 +++ linux/drivers/net/ni65.c Sun Feb 2 15:18:40 1997 @@ -195,27 +195,27 @@ struct priv { - struct rmd rmdhead[RMDNUM]; - struct tmd tmdhead[TMDNUM]; - struct init_block ib; - int rmdnum; - int tmdnum,tmdlast; + struct rmd rmdhead[RMDNUM]; + struct tmd tmdhead[TMDNUM]; + struct init_block ib; + int rmdnum; + int tmdnum,tmdlast; #ifdef RCV_VIA_SKB - struct sk_buff *recv_skb[RMDNUM]; + struct sk_buff *recv_skb[RMDNUM]; #else - void *recvbounce[RMDNUM]; + void *recvbounce[RMDNUM]; #endif #ifdef XMT_VIA_SKB - struct sk_buff *tmd_skb[TMDNUM]; + struct sk_buff *tmd_skb[TMDNUM]; #endif - void *tmdbounce[TMDNUM]; - int tmdbouncenum; - int lock,xmit_queued; - struct enet_statistics stats; - void *self; - int cmdr_addr; - int cardno; - int features; + void *tmdbounce[TMDNUM]; + int tmdbouncenum; + int lock,xmit_queued; + struct net_device_stats stats; + void *self; + int cmdr_addr; + int cardno; + int features; }; static int ni65_probe1(struct device *dev,int); @@ -229,7 +229,7 @@ static int ni65_close(struct device *dev); static int ni65_alloc_buffer(struct device *dev); static void ni65_free_buffer(struct priv *p); -static struct enet_statistics *ni65_get_stats(struct device *); +static struct net_device_stats *ni65_get_stats(struct device *); static void set_multicast_list(struct device *dev); static int irqtab[] = { 9,12,15,5 }; /* irq config-translate */ @@ -242,22 +242,22 @@ */ static 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; - - 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(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 */ - outw(CSR0,PORT+L_ADDRREG); /* switch back to CSR0 */ + outw(CSR0,PORT+L_ADDRREG); /* switch back to CSR0 */ } /* @@ -265,31 +265,31 @@ */ static int ni65_open(struct device *dev) { - struct priv *p = (struct priv *) dev->priv; - int irqval = request_irq(dev->irq, &ni65_interrupt,0, + struct priv *p = (struct priv *) dev->priv; + int irqval = request_irq(dev->irq, &ni65_interrupt,0, cards[p->cardno].cardname,NULL); - if (irqval) { - printk ("%s: unable to get IRQ %d (irqval=%d).\n", - dev->name,dev->irq, irqval); - return -EAGAIN; - } - irq2dev_map[dev->irq] = dev; - - if(ni65_lance_reinit(dev)) - { - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - MOD_INC_USE_COUNT; - return 0; - } - else - { - irq2dev_map[dev->irq] = NULL; - free_irq(dev->irq,NULL); - dev->start = 0; - return -EAGAIN; - } + if (irqval) { + printk ("%s: unable to get IRQ %d (irqval=%d).\n", + dev->name,dev->irq, irqval); + return -EAGAIN; + } + irq2dev_map[dev->irq] = dev; + + if(ni65_lance_reinit(dev)) + { + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + MOD_INC_USE_COUNT; + return 0; + } + else + { + irq2dev_map[dev->irq] = NULL; + free_irq(dev->irq,NULL); + dev->start = 0; + return -EAGAIN; + } } /* @@ -297,28 +297,28 @@ */ static int ni65_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;itmd_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; + { + int i; + for(i=0;itmd_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; } /* @@ -329,21 +329,21 @@ #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; - - for (port = ports; *port; port++) - { - if (ni65_probe1(dev, *port) == 0) - return 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; + + for (port = ports; *port; port++) + { + if (ni65_probe1(dev, *port) == 0) + return 0; + } - return -ENODEV; + return -ENODEV; } /* @@ -351,139 +351,139 @@ */ static int ni65_probe1(struct device *dev,int ioaddr) { - int i,j; - struct priv *p; + int i,j; + struct priv *p; - for(i=0;i= 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) { + for(i=0;i= 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; + 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 */ + return 0; /* everything is OK */ } /* @@ -491,33 +491,33 @@ */ 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; - - 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 */ - - for(i=0;i<32;i++) - { - udelay(4000); - if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) ) - break; /* init ok ? */ - } + 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); + + 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 ? */ + } } /* @@ -525,37 +525,37 @@ */ static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type) { - struct sk_buff *skb=NULL; - unsigned char *ptr; - void *ret; - - if(type) { - ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA); - if(!skb) { - printk("%s: unable to allocate %s memory.\n",dev->name,what); - return NULL; - } - skb->dev = dev; - skb_reserve(skb,2+16); - skb_put(skb,R_BUF_SIZE); /* grab the whole space .. (not necessary) */ - ptr = skb->data; - } - else { - ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA); - if(!ret) { - printk("%s: unable to allocate %s memory.\n",dev->name,what); - return NULL; - } - } - if( (u32) virt_to_bus(ptr+size) > 0x1000000) { - printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); - if(type) - kfree_skb(skb,FREE_WRITE); - else - kfree(ptr); - return NULL; - } - return ret; + struct sk_buff *skb=NULL; + unsigned char *ptr; + void *ret; + + if(type) { + ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA); + if(!skb) { + printk("%s: unable to allocate %s memory.\n",dev->name,what); + return NULL; + } + skb->dev = dev; + skb_reserve(skb,2+16); + skb_put(skb,R_BUF_SIZE); /* grab the whole space .. (not necessary) */ + ptr = skb->data; + } + else { + ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA); + if(!ret) { + printk("%s: unable to allocate %s memory.\n",dev->name,what); + return NULL; + } + } + if( (u32) virt_to_bus(ptr+size) > 0x1000000) { + printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); + if(type) + kfree_skb(skb,FREE_WRITE); + else + kfree(ptr); + return NULL; + } + return ret; } /* @@ -563,51 +563,51 @@ */ static 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; + 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;itmd_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;itmd_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;irecv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1); - if(!p->recv_skb[i]) { - ni65_free_buffer(p); - return -ENOMEM; - } + p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1); + if(!p->recv_skb[i]) { + ni65_free_buffer(p); + return -ENOMEM; + } #else - p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0); - if(!p->recvbounce[i]) { - ni65_free_buffer(p); - return -ENOMEM; - } + p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0); + if(!p->recvbounce[i]) { + ni65_free_buffer(p); + return -ENOMEM; + } #endif - } + } - return 0; /* everything is OK */ + return 0; /* everything is OK */ } /* @@ -615,32 +615,32 @@ */ static void ni65_free_buffer(struct priv *p) { - int i; + int i; - if(!p) - return; + if(!p) + return; - for(i=0;itmdbounce[i]) - kfree(p->tmdbounce[i]); + for(i=0;itmdbounce[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;irecv_skb[i]) - dev_kfree_skb(p->recv_skb[i],FREE_WRITE); + if(p->recv_skb[i]) + dev_kfree_skb(p->recv_skb[i],FREE_WRITE); #else - if(p->recvbounce[i]) - kfree(p->recvbounce[i]); + if(p->recvbounce[i]) + kfree(p->recvbounce[i]); #endif - } - if(p->self) - kfree(p->self); + } + if(p->self) + kfree(p->self); } @@ -649,68 +649,68 @@ */ static void ni65_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(p->features & INIT_RING_BEFORE_START) { - int i; -#ifdef XMT_VIA_SKB - struct sk_buff *skb_save[TMDNUM]; -#endif - unsigned long buffer[TMDNUM]; - short blen[TMDNUM]; + if(debuglevel > 1) + printk("ni65_stop_start\n"); - 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;itmdhead + i; -#ifdef XMT_VIA_SKB - 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;irmdhead + i; - rmdp->u.s.status = RCV_OWN; - } - p->tmdnum = p->xmit_queued = 0; - writedatareg(CSR0_STRT | csr0); - - for(i=0;itmdlast) & (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; + if(p->features & INIT_RING_BEFORE_START) { + int i; +#ifdef XMT_VIA_SKB + 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;itmdhead + i; +#ifdef XMT_VIA_SKB + 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;irmdhead + i; + rmdp->u.s.status = RCV_OWN; + } + p->tmdnum = p->xmit_queued = 0; + writedatareg(CSR0_STRT | csr0); + + for(i=0;itmdlast) & (TMDNUM-1); + p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */ + p->tmdhead[i].blen = blen[num]; + if(p->tmdhead[i].u.s.status & XMIT_OWN) { + p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); + p->xmit_queued = 1; writedatareg(CSR0_TDMD | CSR0_INEA | csr0); - } + } #ifdef XMT_VIA_SKB - p->tmd_skb[i] = skb_save[num]; + p->tmd_skb[i] = skb_save[num]; #endif - } - p->rmdnum = p->tmdlast = 0; - if(!p->lock) - dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1; - dev->trans_start = jiffies; - } - else - writedatareg(CSR0_STRT | csr0); + } + p->rmdnum = p->tmdlast = 0; + if(!p->lock) + dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1; + dev->trans_start = jiffies; + } + else + writedatareg(CSR0_STRT | csr0); } /* @@ -718,74 +718,74 @@ */ static int ni65_lance_reinit(struct device *dev) { - int i; - struct priv *p = (struct priv *) dev->priv; + int i; + struct priv *p = (struct priv *) dev->priv; - p->lock = 0; - p->xmit_queued = 0; + 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;itmdhead + i; -#ifdef XMT_VIA_SKB - 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;irmdhead + i; + 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;itmdhead + i; +#ifdef XMT_VIA_SKB + 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;irmdhead + i; #ifdef RCV_VIA_SKB - rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data); + rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data); #else - rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]); + rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]); #endif - rmdp->blen = -(R_BUF_SIZE-8); - rmdp->mlen = 0; - rmdp->u.s.status = RCV_OWN; - } - - if(dev->flags & IFF_PROMISC) - ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); - else if(dev->mc_count || dev->flags & IFF_ALLMULTI) - ni65_init_lance(p,dev->dev_addr,0xff,0x0); - else - ni65_init_lance(p,dev->dev_addr,0x00,0x00); - - /* - * ni65_set_lance_mem() sets L_ADDRREG to CSR0 - * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED - */ - - if(inw(PORT+L_DATAREG) & CSR0_IDON) { - ni65_set_performance(p); - /* init OK: start lance , enable interrupts */ - writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); - return 1; /* ->OK */ - } - printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); - disable_dma(dev->dma); - return 0; /* ->Error */ + rmdp->blen = -(R_BUF_SIZE-8); + rmdp->mlen = 0; + rmdp->u.s.status = RCV_OWN; + } + + if(dev->flags & IFF_PROMISC) + ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); + else if(dev->mc_count || dev->flags & IFF_ALLMULTI) + ni65_init_lance(p,dev->dev_addr,0xff,0x0); + else + ni65_init_lance(p,dev->dev_addr,0x00,0x00); + + /* + * ni65_set_lance_mem() sets L_ADDRREG to CSR0 + * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED + */ + + if(inw(PORT+L_DATAREG) & CSR0_IDON) { + ni65_set_performance(p); + /* init OK: start lance , enable interrupts */ + writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); + return 1; /* ->OK */ + } + printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); + disable_dma(dev->dma); + return 0; /* ->Error */ } /* @@ -793,117 +793,117 @@ */ static 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; - - 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; + 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(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_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;irmdhead[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_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;irmdhead[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;jpriv; - 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;krmdnum + 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;krmdhead[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;krmdnum + 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;krmdhead[k].u.s.status)); /* & RCV_OWN) ); */ + buf1 += 3; + } + *buf1 = 0; + printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf); + } + + p->rmdnum = num1; + ni65_recv_intr(dev,csr0); + if((p->rmdhead[num2].u.s.status & RCV_OWN)) + break; /* ok, we are 'in sync' again */ + } + else + break; } } #endif - if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) { - printk("%s: RX or TX was offline -> restart\n",dev->name); - ni65_stop_start(dev,p); - } - else - writedatareg(CSR0_INEA); + if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) { + printk("%s: RX or TX was offline -> restart\n",dev->name); + ni65_stop_start(dev,p); + } + else + writedatareg(CSR0_INEA); - dev->interrupt = 0; + dev->interrupt = 0; - return; + return; } /* @@ -912,62 +912,62 @@ */ static void ni65_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++; - -#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; - } -#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->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; + } +#endif + + p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); + if(p->tmdlast == p->tmdnum) + p->xmit_queued = 0; + } + dev->tbusy = 0; + mark_bh(NET_BH); } /* @@ -975,90 +975,90 @@ */ static void ni65_recv_intr(struct device *dev,int csr0) { - struct rmd *rmdp; - int rmdstat,len; - int cnt=0; - struct priv *p = (struct priv *) dev->priv; - - rmdp = p->rmdhead + p->rmdnum; - while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) - { - cnt++; - if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */ - { - if(!(rmdstat & RCV_ERR)) { - if(rmdstat & RCV_START) - { - p->stats.rx_length_errors++; - printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff); - } - } - else { - if(debuglevel > 2) - printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n", - dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) ); - if(rmdstat & RCV_FRAM) - p->stats.rx_frame_errors++; - if(rmdstat & RCV_OFLO) - p->stats.rx_over_errors++; - if(rmdstat & RCV_CRC) - p->stats.rx_crc_errors++; - if(rmdstat & RCV_BUF_ERR) - p->stats.rx_fifo_errors++; - } - if(!(csr0 & CSR0_MISS)) /* don't count errors twice */ - p->stats.rx_errors++; - } - else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60) - { + struct rmd *rmdp; + int rmdstat,len; + int cnt=0; + struct priv *p = (struct priv *) dev->priv; + + rmdp = p->rmdhead + p->rmdnum; + while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) + { + cnt++; + if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */ + { + if(!(rmdstat & RCV_ERR)) { + if(rmdstat & RCV_START) + { + p->stats.rx_length_errors++; + printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff); + } + } + else { + if(debuglevel > 2) + printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n", + dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) ); + if(rmdstat & RCV_FRAM) + p->stats.rx_frame_errors++; + if(rmdstat & RCV_OFLO) + p->stats.rx_over_errors++; + if(rmdstat & RCV_CRC) + p->stats.rx_crc_errors++; + if(rmdstat & RCV_BUF_ERR) + p->stats.rx_fifo_errors++; + } + if(!(csr0 & CSR0_MISS)) /* don't count errors twice */ + p->stats.rx_errors++; + } + else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60) + { #ifdef RCV_VIA_SKB - struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC); - if (skb) - skb_reserve(skb,16); + struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC); + if (skb) + skb_reserve(skb,16); #else - struct sk_buff *skb = dev_alloc_skb(len+2); + struct sk_buff *skb = dev_alloc_skb(len+2); #endif - if(skb) - { - skb_reserve(skb,2); + if(skb) + { + skb_reserve(skb,2); skb->dev = dev; #ifdef RCV_VIA_SKB - if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) { - skb_put(skb,len); - eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0); - } - else { - struct sk_buff *skb1 = p->recv_skb[p->rmdnum]; - skb_put(skb,R_BUF_SIZE); - p->recv_skb[p->rmdnum] = skb; - rmdp->u.buffer = (u32) virt_to_bus(skb->data); - skb = skb1; - skb_trim(skb,len); - } + if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) { + skb_put(skb,len); + eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0); + } + else { + struct sk_buff *skb1 = p->recv_skb[p->rmdnum]; + skb_put(skb,R_BUF_SIZE); + p->recv_skb[p->rmdnum] = skb; + rmdp->u.buffer = (u32) virt_to_bus(skb->data); + skb = skb1; + skb_trim(skb,len); + } #else - skb_put(skb,len); - eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0); + skb_put(skb,len); + eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0); #endif - p->stats.rx_packets++; - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - else - { - printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name); - p->stats.rx_dropped++; - } - } - else { - printk(KERN_INFO "%s: received runt packet\n",dev->name); - p->stats.rx_errors++; - } - rmdp->blen = -(R_BUF_SIZE-8); - rmdp->mlen = 0; - rmdp->u.s.status = RCV_OWN; /* change owner */ - p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1); - rmdp = p->rmdhead + p->rmdnum; - } + p->stats.rx_packets++; + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + else + { + printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name); + p->stats.rx_dropped++; + } + } + else { + printk(KERN_INFO "%s: received runt packet\n",dev->name); + p->stats.rx_errors++; + } + rmdp->blen = -(R_BUF_SIZE-8); + rmdp->mlen = 0; + rmdp->u.s.status = RCV_OWN; /* change owner */ + p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1); + rmdp = p->rmdhead + p->rmdnum; + } } /* @@ -1066,106 +1066,99 @@ */ static int ni65_send_packet(struct sk_buff *skb, struct device *dev) { - 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 < 50) - return 1; + 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;itmdhead[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; + printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); + { + int i; + for(i=0;itmdhead[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(); + } + 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; - } + 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;irmdhead + ((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;irmdhead + ((p->rmdnum + i) & (RMDNUM-1)); + printk("%02x ",rmdp->u.s.status); + } + printk("\n"); #endif - return &((struct priv *) dev->priv)->stats; + return &((struct priv *) dev->priv)->stats; } static void set_multicast_list(struct device *dev) @@ -1177,10 +1170,10 @@ #ifdef MODULE static struct device dev_ni65 = { - " ", /* "ni6510": device name inserted by net_init.c */ - 0, 0, 0, 0, - 0x360, 9, /* I/O address, IRQ */ - 0, 0, 0, NULL, ni65_probe }; + " ", /* "ni6510": device name inserted by net_init.c */ + 0, 0, 0, 0, + 0x360, 9, /* I/O address, IRQ */ + 0, 0, 0, NULL, ni65_probe }; /* set: io,irq,dma or set it when calling insmod */ static int irq=0; @@ -1193,35 +1186,28 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/pi2.c linux/drivers/net/pi2.c --- v2.1.24/linux/drivers/net/pi2.c Thu Jan 23 21:06:47 1997 +++ linux/drivers/net/pi2.c Sun Feb 2 15:18:40 1997 @@ -146,7 +146,7 @@ static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs); static int pi_close(struct device *dev); static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd); -static struct enet_statistics *pi_get_stats(struct device *dev); +static struct net_device_stats *pi_get_stats(struct device *dev); static void rts(struct pi_local *lp, int x); static void b_rxint(struct device *dev, struct pi_local *lp); static void b_txint(struct pi_local *lp); @@ -164,69 +164,71 @@ static 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; + 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; + /* assume caller disables interrupts! */ + outb_p(0, cbase + DMAEN); /* Disable DMA while we touch the scc */ + outb_p(sccreg, ctl); /* Select register */ + retval = inb_p(ctl); + outb_p(1, cbase + DMAEN); /* Enable DMA */ + return retval; } static void switchbuffers(struct pi_local *lp) { - if (lp->rcvbuf == lp->rxdmabuf1) - lp->rcvbuf = lp->rxdmabuf2; - else - lp->rcvbuf = lp->rxdmabuf1; + if (lp->rcvbuf == lp->rxdmabuf1) + lp->rcvbuf = lp->rxdmabuf2; + else + lp->rcvbuf = lp->rxdmabuf1; } static void hardware_send_packet(struct pi_local *lp, struct sk_buff *skb) { - char kickflag; - unsigned long flags; + char kickflag; + unsigned long flags; - lp->stats.tx_packets++; + lp->stats.tx_packets++; - save_flags(flags); - cli(); - kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL); - restore_flags(flags); + save_flags(flags); + cli(); + kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL); + restore_flags(flags); - skb_queue_tail(&lp->sndq, skb); - if (kickflag) { - /* simulate interrupt to xmit */ - switch (lp->base & 2) { - case 2: - a_txint(lp); /* process interrupt */ - break; - case 0: - save_flags(flags); - cli(); - if (lp->tstate == IDLE) - b_txint(lp); - restore_flags(flags); - break; + skb_queue_tail(&lp->sndq, skb); + if (kickflag) + { + /* simulate interrupt to xmit */ + switch (lp->base & 2) + { + case 2: + a_txint(lp); /* process interrupt */ + break; + case 0: + save_flags(flags); + cli(); + if (lp->tstate == IDLE) + b_txint(lp); + restore_flags(flags); + break; + } } - } } static void setup_rx_dma(struct pi_local *lp) @@ -1662,12 +1664,11 @@ /* 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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/pi2.h linux/drivers/net/pi2.h --- v2.1.24/linux/drivers/net/pi2.h Tue Jun 6 11:22:10 1995 +++ linux/drivers/net/pi2.h Sun Feb 2 15:18:40 1997 @@ -1,9 +1,6 @@ #define DMA_BUFF_SIZE 2200 -/* Network statistics, with the same names as 'struct enet_statistics'. */ -#define netstats enet_statistics - #define ON 1 #define OFF 0 diff -u --recursive --new-file v2.1.24/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.24/linux/drivers/net/plip.c Tue Dec 31 21:41:05 1996 +++ linux/drivers/net/plip.c Sun Feb 2 15:18:41 1997 @@ -147,7 +147,7 @@ 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); @@ -198,7 +198,7 @@ }; struct net_local { - struct enet_statistics enet_stats; + struct net_device_stats enet_stats; struct tq_struct immediate; struct tq_struct deferred; struct plip_local snd_data; @@ -213,8 +213,8 @@ /* Entry point of PLIP driver. Probe the hardware, and register/initialize the driver. */ -int -plip_init(struct device *dev) + +int plip_init(struct device *dev) { struct net_local *nl; int iosize = (PAR_DATA(dev) == 0x3bc) ? 3 : 8; @@ -306,8 +306,8 @@ /* Bottom half handler for the delayed request. This routine is kicked by do_timer(). Request `plip_bh' to be invoked. */ -static void -plip_kick_bh(struct device *dev) + +static void plip_kick_bh(struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; @@ -350,8 +350,7 @@ }; /* Bottom half handler of PLIP. */ -static void -plip_bh(struct device *dev) +static void plip_bh(struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; struct plip_local *snd = &nl->snd_data; @@ -368,8 +367,7 @@ } } -static int -plip_bh_timeout_error(struct device *dev, struct net_local *nl, +static int plip_bh_timeout_error(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv, int error) { @@ -431,8 +429,7 @@ return TIMEOUT; } -static int -plip_none(struct device *dev, struct net_local *nl, +static int plip_none(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { return OK; @@ -440,8 +437,7 @@ /* PLIP_RECEIVE --- receive a byte(two nibbles) Returns OK on success, TIMEOUT on timeout */ -inline static int -plip_receive(unsigned short nibble_timeout, unsigned short status_addr, +extern inline int plip_receive(unsigned short nibble_timeout, unsigned short status_addr, enum plip_nibble_state *ns_p, unsigned char *data_p) { unsigned char c0, c1; @@ -490,8 +486,7 @@ } /* PLIP_RECEIVE_PACKET --- receive a packet */ -static int -plip_receive_packet(struct device *dev, struct net_local *nl, +static int plip_receive_packet(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { unsigned short status_addr = PAR_STATUS(dev); @@ -607,8 +602,7 @@ /* PLIP_SEND --- send a byte (two nibbles) Returns OK on success, TIMEOUT when timeout */ -inline static int -plip_send(unsigned short nibble_timeout, unsigned short data_addr, +extern inline int plip_send(unsigned short nibble_timeout, unsigned short data_addr, enum plip_nibble_state *ns_p, unsigned char data) { unsigned char c0; @@ -654,8 +648,7 @@ } /* PLIP_SEND_PACKET --- send a packet */ -static int -plip_send_packet(struct device *dev, struct net_local *nl, +static int plip_send_packet(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { unsigned short data_addr = PAR_DATA(dev); @@ -759,8 +752,7 @@ return OK; } -static int -plip_connection_close(struct device *dev, struct net_local *nl, +static int plip_connection_close(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { cli(); @@ -774,8 +766,7 @@ } /* PLIP_ERROR --- wait till other end settled */ -static int -plip_error(struct device *dev, struct net_local *nl, +static int plip_error(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { unsigned char status; @@ -799,8 +790,7 @@ } /* Handle the parallel port interrupts. */ -static void -plip_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void plip_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct device *dev = (struct device *) irq2dev_map[irq]; struct net_local *nl = (struct net_local *)dev->priv; @@ -853,8 +843,7 @@ } /* We don't need to send arp, for plip is point-to-point. */ -static int -plip_rebuild_header(struct sk_buff *skb) +static int plip_rebuild_header(struct sk_buff *skb) { struct device *dev = skb->dev; struct net_local *nl = (struct net_local *)dev->priv; @@ -888,8 +877,7 @@ return 0; } -static int -plip_tx_packet(struct sk_buff *skb, struct device *dev) +static int plip_tx_packet(struct sk_buff *skb, struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; struct plip_local *snd = &nl->snd_data; @@ -941,8 +929,7 @@ This routine gets exclusive access to the parallel port by allocating its IRQ line. */ -static int -plip_open(struct device *dev) +static int plip_open(struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; int i; @@ -985,8 +972,7 @@ } /* The inverse routine to plip_open (). */ -static int -plip_close(struct device *dev) +static int plip_close(struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; struct plip_local *snd = &nl->snd_data; @@ -1019,17 +1005,15 @@ return 0; } -static struct enet_statistics * -plip_get_stats(struct device *dev) +static struct net_device_stats *plip_get_stats(struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; - struct enet_statistics *r = &nl->enet_stats; + struct net_device_stats *r = &nl->enet_stats; return r; } -static int -plip_config(struct device *dev, struct ifmap *map) +static int plip_config(struct device *dev, struct ifmap *map) { if (dev->flags & IFF_UP) return -EBUSY; @@ -1043,8 +1027,7 @@ return 0; } -static int -plip_ioctl(struct device *dev, struct ifreq *rq, int cmd) +static int plip_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct net_local *nl = (struct net_local *) dev->priv; struct plipconf *pc = (struct plipconf *) &rq->ifr_data; @@ -1092,8 +1075,7 @@ } }; -int -init_module(void) +int init_module(void) { int no_parameters=1; int devices=0; @@ -1134,8 +1116,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { int i; diff -u --recursive --new-file v2.1.24/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.24/linux/drivers/net/ppp.c Sun Feb 2 15:46:19 1997 +++ linux/drivers/net/ppp.c Sun Feb 2 15:18:41 1997 @@ -183,7 +183,7 @@ static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd); static int ppp_dev_close (struct device *); static int ppp_dev_xmit (sk_buff *, struct device *); -static struct enet_statistics *ppp_dev_stats (struct device *); +static struct net_device_stats *ppp_dev_stats (struct device *); /* * TTY callbacks @@ -3080,11 +3080,11 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/pt.c linux/drivers/net/pt.c --- v2.1.24/linux/drivers/net/pt.c Thu Jan 2 15:55:19 1997 +++ linux/drivers/net/pt.c Sun Feb 2 15:18:41 1997 @@ -124,7 +124,7 @@ static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int pt_close(struct device *dev); static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd); -static struct enet_statistics *pt_get_stats(struct device *dev); +static struct net_device_stats *pt_get_stats(struct device *dev); static void pt_rts(struct pt_local *lp, int x); static void pt_rxisr(struct device *dev); static void pt_txisr(struct pt_local *lp); @@ -175,10 +175,10 @@ static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb) { - char kickflag; - unsigned long flags; - char *ptr; - struct device *dev; + char kickflag; + unsigned long flags; + char *ptr; + struct device *dev; /* First, let's see if this packet is actually a KISS packet */ ptr = skb->data; @@ -215,73 +215,78 @@ 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); - /* Enable RX dma */ - wrtscc(lp->cardbase, cmd, R1, - WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); + /* + * If a packet is already coming in, this line is supposed to + * avoid receiving a partial packet. + */ - restore_flags(flags); + wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC); + + /* Enable RX dma */ + wrtscc(lp->cardbase, cmd, R1, + WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); + + restore_flags(flags); } static void setup_tx_dma(struct pt_local *lp, int length) @@ -324,79 +329,76 @@ */ static void 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); + /* 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); - } 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/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 */ + } - /* Null out SDLC start address */ - wrtscc(lp->cardbase, cmd, R6, 0); + /* Null out SDLC start address */ + wrtscc(lp->cardbase, cmd, R6, 0); - /* SDLC flag */ - wrtscc(lp->cardbase, cmd, R7, FLAG); + /* SDLC flag */ + wrtscc(lp->cardbase, cmd, R7, FLAG); - /* Setup Tx but don't enable it */ - wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); + /* Setup Tx but don't enable it */ + wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); - /* Setup Rx */ - wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); + /* Setup Rx */ + wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); - /* Setup the BRG, turn it off first */ - wrtscc(lp->cardbase, cmd, R14, BRSRC); + /* Setup the BRG, turn it off first */ + wrtscc(lp->cardbase, cmd, R14, BRSRC); - /* set the 32x time constant for the BRG in Rx mode */ + /* set the 32x time constant for the BRG in Rx mode */ if (lp->speed) { br = lp->speed; tc = ((lp->xtal / 32) / (br * 2)) - 2; - wrtscc(lp->cardbase, cmd, R12, tc & 0xff); /* lower byte */ + wrtscc(lp->cardbase, cmd, R12, tc & 0xff); /* lower byte */ wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); /* upper byte */ } @@ -409,36 +411,37 @@ /* DPLL frm BRG, BRG src PCLK */ wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR); wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); /* Enable the BRG */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); /* Enable the BRG */ /* Turn off external clock port */ - if (lp->base & CHANA) - outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); - else - outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); - } else { + if (lp->base & CHANA) + outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); + else + outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); + } + else + { /* DPLL frm rtxc,BRG src PCLK */ -/* wrtscc(lp->cardbase, cmd, R14, BRSRC | SSRTxC);*/ - /* Turn on external clock port */ - if (lp->base & CHANA) - outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); - else - outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); - } + /* Turn on external clock port */ + if (lp->base & CHANA) + outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); + else + outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); + } - if (!lp->dmachan) + if (!lp->dmachan) wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); - wrtscc(lp->cardbase, cmd, R15, BRKIE); /* ABORT int */ + wrtscc(lp->cardbase, cmd, R15, BRKIE); /* ABORT int */ /* Turn on the DTR to tell modem we're alive */ if (lp->base & CHANA) - outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) ); + outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) ); else - outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) ); + outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) ); - /* Now, turn on the receiver and hunt for a flag */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 ); + /* Now, turn on the receiver and hunt for a flag */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 ); restore_flags(flags); @@ -1075,14 +1078,15 @@ return ret; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct netstats * - pt_get_stats(struct device *dev) +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct net_device_stats *pt_get_stats(struct device *dev) { - struct pt_local *lp = (struct pt_local *) dev->priv; - - return &lp->stats; + struct pt_local *lp = (struct pt_local *) dev->priv; + return &lp->stats; } @@ -1102,13 +1106,16 @@ if (!lp->dmachan) wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB); - if (lp->base & CHANA) { - outb_p(time & 0xff, lp->cardbase + TMR1); - outb_p((time >> 8)&0xff, lp->cardbase + TMR1); - } else { - outb_p(time & 0xff, lp->cardbase + TMR2); - outb_p((time >> 8)&0xff, lp->cardbase + TMR2); - } + if (lp->base & CHANA) + { + outb_p(time & 0xff, lp->cardbase + TMR1); + outb_p((time >> 8)&0xff, lp->cardbase + TMR1); + } + else + { + outb_p(time & 0xff, lp->cardbase + TMR2); + outb_p((time >> 8)&0xff, lp->cardbase + TMR2); + } } /* tdelay */ @@ -1379,6 +1386,7 @@ memcpy(cfix, lp->rcvbuf->data, pkt_len - 1); skb->protocol = ntohs(ETH_P_AX25); skb->mac.raw=skb->data; + lp->stats.rx_bytes+=skb->len; IS_SKB(skb); netif_rx(skb); lp->stats.rx_packets++; @@ -1767,21 +1775,21 @@ 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; - - kfree(pt0a.priv); - pt0a.priv = NULL; - unregister_netdev(&pt0a); - - kfree(pt0b.priv); - pt0b.priv = NULL; - unregister_netdev(&pt0b); + 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(pt0b.priv); + pt0b.priv = NULL; + unregister_netdev(&pt0b); } #endif diff -u --recursive --new-file v2.1.24/linux/drivers/net/pt.h linux/drivers/net/pt.h --- v2.1.24/linux/drivers/net/pt.h Tue Dec 26 06:03:00 1995 +++ linux/drivers/net/pt.h Sun Feb 2 15:18:41 1997 @@ -6,9 +6,6 @@ */ #define DMA_BUFF_SIZE 2200 -/* Network statistics, with the same names as 'struct enet_statistics'. */ -#define netstats enet_statistics - #define ON 1 #define OFF 0 @@ -98,16 +95,17 @@ #define SIOCGPIIRQ 0x5006 /* get only IRQ */ #define SIOCSPIIRQ 0x5007 -struct pt_req { - int cmd; - int speed; - int clockmode; - int txdelay; - unsigned char persist; - int slotime; - int squeldelay; - int dmachan; - int irq; +struct pt_req +{ + int cmd; + int speed; + int clockmode; + int txdelay; + unsigned char persist; + int slotime; + int squeldelay; + int dmachan; + int irq; }; /* SCC Interrupt vectors, if we have set 'status low' */ @@ -124,53 +122,53 @@ #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 diff -u --recursive --new-file v2.1.24/linux/drivers/net/scc.c linux/drivers/net/scc.c --- v2.1.24/linux/drivers/net/scc.c Thu Jan 23 21:06:48 1997 +++ linux/drivers/net/scc.c Sun Feb 2 15:18:41 1997 @@ -204,7 +204,7 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd); static int scc_net_set_mac_address(struct device *dev, void *addr); static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); -static struct enet_statistics * scc_net_get_stats(struct device *dev); +static struct net_device_stats * scc_net_get_stats(struct device *dev); static unsigned char *SCC_DriverName = "scc"; @@ -1663,12 +1663,6 @@ dev->trans_start = jiffies; } - if (skb == NULL) - { - dev_tint(dev); - return 0; - } - if (scc == NULL || scc->magic != SCC_MAGIC) { dev_kfree_skb(skb, FREE_WRITE); @@ -1971,12 +1965,12 @@ static int scc_net_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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.1.24/linux/drivers/net/sdla.c Thu Jan 2 15:55:19 1997 +++ linux/drivers/net/sdla.c Sun Feb 2 15:18:41 1997 @@ -82,147 +82,145 @@ 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; + 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; - } + 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; + 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; - } + flp = dev->priv; + switch(flp->type) + { + case SDLA_S502A: + outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL); + outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); + flp->state = SDLA_S502A_START; + break; + case SDLA_S502E: + outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL); + outb(0x00, dev->base_addr + SDLA_REG_CONTROL); + flp->state = 0; + break; + case SDLA_S507: + flp->state |= SDLA_CPUEN; + outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); + break; + case SDLA_S508: + flp->state |= SDLA_CPUEN; + outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); + break; + } } /**************************************************** @@ -237,26 +235,26 @@ int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char resp2) { - unsigned long start, done, now; - char resp, *temp; + unsigned long start, done, now; + char resp, *temp; - start = now = jiffies; - done = jiffies + jiffs; + 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); + temp = (void *)dev->mem_start; + temp += z80_addr & SDLA_ADDR_MASK; + + resp = ~resp1; + while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2))) + { + if (jiffies != now) + { + SDLA_WINDOW(dev, z80_addr); + now = jiffies; + resp = *temp; + } + } + return(jiffies < done ? jiffies - start : -1); } /* constants for Z80 CPU speed */ @@ -267,46 +265,45 @@ static int sdla_cpuspeed(struct device *dev, struct ifreq *ifr) { - int jiffs; - char data; + 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; + sdla_start(dev); + if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0) + return(-EIO); + + data = LOADER_READY; + sdla_write(dev, 0, &data, 1); + + if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0) + return(-EIO); + + sdla_stop(dev); + sdla_read(dev, 0, &data, 1); + + if (data == Z80_SCC_BAD) + { + printk("%s: SCC bad\n", dev->name); + return(-EIO); + } + + if (data != Z80_SCC_OK) + return(-EINVAL); + + if (jiffs < 165) + ifr->ifr_mtu = SDLA_CPU_16M; + else if (jiffs < 220) + ifr->ifr_mtu = SDLA_CPU_10M; + else if (jiffs < 258) + ifr->ifr_mtu = SDLA_CPU_8M; + else if (jiffs < 357) + ifr->ifr_mtu = SDLA_CPU_7M; + else if (jiffs < 467) + ifr->ifr_mtu = SDLA_CPU_5M; + else + ifr->ifr_mtu = SDLA_CPU_3M; - return(0); + return(0); } /************************************************ @@ -316,175 +313,174 @@ * ************************************************/ -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; + 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); + if (ret != SDLA_RET_OK) + sdla_errors(dev, cmd, dlci, ret, len, &status); - return(ret); + return(ret); } /*********************************************** @@ -497,141 +493,141 @@ 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;imaster[i] == master) - break; + for(i=0;imaster[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;imaster[i] == master) - break; + for(i=0;imaster[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;imaster[i]) - break; - if (abs(flp->dlci[i]) == *(short *)(master->dev_addr)) - return(-EADDRINUSE); - } - - if (i == CONFIG_DLCI_MAX) - return(-EMLINK); /* #### Alan: Comments on this ?? */ - - MOD_INC_USE_COUNT; - - 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); + for(i=0;imaster[i]) + break; + if (abs(flp->dlci[i]) == *(short *)(master->dev_addr)) + return(-EADDRINUSE); + } + + if (i == CONFIG_DLCI_MAX) + return(-EMLINK); /* #### Alan: Comments on this ?? */ + + MOD_INC_USE_COUNT; + + 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); - 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;imaster[i] == master) - break; + for(i=0;imaster[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; - - flp = slave->priv; - - for(i=0;imaster[i] == master) - break; - - if (i == CONFIG_DLCI_MAX) - return(-ENODEV); - - 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); + struct frad_local *flp; + struct dlci_local *dlp; + int i; + short len, ret; + + flp = slave->priv; + + for(i=0;imaster[i] == master) + break; + + if (i == CONFIG_DLCI_MAX) + return(-ENODEV); + + 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); - return(ret == SDLA_RET_OK ? 0 : -EIO); + return(ret == SDLA_RET_OK ? 0 : -EIO); } /************************** @@ -643,656 +639,643 @@ /* 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;idlci[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); - } + 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;idlci[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); + 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;idlci[i]) - dlcis[len++] = abs(flp->dlci[i]); - len *= 2; - - if (flp->config.station == FRAD_STATION_NODE) - { - for(i=0;idlci[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; - } + struct frad_local *flp; + struct intr_info intr; + int len, i; + short dlcis[CONFIG_DLCI_MAX]; + + flp = dev->priv; + + len = 0; + for(i=0;idlci[i]) + dlcis[len++] = abs(flp->dlci[i]); + len *= 2; + + if (flp->config.station == FRAD_STATION_NODE) + { + for(i=0;idlci[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); + sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); - dev->tbusy = 1; - dev->start = 0; + dev->tbusy = 1; + dev->start = 0; - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; - return(0); + 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;idlci[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;idlci[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;idlci[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; + 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;idlci[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;idlci[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;idlci[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; + MOD_INC_USE_COUNT; - return(0); + 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;imaster[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)); - } + 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;imaster[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); + 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; - - flp = dev->priv; - - len = 0; - for(i=0;idlci[i]) - data.dlci[len++] = flp->dlci[i]; - len *= 2; - - 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); + struct frad_local *flp; + struct conf_data data; + int i, len; + + flp = dev->priv; + + len = 0; + for(i=0;idlci[i]) + data.dlci[len++] = flp->dlci[i]; + len *= 2; + + 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); - 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(-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)); + + case SDLA_IDENTIFY: + ifr->ifr_flags = flp->type; + break; - if (!flp->initialized) - return(-EPERM); - - 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_CPUSPEED: - return(sdla_cpuspeed(dev, ifr)); + case SDLA_CPUSPEED: + return(sdla_cpuspeed(dev, ifr)); /* ========================================================== NOTE: This is rather a useless action right now, as the @@ -1300,391 +1283,396 @@ 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;ibase_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;ibase_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); + for(i=1;ibase_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;ibase_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); + 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; + 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; + /* 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); + 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; + 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); + return(0); } void sdla_setup(void) { - printk("%s.\n", version); - register_frad(devname); + printk("%s.\n", version); + register_frad(devname); } #ifdef MODULE @@ -1692,21 +1680,20 @@ int init_module(void) { - int result; - - sdla_setup(); - if ((result = register_netdev(&sdla0)) != 0) - return result; + int result; - return 0; + sdla_setup(); + if ((result = register_netdev(&sdla0)) != 0) + return result; + return 0; } void cleanup_module(void) { - unregister_netdev(&sdla0); - if (sdla0.priv) - kfree(sdla0.priv); - if (sdla0.irq) - free_irq(sdla0.irq, NULL); + unregister_netdev(&sdla0); + if (sdla0.priv) + kfree(sdla0.priv); + if (sdla0.irq) + free_irq(sdla0.irq, NULL); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.24/linux/drivers/net/sdla_fr.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sdla_fr.c Sun Feb 2 16:42:57 1997 @@ -0,0 +1,1428 @@ +/***************************************************************************** +* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. +* +* Author: Gene Kozin +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* ARPHRD_* defines */ +#include /* htons(), etc. */ +#include /* for inb(), outb(), etc. */ + +#define _GNUC_ +#include /* frame relay firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ + +/* Q.922 frame types */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* ??? */ + +/****** Data Structures *****************************************************/ + +/* This is an extention of the 'struct device' we create for each network + * interface to keep the rest of channel-specific data. + */ +typedef struct fr_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + char state; /* channel state */ + unsigned long state_tick; /* time of the last state change */ + sdla_t* card; /* -> owner */ + struct enet_statistics ifstats; /* interface statistics */ +} fr_channel_t; + +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; +} dlci_status_t; + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); + +/* Network device interface */ +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, + struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); + +/* Interrupt handlers */ +static void fr502_isr (sdla_t* card); +static void fr508_isr (sdla_t* card); +static void fr502_rx_intr (sdla_t* card); +static void fr508_rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); +static void spur_intr (sdla_t* card); + +/* Background polling routines */ +static void wpf_poll (sdla_t* card); + +/* Frame relay firmware interface functions */ +static int fr_read_version (sdla_t* card, char* str); +static int fr_configure (sdla_t* card, fr_conf_t *conf); +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu); +static int fr_comm_enable (sdla_t* card); +static int fr_comm_disable (sdla_t* card); +static int fr_add_dlci (sdla_t* card, int dlci, int num); +static int fr_activate_dlci (sdla_t* card, int dlci, int num); +static int fr_issue_isf (sdla_t* card, int isf); +static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf); +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf); + +/* Firmware asynchronous event handlers */ +static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox); +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox); +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox); + +/* Miscellaneous functions */ +static int update_chan_state (struct device* dev); +static void set_chan_state (struct device* dev, int state); +static struct device* find_channel (sdla_t* card, unsigned dlci); +static int is_tx_ready (sdla_t* card); +static unsigned int dec_to_uint (unsigned char* str, int len); +static unsigned int hex_to_uint (unsigned char* str, int len); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Frame relay protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpf_init (sdla_t* card, wandev_conf_t* conf) +{ + union + { + char str[80]; + fr_conf_t cfg; + } u; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_FR) + { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id) + ; + return -EINVAL; + } + + /* Initialize protocol-specific fields of adapter data space */ + switch (card->hw.fwid) + { + case SFID_FR502: + card->mbox = (void*)(card->hw.dpmbase + FR502_MBOX_OFFS); + card->rxmb = (void*)(card->hw.dpmbase + FR502_RXMB_OFFS); + card->flags = (void*)(card->hw.dpmbase + FR502_FLAG_OFFS); + card->isr = &fr502_isr; + break; + + case SFID_FR508: + card->mbox = (void*)(card->hw.dpmbase + FR508_MBOX_OFFS); + card->flags = (void*)(card->hw.dpmbase + FR508_FLAG_OFFS); + card->isr = &fr508_isr; + break; + + default: + return -EINVAL; + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) + return -EIO + ; + printk(KERN_INFO "%s: running frame relay firmware v%s\n", + card->devname, u.str) + ; + + /* Adjust configuration */ + conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN); + conf->bps = min(conf->bps, 2048000); + + /* Configure adapter firmware */ + memset(&u.cfg, 0, sizeof(u.cfg)); + u.cfg.mtu = conf->mtu; + u.cfg.t391 = 10; + u.cfg.t392 = 15; + u.cfg.n391 = 6; + u.cfg.n392 = 3; + u.cfg.n393 = 4; + u.cfg.kbps = conf->bps / 1000; + u.cfg.cir_fwd = max(min(u.cfg.kbps, 512), 1); + u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd; + u.cfg.options = 0x0081; /* direct Rx, no CIR check */ + switch (conf->u.fr.signalling) + { + case WANOPT_FR_Q933: u.cfg.options |= 0x0200; break; + case WANOPT_FR_LMI: u.cfg.options |= 0x0400; break; + } + if (conf->station == WANOPT_CPE) + { + u.cfg.options |= 0x8000; /* auto config DLCI */ + } + else + { + u.cfg.station = 1; /* switch emulation mode */ + card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16; + card->u.f.dlci_num = max(min(conf->u.fr.dlci_num, 1), 100); + } + if (conf->clocking == WANOPT_INTERNAL) + u.cfg.port |= 0x0001 + ; + if (conf->interface == WANOPT_RS232) + u.cfg.port |= 0x0002 + ; + if (conf->u.fr.t391) + u.cfg.t391 = min(conf->u.fr.t391, 30) + ; + if (conf->u.fr.t392) + u.cfg.t392 = min(conf->u.fr.t392, 30) + ; + if (conf->u.fr.n391) + u.cfg.n391 = min(conf->u.fr.n391, 255) + ; + if (conf->u.fr.n392) + u.cfg.n392 = min(conf->u.fr.n392, 10) + ; + if (conf->u.fr.n393) + u.cfg.n393 = min(conf->u.fr.n393, 10) + ; + + if (fr_configure(card, &u.cfg)) + return -EIO + ; + + if (card->hw.fwid == SFID_FR508) + { + fr_buf_info_t* buf_info = + (void*)(card->hw.dpmbase + FR508_RXBC_OFFS) + ; + + card->rxmb = + (void*)(buf_info->rse_next - + FR_MB_VECTOR + card->hw.dpmbase) + ; + card->u.f.rxmb_base = + (void*)(buf_info->rse_base - + FR_MB_VECTOR + card->hw.dpmbase) + ; + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_buf_ctl_t) - + FR_MB_VECTOR + card->hw.dpmbase) + ; + card->u.f.rx_base = buf_info->buf_base; + card->u.f.rx_top = buf_info->buf_top; + } + card->wandev.mtu = conf->mtu; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->poll = &wpf_poll; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ +/* + sdla_t* card = wandev->private; +*/ + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + fr_channel_t* chan; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) + { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname) + ; + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); + if (chan == NULL) + return -ENOMEM + ; + memset(chan, 0, sizeof(fr_channel_t)); + strcpy(chan->name, conf->name); + chan->card = card; + + /* verify media address */ + if (is_digit(conf->addr[0])) + { + int dlci = dec_to_uint(conf->addr, 0); + + if (dlci && (dlci <= 4095)) + { + chan->dlci = dlci; + } + else + { + printk(KERN_ERR + "%s: invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name) + ; + err = -EINVAL; + } + } + else + { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name) + ; + err = -EINVAL; + } + if (err) + { + kfree(chan); + return err; + } + + /* prepare network device data space for registration */ + dev->name = chan->name; + dev->init = &if_init; + dev->priv = chan; + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct device* dev) +{ + if (dev->priv) + { + kfree(dev->priv); + dev->priv = NULL; + } + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + int i; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + dev->family = AF_INET; /* address family */ + dev->type = ARPHRD_DLCI; /* ARP h/w type */ + dev->mtu = FR_CHANNEL_MTU; + dev->hard_header_len = FR_HEADER_LEN;/* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = htons(chan->dlci); + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Initialize socket buffers */ + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]) + ; + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + +/*============================================================================ + * Open network interface. + * o if this is the first open, then enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct device* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int err = 0; + + if (dev->start) + return -EBUSY /* only one open is allowed */ + ; + if (set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + ; + if (!card->open_cnt) + { + if ((fr_comm_enable(card)) || + (fr_set_intr_mode(card, 0x03, card->wandev.mtu))) + { + err = -EIO; + goto done; + } + if (card->wandev.station == WANOPT_CPE) + { + /* CPE: issue full status enquiry */ + fr_issue_isf(card, FR_ISF_FSE); + } + else /* Switch: activate DLCI(s) */ + { + fr_add_dlci(card, + card->u.f.node_dlci, card->u.f.dlci_num) + ; + fr_activate_dlci(card, + card->u.f.node_dlci, card->u.f.dlci_num) + ; + } + wanpipe_set_state(card, WAN_CONNECTED); + } + dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + update_chan_state(dev); + +done: + card->wandev.critical = 0; + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (struct device* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + ; + dev->start = 0; + wanpipe_close(card); + if (!card->open_cnt) + { + wanpipe_set_state(card, WAN_DISCONNECTED); + fr_set_intr_mode(card, 0, 0); + fr_comm_disable(card); + } + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Build media header. + * o encapsulate packet according to encapsulation type. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If encapsulation fails, + * set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + int hdr_len = 0; + + skb->protocol = type; + hdr_len = wan_encapsulate(skb, dev); + if (hdr_len < 0) + { + hdr_len = 0; + skb->protocol = 0; + } + skb_push(skb, 1); + skb->data[0] = Q922_UI; + ++hdr_len; + return hdr_len; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, + struct sk_buff* skb) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", + card->devname, dev->name) + ; + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int retry = 0; + + if (skb == NULL) + { + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ +#ifdef _DEBUG_ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name) + ; +#endif + dev_tint(dev); + return 0; + } + + if (set_bit(0, (void*)&card->wandev.critical)) + { +#ifdef _DEBUG_ + printk(KERN_INFO "%s: if_send() hit critical section!\n", + card->devname) + ; +#endif + return 1; + } + + if (set_bit(0, (void*)&dev->tbusy)) + { +#ifdef _DEBUG_ + printk(KERN_INFO "%s: Tx collision on interface %s!\n", + card->devname, dev->name) + ; +#endif + ++chan->ifstats.collisions; + retry = 1; + } + else if ((card->wandev.state != WAN_CONNECTED) || + (chan->state != WAN_CONNECTED)) + ++chan->ifstats.tx_dropped + ; + else if (!is_tx_ready(card)) + retry = 1 + ; + else + { + int err = (card->hw.fwid == SFID_FR508) ? + fr508_send(card, chan->dlci, 0, skb->len, skb->data) : + fr502_send(card, chan->dlci, 0, skb->len, skb->data) + ; + if (err) ++chan->ifstats.tx_errors; + else ++chan->ifstats.tx_packets; + } + if (!retry) + { + dev_kfree_skb(skb, FREE_WRITE); + dev->tbusy = 0; + } + card->wandev.critical = 0; + return retry; +} + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + fr_channel_t* chan = dev->priv; + + return &chan->ifstats; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * S502 frame relay interrupt service routine. + */ +static void fr502_isr (sdla_t* card) +{ + fr502_flags_t* flags = card->flags; + + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + fr502_rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + flags->imask &= ~0x02; + tx_intr(card); + break; + + default: + spur_intr(card); + } + flags->iflag = 0; +} + +/*============================================================================ + * S508 frame relay interrupt service routine. + */ +static void fr508_isr (sdla_t* card) +{ + fr508_flags_t* flags = card->flags; + fr_buf_ctl_t* bctl; + + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + fr508_rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase) + ; + bctl->flag = 0x90; /* disable further Tx interrupts */ + tx_intr(card); + break; + + default: + spur_intr(card); + } + flags->iflag = 0; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void fr502_rx_intr (sdla_t* card) +{ + fr_mbox_t* mbox = card->rxmb; + struct sk_buff* skb; + struct device* dev; + fr_channel_t* chan; + unsigned dlci, len; + void* buf; + + sdla_mapmem(&card->hw, FR502_RX_VECTOR); + dlci = mbox->cmd.dlci; + len = mbox->cmd.length; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", + card->devname, dlci) + ; + goto rx_done; + } + chan = dev->priv; + if (!dev->start) + { + ++chan->ifstats.rx_dropped; + goto rx_done; + } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + if (skb == NULL) + { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname) + ; + ++chan->ifstats.rx_dropped; + goto rx_done; + } + + /* Copy data to the socket buffer */ + buf = skb_put(skb, len); + memcpy(buf, mbox->data, len); + sdla_mapmem(&card->hw, FR_MB_VECTOR); + + /* Decapsulate packet and pass it up the protocol stack */ + skb->dev = dev; + buf = skb_pull(skb, 1); /* remove hardware header */ + if (!wan_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb, FREE_READ); + ++chan->ifstats.rx_errors; + } + else + { + netif_rx(skb); + ++chan->ifstats.rx_packets; + } + +rx_done: + sdla_mapmem(&card->hw, FR_MB_VECTOR); +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void fr508_rx_intr (sdla_t* card) +{ + fr_buf_ctl_t* frbuf = card->rxmb; + struct sk_buff* skb; + struct device* dev; + fr_channel_t* chan; + unsigned dlci, len, offs; + void* buf; + + if (frbuf->flag != 0x01) + { + printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", + card->devname, (unsigned)frbuf) + ; + return; + } + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", + card->devname, dlci) + ; + goto rx_done; + } + chan = dev->priv; + if (!dev->start) + { + ++chan->ifstats.rx_dropped; + goto rx_done; + } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + if (skb == NULL) + { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname) + ; + ++chan->ifstats.rx_dropped; + goto rx_done; + } + + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top) + { + unsigned tmp = card->u.f.rx_top - offs; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); + + /* Decapsulate packet and pass it up the protocol stack */ + skb->dev = dev; + buf = skb_pull(skb, 1); /* remove hardware header */ + if (!wan_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb, FREE_READ); + ++chan->ifstats.rx_errors; + } + else + { + netif_rx(skb); + ++chan->ifstats.rx_packets; + } + +rx_done: + /* Release buffer element and calculate a pointer to the next one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + if ((void*)frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base + ; +} + +/*============================================================================ + * Transmit interrupt handler. + * o print a warning + * o + * If number of spurious interrupts exceeded some limit, then ??? + */ +static void tx_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); +} + +/*============================================================================ + * Spurious interrupt handler. + * o print a warning + * o + * If number of spurious interrupts exceeded some limit, then ??? + */ +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + +/****** Background Polling Routines ****************************************/ + +/*============================================================================ + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * o fetch asynchronous network events. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + */ +static void wpf_poll (sdla_t* card) +{ + fr502_flags_t* flags = card->flags; + + if (flags->event) + { + fr_mbox_t* mbox = card->mbox; + int err; + + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) fr_event(card, err, mbox); + } +} + +/****** Frame Relay Firmware-Specific Functions *****************************/ + +/*============================================================================ + * Read firmware code version. + * o fill string str with firmware version info. + */ +static int fr_read_version (sdla_t* card, char* str) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_CODE_VERSION; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + if (!err && str) + { + int len = mbox->cmd.length; + + memcpy(str, mbox->data, len); + str[len] = '\0'; + } + return err; +} + +/*============================================================================ + * Set global configuration. + */ +static int fr_configure (sdla_t* card, fr_conf_t *conf) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int dlci = card->u.f.node_dlci; + int dlci_num = card->u.f.dlci_num; + int err, i; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, conf, sizeof(fr_conf_t)); + if (dlci_num) for (i = 0; i < dlci_num; ++i) + ((fr_conf_t*)mbox->data)->dlci[i] = dlci + i + ; + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.length = + sizeof(fr_conf_t) + dlci_num * sizeof(short) + ; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + if (card->hw.fwid == SFID_FR502) + { + fr502_intr_ctl_t* ictl = (void*)mbox->data; + + memset(ictl, 0, sizeof(fr502_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + mbox->cmd.length = sizeof(fr502_intr_ctl_t); + } + else + { + fr508_intr_ctl_t* ictl = (void*)mbox->data; + + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->hw.irq; + mbox->cmd.length = sizeof(fr508_intr_ctl_t); + } + mbox->cmd.command = FR_SET_INTR_MODE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Enable communications. + */ +static int fr_comm_enable (sdla_t* card) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_COMM_ENABLE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Disable communications. + */ +static int fr_comm_disable (sdla_t* card) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_COMM_DISABLE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Add DLCI(s) (Access Node only!). + */ +static int fr_add_dlci (sdla_t* card, int dlci, int num) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, i; + + do + { + unsigned short* dlci_list = (void*)mbox->data; + + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) + dlci_list[i] = dlci + i + ; + mbox->cmd.length = num * sizeof(short); + mbox->cmd.command = FR_ADD_DLCI; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Activate DLCI(s) (Access Node only!). + */ +static int fr_activate_dlci (sdla_t* card, int dlci, int num) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, i; + + do + { + unsigned short* dlci_list = (void*)mbox->data; + + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) + dlci_list[i] = dlci + i + ; + mbox->cmd.length = num * sizeof(short); + mbox->cmd.command = FR_ACTIVATE_DLCI; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Issue in-channel signalling frame. + */ +static int fr_issue_isf (sdla_t* card, int isf) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->data[0] = isf; + mbox->cmd.length = 1; + mbox->cmd.command = FR_ISSUE_IS_FRAME; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Send a frame (S502 version). + */ +static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, buf, len); + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; + mbox->cmd.command = FR_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + return err; +} + +/*============================================================================ + * Send a frame (S508 version). + */ +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; + mbox->cmd.command = FR_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_buf_ctl_t* frbuf = (void*)(*(unsigned long*)mbox->data - + FR_MB_VECTOR + card->hw.dpmbase) + ; + unsigned long flags; + + save_flags(flags); + cli(); + sdla_poke(&card->hw, frbuf->offset, buf, len); + frbuf->flag = 0x01; + restore_flags(flags); + } + return err; +} + +/****** Firmware Asynchronous Event Handlers ********************************/ + +/*============================================================================ + * Main asyncronous event/error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) +{ + switch (event) + { + case FRRES_MODEM_FAILURE: + return fr_modem_failure(card, mbox); + + case FRRES_CHANNEL_DOWN: + wanpipe_set_state(card, WAN_DISCONNECTED); + return 1; + + case FRRES_CHANNEL_UP: + wanpipe_set_state(card, WAN_CONNECTED); + return 1; + + case FRRES_DLCI_CHANGE: + return fr_dlci_change(card, mbox); + + case FRRES_DLCI_MISMATCH: + printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname); + return 1; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, mbox->cmd.command) + ; + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, mbox->cmd.command, event) + ; + } + return 0; +} + +/*============================================================================ + * Handle modem error. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) +{ + printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", + card->devname, mbox->data[0]) + ; + switch (mbox->cmd.command) + { + case FR_WRITE: + case FR_READ: + return 0; + } + return 1; +} + +/*============================================================================ + * Handle DLCI status change. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) +{ + dlci_status_t* status = (void*)mbox->data; + int cnt = mbox->cmd.length / sizeof(dlci_status_t); + + for (; cnt; --cnt, ++status) + { + unsigned short dlci = status->dlci; + struct device* dev = find_channel(card, dlci); + + if (status->state & 0x01) + { + printk(KERN_INFO + "%s: DLCI %u has been deleted!\n", + card->devname, dlci) + ; + if (dev && dev->start) + set_chan_state(dev, WAN_DISCONNECTED) + ; + } + else if (status->state & 0x02) + { + printk(KERN_INFO + "%s: DLCI %u becomes active!\n", + card->devname, dlci) + ; + if (dev && dev->start) + set_chan_state(dev, WAN_CONNECTED) + ; + } + } + return 1; +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Update channel state. + */ +static int update_chan_state (struct device* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_LIST_ACTIVE_DLCI; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + unsigned short* list = (void*)mbox->data; + int cnt = mbox->cmd.length / sizeof(short); + + for (; cnt; --cnt, ++list) + { + if (*list == chan->dlci) + { + set_chan_state(dev, WAN_CONNECTED); + break; + } + } + } + return err; +} + +/*============================================================================ + * Set channel state. + */ +static void set_chan_state (struct device* dev, int state) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned long flags; + + save_flags(flags); + cli(); + if (chan->state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: interface %s connected!\n", + card->devname, dev->name) + ; + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: interface %s connecting...\n", + card->devname, dev->name) + ; + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: interface %s disconnected!\n", + card->devname, dev->name) + ; + break; + } + chan->state = state; + } + chan->state_tick = jiffies; + restore_flags(flags); +} + +/*============================================================================ + * Find network device by its channel number. + */ +static struct device* find_channel (sdla_t* card, unsigned dlci) +{ + struct device* dev; + + for (dev = card->wandev.dev; dev; dev = dev->slave) + if (((fr_channel_t*)dev->priv)->dlci == dlci) break + ; + return dev; +} + +/*============================================================================ + * Check to see if a frame can be sent. If no transmit buffers available, + * enable transmit interrupts. + * + * Return: 1 - Tx buffer(s) available + * 0 - no buffers available + */ +static int is_tx_ready (sdla_t* card) +{ + if (card->hw.fwid == SFID_FR508) + { + fr508_flags_t* flags = card->flags; + unsigned char sb = inb(card->hw.port); + + if (sb & 0x02) return 1; + flags->imask |= 0x02; + } + else + { + fr502_flags_t* flags = card->flags; + + if (flags->tx_ready) return 1; + flags->imask |= 0x02; + } + return 0; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0') + ; + return val; +} + +/*============================================================================ + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. + */ +static unsigned int hex_to_uint (unsigned char* str, int len) +{ + unsigned val, ch; + + if (!len) len = strlen(str); + for (val = 0; len; ++str, --len) + { + ch = *str; + if (is_digit(ch)) + val = (val << 4) + (ch - (unsigned)'0') + ; + else if (is_hex_digit(ch)) + val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10) + ; + else break; + } + return val; +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.24/linux/drivers/net/sdla_ppp.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sdla_ppp.c Sun Feb 2 16:43:08 1997 @@ -0,0 +1,1025 @@ +/***************************************************************************** +* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. +* +* Author: Gene Kozin +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* ARPHRD_* defines */ +#include /* htons(), etc. */ + +#define _GNUC_ +#include /* PPP firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ + +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ +#define PPP_HDR_LEN 1 + +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); + +/* Network device interface */ +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, + struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); + +/* PPP firmware interface functions */ +static int ppp_read_version (sdla_t* card, char* str); +static int ppp_configure (sdla_t* card, void* data); +static int ppp_set_intr_mode (sdla_t* card, unsigned mode); +static int ppp_comm_enable (sdla_t* card); +static int ppp_comm_disable (sdla_t* card); +static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto); +static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb); + +/* Interrupt handlers */ +STATIC void wpp_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); + +/* Background polling routines */ +static void wpp_poll (sdla_t* card); +static void poll_active (sdla_t* card); +static void poll_connecting (sdla_t* card); +static void poll_disconnected (sdla_t* card); + +/* Miscellaneous functions */ +static int config502 (sdla_t* card); +static int config508 (sdla_t* card); +static void show_disc_cause (sdla_t* card, unsigned cause); +static unsigned char bps_to_speed_code (unsigned long bps); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * PPP protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpp_init (sdla_t* card, wandev_conf_t* conf) +{ + union + { + char str[80]; + } u; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_PPP) + { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id) + ; + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + switch (card->hw.fwid) + { + case SFID_PPP502: + card->mbox = (void*)(card->hw.dpmbase + PPP502_MB_OFFS); + card->flags = (void*)(card->hw.dpmbase + PPP502_FLG_OFFS); + break; + + case SFID_PPP508: + card->mbox = (void*)(card->hw.dpmbase + PPP508_MB_OFFS); + card->flags = (void*)(card->hw.dpmbase + PPP508_FLG_OFFS); + break; + + default: + return -EINVAL; + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) + return -EIO + ; + printk(KERN_INFO "%s: running PPP firmware v%s\n", + card->devname, u.str) + ; + + /* Adjust configuration and set defaults */ + card->wandev.mtu = (conf->mtu) ? + min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU + ; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpp_isr; + card->poll = &wpp_poll; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ +/* + sdla_t* card = wandev->private; +*/ + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + + if (wandev->ndev) + return -EEXIST + ; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) + { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname) + ; + return -EINVAL; + } + + /* initialize data */ + strcpy(card->u.p.if_name, conf->name); + + /* prepare network device data space for registration */ + dev->name = card->u.p.if_name; + dev->init = &if_init; + dev->priv = card; + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct device* dev) +{ + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device* dev) +{ + sdla_t* card = dev->priv; + wan_device_t* wandev = &card->wandev; + int i; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + dev->family = AF_INET; /* address family */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->mtu = wandev->mtu; + dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Initialize socket buffers */ + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]) + ; + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct device* dev) +{ + sdla_t* card = dev->priv; + int err = 0; + + if (dev->start) + return -EBUSY /* only one open is allowed */ + ; + if (set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + ; + if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) + { + err = -EIO; + goto split; + } + + /* Initialize Rx/Tx buffer control fields */ + if (card->hw.fwid == SFID_PPP502) + { + ppp502_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP502_BUF_OFFS) + ; + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + info->txb_offs) + ; + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1) + ; + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + info->rxb_offs) + ; + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1) + ; + } + else + { + ppp508_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP508_BUF_OFFS) + ; + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + (info->txb_ptr - PPP508_MB_VECT)) + ; + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1) + ; + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + (info->rxb_ptr - PPP508_MB_VECT)) + ; + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1) + ; + card->u.p.rx_base = info->rxb_base; + card->u.p.rx_top = info->rxb_end; + } + card->u.p.txbuf = card->u.p.txbuf_base; + card->rxmb = card->u.p.rxbuf_base; + + if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card)) + { + err = -EIO; + goto split; + } + wanpipe_set_state(card, WAN_CONNECTING); + wanpipe_open(card); + dev->mtu = min(dev->mtu, card->wandev.mtu); + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + +split: + card->wandev.critical = 0; + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (struct device* dev) +{ + sdla_t* card = dev->priv; + + if (set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + ; + dev->start = 0; + wanpipe_close(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + ppp_set_intr_mode(card, 0); + ppp_comm_disable(card); + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + switch (type) + { + case ETH_P_IP: + case ETH_P_IPX: + skb->protocol = type; + break; + + default: + skb->protocol = 0; + } + return PPP_HDR_LEN; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, + struct sk_buff* skb) +{ + sdla_t* card = dev->priv; + + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", + card->devname, dev->name) + ; + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + sdla_t* card = dev->priv; + int retry = 0; + + if (skb == NULL) + { + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ +#ifdef _DEBUG_ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name) + ; +#endif + dev_tint(dev); + return 0; + } + + if (set_bit(0, (void*)&card->wandev.critical)) + { +#ifdef _DEBUG_ + printk(KERN_INFO "%s: if_send() hit critical section!\n", + card->devname) + ; +#endif + return 1; + } + + if (set_bit(0, (void*)&dev->tbusy)) + { +#ifdef _DEBUG_ + printk(KERN_INFO "%s: Tx collision on interface %s!\n", + card->devname, dev->name) + ; +#endif + ++card->wandev.stats.collisions; + retry = 1; + } + else if (card->wandev.state != WAN_CONNECTED) + ++card->wandev.stats.tx_dropped + ; + else if (!skb->protocol) + ++card->wandev.stats.tx_errors + ; + else if (ppp_send(card, skb->data, skb->len, skb->protocol)) + { + ppp_flags_t* flags = card->flags; + + flags->imask |= 0x02; /* unmask Tx interrupts */ + retry = 1; + } + else ++card->wandev.stats.tx_packets; + + if (!retry) + { + dev_kfree_skb(skb, FREE_WRITE); + dev->tbusy = 0; + } + card->wandev.critical = 0; + return retry; +} + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + sdla_t* card = dev->priv; + + return &card->wandev.stats; +} + +/****** PPP Firmware Interface Functions ************************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int ppp_read_version (sdla_t* card, char* str) +{ + ppp_mbox_t* mb = card->mbox; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_READ_CODE_VERSION; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + else if (str) + { + int len = mb->cmd.length; + + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return err; +} + +/*============================================================================ + * Configure PPP firmware. + */ +static int ppp_configure (sdla_t* card, void* data) +{ + ppp_mbox_t* mb = card->mbox; + int data_len = (card->hw.fwid == SFID_PPP502) ? + sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t) + ; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memcpy(mb->data, data, data_len); + mb->cmd.length = data_len; + mb->cmd.command = PPP_SET_CONFIG; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int ppp_set_intr_mode (sdla_t* card, unsigned mode) +{ + ppp_mbox_t* mb = card->mbox; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->data[0] = mode; + switch (card->hw.fwid) + { + case SFID_PPP502: + mb->cmd.length = 1; + break; + + case SFID_PPP508: + default: + mb->data[1] = card->hw.irq; + mb->cmd.length = 2; + } + mb->cmd.command = PPP_SET_INTR_FLAGS; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Enable communications. + */ +static int ppp_comm_enable (sdla_t* card) +{ + ppp_mbox_t* mb = card->mbox; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_COMM_ENABLE; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Disable communications. + */ +static int ppp_comm_disable (sdla_t* card) +{ + ppp_mbox_t* mb = card->mbox; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_COMM_DISABLE; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto) +{ + ppp_buf_ctl_t* txbuf = card->u.p.txbuf; + unsigned long addr, cpu_flags; + + if (txbuf->flag) + return 1 + ; + if (card->hw.fwid == SFID_PPP502) + addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0] + ; + else addr = txbuf->buf.ptr; + + save_flags(cpu_flags); + cli(); + sdla_poke(&card->hw, addr, data, len); + restore_flags(cpu_flags); + txbuf->length = len; /* frame length */ + if (proto == ETH_P_IPX) + txbuf->proto = 0x01 /* protocol ID */ + ; + txbuf->flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.p.txbuf = ++txbuf; + if ((void*)txbuf > card->u.p.txbuf_last) + card->u.p.txbuf = card->u.p.txbuf_base + ; + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb) +{ + unsigned cmd = mb->cmd.command; + + switch (err) + { + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd) + ; + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err) + ; + } + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * PPP interrupt service routine. + */ +STATIC void wpp_isr (sdla_t* card) +{ + ppp_flags_t* flags = card->flags; + + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + flags->imask &= ~0x02; + tx_intr(card); + break; + + default: /* unexpected interrupt */ + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags->iflag) + ; + } + flags->iflag = 0; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + ppp_buf_ctl_t* rxbuf = card->rxmb; + struct device* dev = card->wandev.dev; + struct sk_buff* skb; + unsigned len; + void* buf; + + if (rxbuf->flag != 0x01) + { + printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", + card->devname, (unsigned)rxbuf) + ; + return; + } + + if (!dev || !dev->start) + goto rx_done + ; + len = rxbuf->length; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + if (skb == NULL) + { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname) + ; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } + + /* Copy data to the socket buffer */ + if (card->hw.fwid == SFID_PPP502) + { + unsigned addr = (rxbuf->buf.o_p[1] << 8) + rxbuf->buf.o_p[0]; + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + } + else + { + unsigned addr = rxbuf->buf.ptr; + + if ((addr + len) > card->u.p.rx_top) + { + unsigned tmp = card->u.p.rx_top - addr; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.p.rx_base; + len -= tmp; + } + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + } + + /* Decapsulate packet and pass it up the protocol stack */ + switch (rxbuf->proto) + { + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; + } + skb->dev = dev; + netif_rx(skb); + ++card->wandev.stats.rx_packets; + +rx_done: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; + card->rxmb = ++rxbuf; + if ((void*)rxbuf > card->u.p.rxbuf_last) + card->rxmb = card->u.p.rxbuf_base + ; +} + +/*============================================================================ + * Transmit interrupt handler. + */ +static void tx_intr (sdla_t* card) +{ + struct device* dev = card->wandev.dev; + + if (!dev || !dev->start) + return + ; + dev->tbusy = 0; + dev_tint(dev); +} + +/****** Background Polling Routines ****************************************/ + +/*============================================================================ + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thread' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + */ +static void wpp_poll (sdla_t* card) +{ + switch(card->wandev.state) + { + case WAN_CONNECTED: + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + } +} + +/*============================================================================ + * Monitor active link phase. + */ +static void poll_active (sdla_t* card) +{ + ppp_flags_t* flags = card->flags; + + if (flags->disc_cause & 0x03) + { + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); + } +} + +/*============================================================================ + * Monitor link establishment phase. + * o if connection timed out, disconnect the link. + */ +static void poll_connecting (sdla_t* card) +{ + ppp_flags_t* flags = card->flags; + + if (flags->lcp_state == 0x09) + { + wanpipe_set_state(card, WAN_CONNECTED); + } + else if (flags->disc_cause & 0x03) + { + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); + } +} + +/*============================================================================ + * Monitor physical link disconnected phase. + * o if interface is up and the hold-down timeout has expired, then retry + * connection. + */ +static void poll_disconnected (sdla_t* card) +{ + struct device* dev = card->wandev.dev; + + if (dev && dev->start && + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) + { + wanpipe_set_state(card, WAN_CONNECTING); + ppp_comm_enable(card); + } +} + +/****** Miscellaneous Functions *********************************************/ + +/*============================================================================ + * Configure S502 adapter. + */ +static int config502 (sdla_t* card) +{ + ppp502_conf_t cfg; + + /* Prepare PPP configuration structure */ + memset(&cfg, 0, sizeof(ppp502_conf_t)); + + if (card->wandev.clocking) + cfg.line_speed = bps_to_speed_code(card->wandev.bps) + ; + cfg.txbuf_num = 4; + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 5; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 900; + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + cfg.ip_options = 0x80; + cfg.ipx_options = 0xA0; +/* + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +*/ + return ppp_configure(card, &cfg); +} + +/*============================================================================ + * Configure S508 adapter. + */ +static int config508 (sdla_t* card) +{ + ppp508_conf_t cfg; + + /* Prepare PPP configuration structure */ + memset(&cfg, 0, sizeof(ppp508_conf_t)); + + if (card->wandev.clocking) + cfg.line_speed = card->wandev.bps + ; + if (card->wandev.interface == WANOPT_RS232) + cfg.conf_flags |= 0x0020; + ; + cfg.txbuf_percent = 60; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 5; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 900; + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + cfg.ip_options = 0x80; + cfg.ipx_options = 0xA0; +/* + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +*/ + return ppp_configure(card, &cfg); +} + +/*============================================================================ + * Show disconnection cause. + */ +static void show_disc_cause (sdla_t* card, unsigned cause) +{ + if (cause & 0x0002) printk(KERN_INFO + "%s: link terminated by peer\n", card->devname) + ; + else if (cause & 0x0004) printk(KERN_INFO + "%s: link terminated by user\n", card->devname) + ; + else if (cause & 0x0008) printk(KERN_INFO + "%s: authentication failed\n", card->devname) + ; + else if (cause & 0x0010) printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname) + ; + else if (cause & 0x0020) printk(KERN_INFO + "%s: peer's request for authentication rejected\n", + card->devname) + ; + else if (cause & 0x0040) printk(KERN_INFO + "%s: MRU option rejected by peer\n", card->devname) + ; + else if (cause & 0x0080) printk(KERN_INFO + "%s: peer's MRU was too small\n", card->devname) + ; + else if (cause & 0x0100) printk(KERN_INFO + "%s: failed to negotiate peer's LCP options\n", + card->devname) + ; + else if (cause & 0x0200) printk(KERN_INFO + "%s: failed to negotiate peer's IPCP options\n", + card->devname) + ; + else if (cause & 0x0400) printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname) + ; +} + +/*============================================================================ + * Convert line speed in bps to a number used by S502 code. + */ +static unsigned char bps_to_speed_code (unsigned long bps) +{ + unsigned char number; + + if (bps <= 1200) number = 0x01 ; + else if (bps <= 2400) number = 0x02; + else if (bps <= 4800) number = 0x03; + else if (bps <= 9600) number = 0x04; + else if (bps <= 19200) number = 0x05; + else if (bps <= 38400) number = 0x06; + else if (bps <= 45000) number = 0x07; + else if (bps <= 56000) number = 0x08; + else if (bps <= 64000) number = 0x09; + else if (bps <= 74000) number = 0x0A; + else if (bps <= 112000) number = 0x0B; + else if (bps <= 128000) number = 0x0C; + else number = 0x0D; + + return number; +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.24/linux/drivers/net/sdla_x25.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sdla_x25.c Sun Feb 2 16:43:19 1997 @@ -0,0 +1,1961 @@ +/***************************************************************************** +* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. +* +* Author: Gene Kozin +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* htons(), etc. */ + +#define _GNUC_ +#include /* X.25 firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ +#define X25_HRDHDR_SZ 6 /* max encapsulation header size */ +#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ +#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +/****** Data Structures *****************************************************/ + +/* This is an extention of the 'struct device' we create for each network + * interface to keep the rest of X.25 channel-specific data. + */ +typedef struct x25_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + unsigned lcn; /* logical channel number */ + unsigned tx_pkt_size; + unsigned short protocol; /* ethertype, 0 - multiplexed */ + char svc; /* 0 - permanent, 1 - switched */ + char state; /* channel state */ + char drop_sequence; /* mark sequence for dropping */ + unsigned long state_tick; /* time of the last state change */ + unsigned idle_timeout; /* sec, before disconnecting */ + unsigned hold_timeout; /* sec, before re-connecting */ + struct sk_buff* rx_skb; /* receive socket buffer */ + struct sk_buff* tx_skb; /* transmit socket buffer */ + sdla_t* card; /* -> owner */ + int ch_idx; + struct enet_statistics ifstats; /* interface statistics */ +} x25_channel_t; + +typedef struct x25_call_info +{ + char dest[17]; /* ASCIIZ destination address */ + char src[17]; /* ASCIIZ source address */ + char nuser; /* number of user data bytes */ + unsigned char user[127]; /* user data */ + char nfacil; /* number of facilities */ + struct + { + unsigned char code; + unsigned char parm; + } facil[64]; /* facilities */ +} x25_call_info_t; + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); + +/* Network device interface */ +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, + struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); + +/* Interrupt handlers */ +static void wpx_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); +static void status_intr (sdla_t* card); +static void event_intr (sdla_t* card); +static void spur_intr (sdla_t* card); + +/* Background polling routines */ +static void wpx_poll (sdla_t* card); +static void poll_disconnected (sdla_t* card); +static void poll_connecting (sdla_t* card); +static void poll_active (sdla_t* card); + +/* X.25 firmware interface functions */ +static int x25_get_version (sdla_t* card, char* str); +static int x25_configure (sdla_t* card, TX25Config* conf); +static int x25_set_intr_mode (sdla_t* card, int mode); +static int x25_close_hdlc (sdla_t* card); +static int x25_open_hdlc (sdla_t* card); +static int x25_setup_hdlc (sdla_t* card); +static int x25_set_dtr (sdla_t* card, int dtr); +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); +static int x25_place_call (sdla_t* card, x25_channel_t* chan); +static int x25_accept_call (sdla_t* card, int lcn, int qdm); +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); +static int x25_fetch_events (sdla_t* card); +static int x25_error (sdla_t* card, int err, int cmd, int lcn); + +/* X.25 asynchronous event handlers */ +static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); + +/* Miscellaneous functions */ +static int connect (sdla_t* card); +static int disconnect (sdla_t* card); +static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); +static int chan_connect (struct device* dev); +static int chan_disc (struct device* dev); +static void set_chan_state (struct device* dev, int state); +static int chan_send (struct device* dev, struct sk_buff* skb); +static unsigned char bps_to_speed_code (unsigned long bps); +static unsigned int dec_to_uint (unsigned char* str, int len); +static unsigned int hex_to_uint (unsigned char* str, int len); +static void parse_call_info (unsigned char* str, x25_call_info_t* info); + +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * X.25 Protocol Initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpx_init (sdla_t* card, wandev_conf_t* conf) +{ + union + { + char str[80]; + TX25Config cfg; + } u; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_X25) + { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id) + ; + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); + card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); + card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) + return -EIO + ; + printk(KERN_INFO "%s: running X.25 firmware v%s\n", + card->devname, u.str) + ; + + /* Configure adapter. Here we set resonable defaults, then parse + * device configuration structure and set configuration options. + * Most configuration options are verified and corrected (if + * necessary) since we can't rely on the adapter to do so and don't + * want it to fail either. + */ + memset(&u.cfg, 0, sizeof(u.cfg)); + u.cfg.t1 = 3; + u.cfg.n2 = 10; + u.cfg.autoHdlc = 1; /* automatic HDLC connection */ + u.cfg.hdlcWindow = 7; + u.cfg.pktWindow = 2; + u.cfg.station = 1; /* DTE */ + u.cfg.options = 0x0010; /* disable D-bit pragmatics */ + u.cfg.ccittCompat = 1988; + u.cfg.t10t20 = 30; + u.cfg.t11t21 = 30; + u.cfg.t12t22 = 30; + u.cfg.t13t23 = 30; + u.cfg.t16t26 = 30; + u.cfg.t28 = 30; + u.cfg.r10r20 = 5; + u.cfg.r12r22 = 5; + u.cfg.r13r23 = 5; + + if (conf->clocking != WANOPT_EXTERNAL) + u.cfg.baudRate = bps_to_speed_code(conf->bps) + ; + if (conf->station != WANOPT_DTE) + { + u.cfg.station = 0; /* DCE mode */ + } + + /* adjust MTU */ + if (!conf->mtu || (conf->mtu >= 1024)) + card->wandev.mtu = 1024 + ; + else if (conf->mtu >= 512) + card->wandev.mtu = 512 + ; + else if (conf->mtu >= 256) + card->wandev.mtu = 256 + ; + else if (conf->mtu >= 128) + card->wandev.mtu = 128 + ; + else conf->mtu = 64; + u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; + + if (conf->u.x25.hi_pvc) + { + card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); + card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); + } + if (conf->u.x25.hi_svc) + { + card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); + card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); + } + u.cfg.loPVC = card->u.x.lo_pvc; + u.cfg.hiPVC = card->u.x.hi_pvc; + u.cfg.loTwoWaySVC = card->u.x.lo_svc; + u.cfg.hiTwoWaySVC = card->u.x.hi_svc; + + if (conf->u.x25.hdlc_window) + u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7) + ; + if (conf->u.x25.pkt_window) + u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7) + ; + if (conf->u.x25.t1) + u.cfg.t1 = min(conf->u.x25.t1, 30) + ; + u.cfg.t2 = min(conf->u.x25.t2, 29); + u.cfg.t4 = min(conf->u.x25.t4, 240); + if (conf->u.x25.n2) + u.cfg.n2 = min(conf->u.x25.n2, 30) + ; + if (conf->u.x25.ccitt_compat) + u.cfg.ccittCompat = conf->u.x25.ccitt_compat + ; + + /* initialize adapter */ + if ((x25_configure(card, &u.cfg) != CMD_OK) || + (x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ + (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ + return -EIO + ; + + /* Initialize protocol-specific fields of adapter data space */ + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpx_isr; + card->poll = &wpx_poll; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ +/* + sdla_t* card = wandev->private; +*/ + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + x25_channel_t* chan; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) + { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname) + ; + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL); + if (chan == NULL) + return -ENOMEM + ; + memset(chan, 0, sizeof(x25_channel_t)); + strcpy(chan->name, conf->name); + chan->card = card; + + /* verify media address */ + if (conf->addr[0] == '@') /* SVC */ + { + chan->svc = 1; + chan->protocol = ETH_P_IP; + strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); + } + else if (is_digit(conf->addr[0])) /* PVC */ + { + int lcn = dec_to_uint(conf->addr, 0); + + if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)) + { + chan->lcn = lcn; + } + else + { + printk(KERN_ERR + "%s: PVC %u is out of range on interface %s!\n", + wandev->name, lcn, chan->name) + ; + err = -EINVAL; + } + } + else + { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name) + ; + err = -EINVAL; + } + if (err) + { + kfree(chan); + return err; + } + + /* prepare network device data space for registration */ + dev->name = chan->name; + dev->init = &if_init; + dev->priv = chan; + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct device* dev) +{ + if (dev->priv) + { + kfree(dev->priv); + dev->priv = NULL; + } + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + int i; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + dev->family = AF_INET; /* address family */ + dev->type = 30; /* ARP h/w type */ + dev->mtu = X25_CHAN_MTU; + dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ + dev->addr_len = 2; /* hardware address length */ + if (!chan->svc) + *(unsigned short*)dev->dev_addr = htons(chan->lcn) + ; + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Initialize socket buffers */ + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]) + ; + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + +/*============================================================================ + * Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (dev->start) + return -EBUSY /* only one open is allowed */ + ; + if (set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + ; + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + + /* If this is the first open, initiate physical connection */ + if (card->open_cnt == 1) + connect(card) + ; + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Close network interface. + * o reset flags. + * o if there's no more open channels then disconnect physical link. + */ +static int if_close (struct device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + ; + dev->start = 0; + if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) + chan_disc(dev) + ; + wanpipe_close(card); + + /* If this is the last close, disconnect physical link */ + if (!card->open_cnt) + disconnect(card) + ; + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Build media header. + * o encapsulate packet according to encapsulation type. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If encapsulation fails, + * set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + x25_channel_t* chan = dev->priv; + int hdr_len = dev->hard_header_len; + + skb->protocol = type; + if (!chan->protocol) + { + hdr_len = wan_encapsulate(skb, dev); + if (hdr_len < 0) + { + hdr_len = 0; + skb->protocol = 0; + } + } + return hdr_len; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, + struct sk_buff* skb) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", + card->devname, dev->name) + ; + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int retry = 0, queued = 0; + + if (skb == NULL) + { + /* If we get here, some higher layer thinks we've missed a + * tx-done interrupt. + */ +#ifdef _DEBUG_ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name) + ; +#endif + dev_tint(dev); + return 0; + } + + if (set_bit(0, (void*)&card->wandev.critical)) + { +#ifdef _DEBUG_ + printk(KERN_INFO "%s: if_send() hit critical section!\n", + card->devname) + ; +#endif + return 1; + } + + if (set_bit(0, (void*)&dev->tbusy)) + { +#ifdef _DEBUG_ + printk(KERN_INFO "%s: Tx collision on interface %s!\n", + card->devname, dev->name) + ; +#endif + ++chan->ifstats.collisions; + retry = 1; + } + else if (chan->protocol && (chan->protocol != skb->protocol)) + { + printk(KERN_INFO + "%s: unsupported Ethertype 0x%04X on interface %s!\n", + card->devname, skb->protocol, dev->name) + ; + ++chan->ifstats.tx_errors; + } + else if (card->wandev.state != WAN_CONNECTED) + ++chan->ifstats.tx_dropped + ; + else switch (chan->state) + { + case WAN_CONNECTED: + dev->trans_start = jiffies; + queued = chan_send(dev, skb); + if (queued) chan->tx_skb = skb; + break; + + case WAN_DISCONNECTED: + /* Try to establish connection. If succeded, then start + * transmission, else drop a packet. + */ + if (chan_connect(dev) == 0) + { + dev->trans_start = jiffies; + queued = chan_send(dev, skb); + if (queued) chan->tx_skb = skb; + break; + } + /* else fall through */ + + default: + ++chan->ifstats.tx_dropped; + } + + if (!retry && !queued) + { + dev_kfree_skb(skb, FREE_WRITE); + dev->tbusy = 0; + } + card->wandev.critical = 0; + return retry; +} + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + x25_channel_t* chan = dev->priv; + + return &chan->ifstats; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * X.25 Interrupt Service Routine. + */ +static void wpx_isr (sdla_t* card) +{ + TX25Status* status = card->flags; + + switch (status->iflags) + { + case 0x01: /* receive interrupt */ + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + tx_intr(card); + break; + + case 0x04: /* modem status interrupt */ + status_intr(card); + break; + + case 0x10: /* network event interrupt */ + event_intr(card); + break; + + default: /* unwanter interrupt */ + spur_intr(card); + } + status->iflags = 0; /* clear interrupt condition */ +} + +/*============================================================================ + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * comming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. + */ +static void rx_intr (sdla_t* card) +{ + TX25Mbox* rxmb = card->rxmb; + unsigned lcn = rxmb->cmd.lcn; /* logical channel number */ + unsigned len = rxmb->cmd.length; /* packet length */ + unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ + wan_device_t* wandev = &card->wandev; + struct device* dev = get_dev_by_lcn(wandev, lcn); + x25_channel_t* chan; + struct sk_buff* skb; + void* bufptr; + + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", + card->devname, lcn) + ; + return; + } + + chan = dev->priv; + if (chan->drop_sequence) + { + if (!(qdm & 0x01)) chan->drop_sequence = 0; + return; + } + + skb = chan->rx_skb; + if (skb == NULL) + { + /* Allocate new socket buffer */ + int bufsize = (qdm & 0x01) ? dev->mtu : len; + + skb = dev_alloc_skb(bufsize + dev->hard_header_len); + if (skb == NULL) + { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname) + ; + chan->drop_sequence = 1; /* set flag */ + ++chan->ifstats.rx_dropped; + return; + } + skb->dev = dev; + skb->protocol = htons(chan->protocol); + chan->rx_skb = skb; + } + + if (skb_tailroom(skb) < len) + { + /* No room for the packet. Call off the whole thing! */ + dev_kfree_skb(skb, FREE_READ); + chan->rx_skb = NULL; + if (qdm & 0x01) chan->drop_sequence = 1; + + printk(KERN_INFO "%s: unexpectedly long packet sequence " + "on interface %s!\n", card->devname, dev->name) + ; + ++chan->ifstats.rx_length_errors; + return; + } + + /* Append packet to the socket buffer */ + bufptr = skb_put(skb, len); + memcpy(bufptr, rxmb->data, len); + if (qdm & 0x01) return; /* more data is comming */ + + dev->last_rx = jiffies; /* timestamp */ + chan->rx_skb = NULL; /* dequeue packet */ + + /* Decapsulate packet, if necessary */ + if (!skb->protocol && !wan_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb, FREE_READ); + ++chan->ifstats.rx_errors; + } + else + { + netif_rx(skb); + ++chan->ifstats.rx_packets; + } +} + +/*============================================================================ + * Transmit interrupt handler. + * o Release socket buffer + * o Clear 'tbusy' flag + */ +static void tx_intr (sdla_t* card) +{ +} + +/*============================================================================ + * Modem status interrupt handler. + */ +static void status_intr (sdla_t* card) +{ +} + +/*============================================================================ + * Network event interrupt handler. + */ +static void event_intr (sdla_t* card) +{ +} + +/*============================================================================ + * Spurious interrupt handler. + * o print a warning + * o + * If number of spurious interrupts exceeded some limit, then ??? + */ +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + +/****** Background Polling Routines ****************************************/ + +/*============================================================================ + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + */ +static void wpx_poll (sdla_t* card) +{ + switch(card->wandev.state) + { + case WAN_CONNECTED: + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + } +} + +/*============================================================================ + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. + */ +static void poll_connecting (sdla_t* card) +{ + TX25Status* status = card->flags; + + if (status->gflags & X25_HDLC_ABM) + { + wanpipe_set_state(card, WAN_CONNECTED); + x25_set_intr_mode(card, 0x81); /* enable Rx interrupts */ + } + else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) + disconnect(card) + ; +} + +/*============================================================================ + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, connect + * link. + */ +static void poll_disconnected (sdla_t* card) +{ + if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) + connect(card) + ; +} + +/*============================================================================ + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. + */ +static void poll_active (sdla_t* card) +{ + struct device* dev; + + /* Fetch X.25 asynchronous events */ + x25_fetch_events(card); + + for (dev = card->wandev.dev; dev; dev = dev->slave) + { + x25_channel_t* chan = dev->priv; + struct sk_buff* skb = chan->tx_skb; + + /* If there is a packet queued for transmission then kick + * the channel's send routine. When transmission is complete + * or if error has occured, release socket buffer and reset + * 'tbusy' flag. + */ + if (skb && (chan_send(dev, skb) == 0)) + { + chan->tx_skb = NULL; + dev->tbusy = 0; + dev_kfree_skb(skb, FREE_WRITE); + } + + /* If SVC has been idle long enough, close virtual circuit */ + +/* + unsigned long flags; + + save_flags(flags); + cli(); + + restore_flags(flags); +*/ + } +} + +/****** SDLA Firmware-Specific Functions ************************************* + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incomming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface command + * in a loop until good return code is received or maximum number of retries + * is reached. Each interface command returns non-zero return code, an + * asynchronous event/error handler x25_error() is called. + */ + +/*============================================================================ + * Read X.25 firmware version. + * Put code version as ASCII string in str. + */ +static int x25_get_version (sdla_t* card, char* str) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_READ_CODE_VERSION; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_READ_CODE_VERSION, 0)) + ; + + if (!err && str) + { + int len = mbox->cmd.length; + + memcpy(str, mbox->data, len); + str[len] = '\0'; + } + return err; +} + +/*============================================================================ + * Configure adapter. + */ +static int x25_configure (sdla_t* card, TX25Config* conf) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); + mbox->cmd.length = sizeof(TX25Config); + mbox->cmd.command = X25_SET_CONFIGURATION; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_SET_CONFIGURATION, 0)) + ; + return err; +} + +/*============================================================================ + * Close HDLC link. + */ +static int x25_close_hdlc (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_CLOSE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)) + ; + return err; +} + +/*============================================================================ + * Open HDLC link. + */ +static int x25_open_hdlc (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_OPEN; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_HDLC_LINK_OPEN, 0)) + ; + return err; +} + +/*============================================================================ + * Setup HDLC link. + */ +static int x25_setup_hdlc (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_SETUP; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_HDLC_LINK_SETUP, 0)) + ; + return err; +} + +/*============================================================================ + * Set (raise/drop) DTR. + */ +static int x25_set_dtr (sdla_t* card, int dtr) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->data[0] = 0; + mbox->data[2] = 0; + mbox->data[1] = dtr ? 0x02 : 0x01; + mbox->cmd.length = 3; + mbox->cmd.command = X25_SET_GLOBAL_VARS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_SET_GLOBAL_VARS, 0)) + ; + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int x25_set_intr_mode (sdla_t* card, int mode) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->data[0] = mode; + if (card->hw.fwid == SFID_X25_508) + { + mbox->data[1] = card->hw.irq; + mbox->cmd.length = 2; + } + else mbox->cmd.length = 1; + mbox->cmd.command = X25_SET_INTERRUPT_MODE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) + ; + return err; +} + +/*============================================================================ + * Read X.25 channel configuration. + */ +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int lcn = chan->lcn; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.lcn = lcn; + mbox->cmd.command = X25_READ_CHANNEL_CONFIG; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)) + ; + + if (!err) + { + TX25Status* status = card->flags; + + /* calculate an offset into the array of status bytes */ + if (card->u.x.hi_svc <= 255) + chan->ch_idx = lcn - 1 + ; + else + { + int offset; + + switch (mbox->data[0] && 0x1F) + { + case 0x01: offset = status->pvc_map; break; + case 0x03: offset = status->icc_map; break; + case 0x07: offset = status->twc_map; break; + case 0x0B: offset = status->ogc_map; break; + default: offset = 0; + } + chan->ch_idx = lcn - 1 - offset; + } + + /* get actual transmit packet size on this channel */ + switch(mbox->data[1] & 0x38) + { + case 0x00: chan->tx_pkt_size = 16; break; + case 0x08: chan->tx_pkt_size = 32; break; + case 0x10: chan->tx_pkt_size = 64; break; + case 0x18: chan->tx_pkt_size = 128; break; + case 0x20: chan->tx_pkt_size = 256; break; + case 0x28: chan->tx_pkt_size = 512; break; + case 0x30: chan->tx_pkt_size = 1024; break; + } + printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", + card->devname, lcn, chan->tx_pkt_size) + ; + } + return err; +} + +/*============================================================================ + * Place X.25 call. + */ +static int x25_place_call (sdla_t* card, x25_channel_t* chan) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + char str[64]; + + sprintf(str, "-d%s -uCC", chan->addr); + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + strcpy(mbox->data, str); + mbox->cmd.length = strlen(str); + mbox->cmd.command = X25_PLACE_CALL; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_PLACE_CALL, 0)) + ; + if (!err) + { + chan->lcn = mbox->cmd.lcn; + chan->protocol = ETH_P_IP; + } + return err; +} + +/*============================================================================ + * Accept X.25 call. + */ +static int x25_accept_call (sdla_t* card, int lcn, int qdm) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.lcn = lcn; + mbox->cmd.qdm = qdm; + mbox->cmd.command = X25_ACCEPT_CALL; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_ACCEPT_CALL, lcn)) + ; + return err; +} + +/*============================================================================ + * Clear X.25 call. + */ +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.lcn = lcn; + mbox->cmd.cause = cause; + mbox->cmd.diagn = diagn; + mbox->cmd.command = X25_CLEAR_CALL; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_CLEAR_CALL, lcn)) + ; + return err; +} + +/*============================================================================ + * Send X.25 data packet. + */ +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + memcpy(mbox->data, buf, len); + mbox->cmd.length = len; + mbox->cmd.lcn = lcn; + mbox->cmd.qdm = qdm; + mbox->cmd.command = X25_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn)); + return err; +} + +/*============================================================================ + * Fetch X.25 asynchronous events. + */ +static int x25_fetch_events (sdla_t* card) +{ + TX25Status* status = card->flags; + TX25Mbox* mbox = card->mbox; + int err = 0; + + if (status->gflags & 0x20) + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_IS_DATA_AVAILABLE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + } + return err; +} + +/*============================================================================ + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns non-zero + * return code to handle X.25 asynchronous events and common errors. + * Return non-zero to repeat command or zero to cancel it. + * + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. + */ +static int x25_error (sdla_t* card, int err, int cmd, int lcn) +{ + int retry = 1; + unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; + TX25Mbox* mb; + + mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); + if (mb == NULL) + { + printk(KERN_ERR "%s: x25_error() out of memory!\n", + card->devname) + ; + return 0; + } + memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); + switch (err) + { + case 0x40: /* X.25 asynchronous packet was received */ + mb->data[dlen] = '\0'; + switch (mb->cmd.pktType & 0x7F) + { + case 0x30: /* incomming call */ + retry = incomming_call(card, cmd, lcn, mb); + break; + + case 0x31: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); + break; + + case 0x02: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); + break; + + case 0x04: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn) + ; + break; + + case 0x08: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); + break; + + default: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.pktType, + mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn) + ; + } + break; + + case 0x41: /* X.25 protocol violation indication */ + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, + mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn) + ; + break; + + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; + + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) + ; + break; + + case 0x08: /* modem failure */ + printk(KERN_INFO "%s: modem failure!\n", card->devname); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname) + ; + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->data[0]) + ; + break; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd) + ; + retry = 0; /* abort command */ + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err) + ; + retry = 0; /* abort command */ + } + kfree(mb); + return retry; +} + +/****** X.25 Asynchronous Event Handlers ************************************* + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. + */ + +/*============================================================================ + * Handle X.25 incomming call request. + * RFC 1356 establishes the following rules: + * 1. The first octet in the Call User Data (CUD) field of the call + * request packet contains NLPID identifying protocol encapsulation. + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when + * clearing a call because protocol encapsulation is not supported. + * 4. If an incomming call is received while a call request is pending + * (i.e. call collision has occured), the incomming call shall be + * rejected and call request shall be retried. + */ +static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + wan_device_t* wandev = &card->wandev; + int new_lcn = mb->cmd.lcn; + struct device* dev = get_dev_by_lcn(wandev, new_lcn); + x25_channel_t* chan = NULL; + int accept = 0; /* set to '1' if o.k. to accept call */ + x25_call_info_t* info; + + /* Make sure there is no call collision */ + if (dev != NULL) + { + printk(KERN_INFO + "%s: X.25 incomming call collision on LCN %d!\n", + card->devname, new_lcn) + ; + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + + /* Make sure D bit is not set in call request */ + if (mb->cmd.qdm & 0x02) + { + printk(KERN_INFO + "%s: X.25 incomming call on LCN %d with D-bit set!\n", + card->devname, new_lcn) + ; + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + + /* Parse call request data */ + info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); + if (info == NULL) + { + printk(KERN_ERR + "%s: not enough memory to parse X.25 incomming call " + "on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + parse_call_info(mb->data, info); + printk(KERN_INFO "%s: X.25 incomming call on LCN %d! Call data: %s\n", + card->devname, new_lcn, mb->data) + ; + + /* Find available channel */ + for (dev = wandev->dev; dev; dev = dev->slave) + { + chan = dev->priv; + + if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + continue + ; + if (strcmp(info->src, chan->addr) == 0) + break + ; + } + + if (dev == NULL) + { + printk(KERN_INFO "%s: no channels available!\n", + card->devname) + ; + x25_clear_call(card, new_lcn, 0, 0); + } + + /* Check requested protocol encapsulation */ + else if (info->nuser == 0) + { + printk(KERN_INFO + "%s: no user data in incomming call on LCN %d!\n", + card->devname, new_lcn) + ; + x25_clear_call(card, new_lcn, 0, 0); + } + else switch (info->user[0]) + { + case 0: /* multiplexed */ + chan->protocol = 0; + accept = 1; + break; + + case NLPID_IP: /* IP datagrams */ + chan->protocol = ETH_P_IP; + accept = 1; + break; + + case NLPID_SNAP: + default: + printk(KERN_INFO + "%s: unsupported NLPID 0x%02X in incomming call " + "on LCN %d!\n", card->devname, info->user[0], new_lcn) + ; + x25_clear_call(card, new_lcn, 0, 249); + } + + if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) + { + chan->lcn = new_lcn; + if (x25_get_chan_conf(card, chan) == CMD_OK) + set_chan_state(dev, WAN_CONNECTED) + ; + else x25_clear_call(card, new_lcn, 0, 0); + } + kfree(info); + return 1; +} + +/*============================================================================ + * Handle accepted call. + */ +static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + unsigned new_lcn = mb->cmd.lcn; + struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + x25_channel_t* chan; + + printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n", + card->devname, new_lcn) + ; + if (dev == NULL) + { + printk(KERN_INFO + "%s: clearing orphaned connection on LCN %d!\n", + card->devname, new_lcn) + ; + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + + /* Get channel configuration and notify router */ + chan = dev->priv; + if (x25_get_chan_conf(card, chan) != CMD_OK) + { + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + set_chan_state(dev, WAN_CONNECTED); + return 1; +} + +/*============================================================================ + * Handle cleared call. + */ +static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + unsigned new_lcn = mb->cmd.lcn; + struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + + printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " + "Diagn:0x%02X\n", + card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn) + ; + if (dev == NULL) return 1; + set_chan_state(dev, WAN_DISCONNECTED); + + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; +} + +/*============================================================================ + * Handle X.25 restart event. + */ +static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + wan_device_t* wandev = &card->wandev; + struct device* dev; + + printk(KERN_INFO + "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.cause, mb->cmd.diagn) + ; + + /* down all logical channels */ + for (dev = wandev->dev; dev; dev = dev->slave) + set_chan_state(dev, WAN_DISCONNECTED) + ; + return (cmd == X25_WRITE) ? 0 : 1; +} + +/*============================================================================ + * Handle timeout event. + */ +static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + unsigned new_lcn = mb->cmd.lcn; + + if (mb->cmd.pktType == 0x05) /* call request time out */ + { + struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + + printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", + card->devname, new_lcn) + ; + if (dev) set_chan_state(dev, WAN_DISCONNECTED); + } + else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", + card->devname, mb->cmd.pktType, new_lcn) + ; + return 1; +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Establish physical connection. + * o open HDLC and raise DTR + * + * Return: 0 connection established + * 1 connection is in progress + * <0 error + */ +static int connect (sdla_t* card) +{ + if (x25_open_hdlc(card) || x25_setup_hdlc(card)) + return -EIO + ; + wanpipe_set_state(card, WAN_CONNECTING); + return 1; +} + +/*============================================================================ + * Tear down physical connection. + * o close HDLC link + * o drop DTR + * + * Return: 0 + * <0 error + */ +static int disconnect (sdla_t* card) +{ + wanpipe_set_state(card, WAN_DISCONNECTED); + x25_set_intr_mode(card, 0); /* disable interrupt generation */ + x25_close_hdlc(card); /* close HDLC link */ + x25_set_dtr(card, 0); /* drop DTR */ + return 0; +} + +/*============================================================================ + * Find network device by its channel number. + */ +static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) +{ + struct device* dev; + + for (dev = wandev->dev; dev; dev = dev->slave) + if (((x25_channel_t*)dev->priv)->lcn == lcn) break + ; + return dev; +} + +/*============================================================================ + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call + * + * Return: 0 connected + * >0 connection in progress + * <0 failure + */ +static int chan_connect (struct device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->svc) + { + if (!chan->addr[0]) + return -EINVAL /* no destination address */ + ; + printk(KERN_INFO "%s: placing X.25 call to %s ...\n", + card->devname, chan->addr) + ; + if (x25_place_call(card, chan) != CMD_OK) + return -EIO + ; + set_chan_state(dev, WAN_CONNECTING); + return 1; + } + else + { + if (x25_get_chan_conf(card, chan) != CMD_OK) + return -EIO + ; + set_chan_state(dev, WAN_CONNECTED); + } + return 0; +} + +/*============================================================================ + * Disconnect logical channel. + * o if SVC then clear X.25 call + */ +static int chan_disc (struct device* dev) +{ + x25_channel_t* chan = dev->priv; + + set_chan_state(dev, WAN_DISCONNECTED); + if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0); + return 0; +} + +/*============================================================================ + * Set logical channel state. + */ +static void set_chan_state (struct device* dev, int state) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned long flags; + + save_flags(flags); + cli(); + if (chan->state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: interface %s connected!\n", + card->devname, dev->name) + ; + *(unsigned short*)dev->dev_addr = htons(chan->lcn); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: interface %s connecting...\n", + card->devname, dev->name) + ; + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: interface %s disconnected!\n", + card->devname, dev->name) + ; + if (chan->svc) + *(unsigned short*)dev->dev_addr = 0 + ; + break; + } + chan->state = state; + } + chan->state_tick = jiffies; + restore_flags(flags); +} + +/*============================================================================ + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data space + * points to the transmit socket buffer. When transmission is complete, + * release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. + */ +static int chan_send (struct device* dev, struct sk_buff* skb) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + TX25Status* status = card->flags; + unsigned len, qdm; + + /* Check to see if channel is ready */ + if (!(status->cflags[chan->ch_idx] & 0x40)) + return 1 + ; + if (skb->len > chan->tx_pkt_size) + { + len = chan->tx_pkt_size; + qdm = 0x01; /* set M-bit (more data) */ + } + else /* final packet */ + { + len = skb->len; + qdm = 0; + } + switch(x25_send(card, chan->lcn, qdm, len, skb->data)) + { + case 0x00: /* success */ + if (qdm) + { + skb_pull(skb, len); + return 1; + } + ++chan->ifstats.tx_packets; + break; + + case 0x33: /* Tx busy */ + return 1; + + default: /* failure */ + ++chan->ifstats.tx_errors; + } + return 0; +} + +/*============================================================================ + * Parse X.25 call request data and fill x25_call_info_t structure. + */ +static void parse_call_info (unsigned char* str, x25_call_info_t* info) +{ + memset(info, 0, sizeof(x25_call_info_t)); + for (; *str; ++str) + { + int i; + unsigned ch; + + if (*str == '-') switch (str[1]) + { + case 'd': /* destination address */ + for (i = 0; i < 16; ++i) + { + ch = str[2+i]; + if (!is_digit(ch)) break; + info->dest[i] = ch; + } + break; + + case 's': /* source address */ + for (i = 0; i < 16; ++i) + { + ch = str[2+i]; + if (!is_digit(ch)) break; + info->src[i] = ch; + } + break; + + case 'u': /* user data */ + for (i = 0; i < 127; ++i) + { + ch = str[2+2*i]; + if (!is_hex_digit(ch)) break; + info->user[i] = hex_to_uint(&str[2+2*i], 2); + } + info->nuser = i; + break; + + case 'f': /* facilities */ + for (i = 0; i < 64; ++i) + { + ch = str[2+4*i]; + if (!is_hex_digit(ch)) break; + info->facil[i].code = + hex_to_uint(&str[2+4*i], 2) + ; + ch = str[4+4*i]; + if (!is_hex_digit(ch)) break; + info->facil[i].parm = + hex_to_uint(&str[4+4*i], 2) + ; + } + info->nfacil = i; + break; + } + } +} + +/*============================================================================ + * Convert line speed in bps to a number used by S502 code. + */ +static unsigned char bps_to_speed_code (unsigned long bps) +{ + unsigned char number; + + if (bps <= 1200) number = 0x01 ; + else if (bps <= 2400) number = 0x02; + else if (bps <= 4800) number = 0x03; + else if (bps <= 9600) number = 0x04; + else if (bps <= 19200) number = 0x05; + else if (bps <= 38400) number = 0x06; + else if (bps <= 45000) number = 0x07; + else if (bps <= 56000) number = 0x08; + else if (bps <= 64000) number = 0x09; + else if (bps <= 74000) number = 0x0A; + else if (bps <= 112000) number = 0x0B; + else if (bps <= 128000) number = 0x0C; + else number = 0x0D; + + return number; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0') + ; + return val; +} + +/*============================================================================ + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. + */ +static unsigned int hex_to_uint (unsigned char* str, int len) +{ + unsigned val, ch; + + if (!len) len = strlen(str); + for (val = 0; len; ++str, --len) + { + ch = *str; + if (is_digit(ch)) + val = (val << 4) + (ch - (unsigned)'0') + ; + else if (is_hex_digit(ch)) + val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10) + ; + else break; + } + return val; +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c --- v2.1.24/linux/drivers/net/sdladrv.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sdladrv.c Sun Feb 2 15:18:41 1997 @@ -0,0 +1,1829 @@ +/***************************************************************************** +* sdladrv.c SDLA Support Module. Main module. +* +* This module is a library of common hardware-specific functions +* used by all Sangoma drivers. +* +* Author: Gene Kozin +* +* 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 /* OS configuration options */ +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* support for loadable modules */ +#include /* for jiffies, HZ, etc. */ +#include /* API definitions */ +#include /* SDLA firmware module definitions */ +#include /* 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 /* API definitions */ +#include /* SDLA firmware module definitions */ +#include /* for inb(), outb(), etc. */ +#define _INB(port) (inb(port)) +#define _OUTB(port, byte) (outb((port),(byte))) +#define SYSTEM_TICK lbolt + +#else +#error Unknown system type! +#endif + +#define MOD_VERSION 3 +#define MOD_RELEASE 0 + +#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ +#define EXEC_DELAY 20 /* shared memory access delay, mks */ +#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ + +/* I/O port address range */ +#define S502A_IORANGE 3 +#define S502E_IORANGE 4 +#define S503_IORANGE 3 +#define S507_IORANGE 4 +#define S508_IORANGE 4 + +/* Maximum amount of memory */ +#define S502_MAXMEM 0x10000L +#define S503_MAXMEM 0x10000L +#define S507_MAXMEM 0x40000L +#define S508_MAXMEM 0x40000L + +/* Minimum amount of memory */ +#define S502_MINMEM 0x8000L +#define S503_MINMEM 0x8000L +#define S507_MINMEM 0x20000L +#define S508_MINMEM 0x20000L + +/****** Function Prototypes *************************************************/ + +/* Module entry points. These are called by the OS and must be public. */ +int init_module (void); +void cleanup_module (void); + +/* Hardware-specific functions */ +static int sdla_detect (sdlahw_t* hw); +static int sdla_autodpm (sdlahw_t* hw); +static int sdla_setdpm (sdlahw_t* hw); +static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); +static int sdla_init (sdlahw_t* hw); +static unsigned long sdla_memtest (sdlahw_t* hw); +static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); +static unsigned char make_config_byte (sdlahw_t* hw); +static int sdla_start (sdlahw_t* hw, unsigned addr); + +static int init_s502a (sdlahw_t* hw); +static int init_s502e (sdlahw_t* hw); +static int init_s503 (sdlahw_t* hw); +static int init_s507 (sdlahw_t* hw); +static int init_s508 (sdlahw_t* hw); + +static int detect_s502a (int port); +static int detect_s502e (int port); +static int detect_s503 (int port); +static int detect_s507 (int port); +static int detect_s508 (int port); + +/* Miscellaneous functions */ +static int calibrate_delay (int mks); +static int get_option_index (unsigned* optlist, unsigned optval); +static unsigned check_memregion (void* ptr, unsigned len); +static unsigned test_memregion (void* ptr, unsigned len); +static unsigned short checksum (unsigned char* buf, unsigned len); + +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ + +/* private data */ +static char modname[] = "sdladrv"; +static char fullname[] = "SDLA Support Module"; +static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static unsigned exec_idle; + +/* Hardware configuration options. + * These are arrays of configuration options used by verification routines. + * The first element of each array is its size (i.e. number of options). + */ +static unsigned s502_port_options[] = + { 4, 0x250, 0x300, 0x350, 0x360 } +; +static unsigned s503_port_options[] = + { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } +; +static unsigned s508_port_options[] = + { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } +; + +static unsigned s502a_irq_options[] = { 0 }; +static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; +static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; +static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; + +static unsigned s502a_dpmbase_options[] = +{ + 28, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, + 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, +}; +static unsigned s507_dpmbase_options[] = +{ + 32, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, + 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, +}; +static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ +{ + 32, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, + 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, +}; + +/* +static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; +static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; +static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; +*/ + +static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; +static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; +static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; +static unsigned s507_pclk_options[] = { 1, 12288 }; +static unsigned s508_pclk_options[] = { 1, 16000 }; + +/* Host memory control register masks */ +static unsigned char s502a_hmcr[] = +{ + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ +}; +static unsigned char s502e_hmcr[] = +{ + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ +}; +static unsigned char s507_hmcr[] = +{ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ +}; +static unsigned char s508_hmcr[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ +}; + +static unsigned char s507_irqmask[] = +{ + 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 +}; + +/******* Kernel Loadable Module Entry Points ********************************/ + +/*============================================================================ + * Module 'insert' entry point. + * o print announcement + * o initialize static data + * o calibrate SDLA shared memory access delay. + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ + +#ifdef MODULE +int init_module (void) +#else +int wanpipe_init(void) +{ + printk(KERN_INFO "%s v%u.%u %s\n", + fullname, MOD_VERSION, MOD_RELEASE, copyright); + exec_idle = calibrate_delay(EXEC_DELAY); +#ifdef WANDEBUG + printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); +#endif + return 0; +} + +#ifdef MODULE +/*============================================================================ + * Module 'remove' entry point. + * o release all remaining system resources + */ +void cleanup_module (void) +{ +} +#endif + +/******* Kernel APIs ********************************************************/ + +/*============================================================================ + * Set up adapter. + * o detect adapter type + * o verify hardware configuration options + * o check for hardware conflicts + * o set up adapter shared memory + * o test adapter memory + * o load firmware + * Return: 0 ok. + * < 0 error + */ +int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) +{ + unsigned* irq_opt = NULL; /* IRQ options */ + unsigned* dpmbase_opt = NULL; /* DPM window base options */ + unsigned* pclk_opt = NULL; /* CPU clock rate options */ + int err; + + if (sdla_detect(hw)) + { + printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n", + modname, hw->type, hw->port) + ; + return -EINVAL; + } + printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", + modname, hw->type, hw->port) + ; + + hw->dpmsize = SDLA_WINDOWSIZE; + switch (hw->type) + { + case SDLA_S502A: + hw->io_range = S502A_IORANGE; + irq_opt = s502a_irq_options; + dpmbase_opt = s502a_dpmbase_options; + pclk_opt = s502a_pclk_options; + break; + + case SDLA_S502E: + hw->io_range = S502E_IORANGE; + irq_opt = s502e_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s502e_pclk_options; + break; + + case SDLA_S503: + hw->io_range = S503_IORANGE; + irq_opt = s503_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s503_pclk_options; + break; + + case SDLA_S507: + hw->io_range = S507_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s507_dpmbase_options; + pclk_opt = s507_pclk_options; + break; + + case SDLA_S508: + hw->io_range = S508_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s508_pclk_options; + break; + } + + /* Verify IRQ configuration options */ + if (!get_option_index(irq_opt, hw->irq)) + { + printk(KERN_ERR "%s: IRQ %d is illegal!\n", + modname, hw->irq) + ; + return -EINVAL; + } + + /* Verify CPU clock rate configuration options */ + if (hw->pclk == 0) + hw->pclk = pclk_opt[1] /* use default */ + ; + else if (!get_option_index(pclk_opt, hw->pclk)) + { + printk(KERN_ERR "%s: CPU clock %u is illegal!\n", + modname, hw->pclk) + ; + return -EINVAL; + } + printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", + modname, hw->pclk) + ; + + /* Setup adapter dual-port memory window and test memory */ + if (hw->dpmbase == 0) + { + err = sdla_autodpm(hw); + if (err) + { + printk(KERN_ERR + "%s: can't find available memory region!\n", + modname) + ; + return err; + } + } + else if (!get_option_index(dpmbase_opt, hw->dpmbase)) + { + printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", + modname, hw->dpmbase) + ; + return -EINVAL; + } + else if (sdla_setdpm(hw)) + { + printk(KERN_ERR + "%s: 8K memory region at 0x%lX is not available!\n", + modname, hw->dpmbase) + ; + return -EINVAL; + } + printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", + modname, hw->dpmbase) + ; + printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", + modname, hw->memory / 1024) + ; + + /* Load firmware. If loader fails then shut down adapter */ + err = sdla_load(hw, sfm, len); + if (err) sdla_down(hw); /* shutdown adapter */ + return err; +} + +/*============================================================================ + * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. + */ +int sdla_down (sdlahw_t* hw) +{ + unsigned port = hw->port; + int i; + + if (!port) return -EFAULT; + + switch (hw->type) + { + case SDLA_S502A: + _OUTB(port, 0x08); /* halt CPU */ + _OUTB(port, 0x08); + _OUTB(port, 0x08); + hw->regs[0] = 0x08; + _OUTB(port + 1, 0xFF); /* close memory window */ + hw->regs[1] = 0xFF; + break; + + case SDLA_S502E: + _OUTB(port + 3, 0); /* stop CPU */ + _OUTB(port, 0); /* reset board */ + for (i = 0; i < S502E_IORANGE; ++i) + hw->regs[i] = 0 + ; + break; + + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + _OUTB(port, 0); /* reset board logic */ + hw->regs[0] = 0; + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Map shared memory window into SDLA adress space. + */ +int sdla_mapmem (sdlahw_t* hw, unsigned long addr) +{ + unsigned port = hw->port; + register int tmp; + + switch (hw->type) + { + case SDLA_S502A: + case SDLA_S502E: + if (addr < S502_MAXMEM) /* verify parameter */ + { + tmp = addr >> 13; /* convert to register mask */ + _OUTB(port + 2, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S503: + if (addr < S503_MAXMEM) /* verify parameter */ + { + tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); + _OUTB(port, tmp); + hw->regs[0] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S507: + if (addr < S507_MAXMEM) + { + if (!(_INB(port) & 0x02)) + return -EIO + ; + tmp = addr >> 13; /* convert to register mask */ + _OUTB(port + 2, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S508: + if (addr < S508_MAXMEM) + { + tmp = addr >> 13; /* convert to register mask */ + _OUTB(port + 2, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + default: + return -EINVAL; + } + hw->vector = addr & 0xFFFFE000L; + return 0; +} + +/*============================================================================ + * Enable interrupt generation. + */ +int sdla_inten (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + switch (hw->type) + { + case SDLA_S502E: + /* Note thar interrupt control operations on S502E are allowed + * only if CPU is enabled (bit 0 of status register is set). + */ + if (_INB(port) & 0x01) + { + _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ + _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ + hw->regs[0] = 0x06; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] | 0x04; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (!(_INB(port) & 0x02)) /* verify */ + return -EIO + ; + break; + + case SDLA_S508: + tmp = hw->regs[0] | 0x10; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (!(_INB(port + 1) & 0x10)) /* verify */ + return -EIO + ; + break; + + case SDLA_S502A: + case SDLA_S507: + break; + + default: + return -EINVAL; + + } + return 0; +} + +/*============================================================================ + * Disable interrupt generation. + */ +int sdla_intde (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + switch (hw->type) + { + case SDLA_S502E: + /* Notes: + * 1) interrupt control operations are allowed only if CPU is + * enabled (bit 0 of status register is set). + * 2) disabling interrupts using bit 1 of control register + * causes IRQ line go high, therefore we are going to use + * 0x04 instead: lower it to inhibit interrupts to PC. + */ + if (_INB(port) & 0x01) + { + _OUTB(port, hw->regs[0] & ~0x04); + hw->regs[0] &= ~0x04; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] & ~0x04; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) & 0x02) /* verify */ + return -EIO + ; + break; + + case SDLA_S508: + tmp = hw->regs[0] & ~0x10; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) & 0x10) /* verify */ + return -EIO + ; + break; + + case SDLA_S502A: + case SDLA_S507: + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Acknowledge SDLA hardware interrupt. + */ +int sdla_intack (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp; + + switch (hw->type) + { + case SDLA_S502E: + /* To acknoledge hardware interrupt we have to toggle bit 3 of + * control register: \_/ + * Note that interrupt control operations on S502E are allowed + * only if CPU is enabled (bit 1 of status register is set). + */ + if (_INB(port) & 0x01) + { + tmp = hw->regs[0] & ~0x04; + _OUTB(port, tmp); + tmp |= 0x04; + _OUTB(port, tmp); + hw->regs[0] = tmp; + } + else return -EIO; + break; + + case SDLA_S503: + if (_INB(port) & 0x04) + { + tmp = hw->regs[0] & ~0x08; + _OUTB(port, tmp); + tmp |= 0x08; + _OUTB(port, tmp); + hw->regs[0] = tmp; + } + break; + + case SDLA_S502A: + case SDLA_S507: + case SDLA_S508: + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Generate an interrupt to adapter's CPU. + */ +int sdla_intr (sdlahw_t* hw) +{ + unsigned port = hw->port; + + switch (hw->type) + { + case SDLA_S502A: + if (!(_INB(port) & 0x40)) + { + _OUTB(port, 0x10); /* issue NMI to CPU */ + hw->regs[0] = 0x10; + } + else return -EIO; + break; + + case SDLA_S507: + if ((_INB(port) & 0x06) == 0x06) + { + _OUTB(port + 3, 0); + } + else return -EIO; + break; + + case SDLA_S508: + if (_INB(port + 1) & 0x02) + { + _OUTB(port, 0x08); + } + else return -EIO; + break; + + case SDLA_S502E: + case SDLA_S503: + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Execute Adapter Command. + * o Set exec flag. + * o Busy-wait until flag is reset. + * o Return number of loops made, or 0 if command timed out. + */ +int sdla_exec (void* opflag) +{ + volatile unsigned char* flag = opflag; + unsigned long tstop; + int nloops; + + if (*flag) return 0; /* ???? */ + + *flag = 1; + tstop = SYSTEM_TICK + EXEC_TIMEOUT; + for (nloops = 1; *flag; ++nloops) + { + unsigned delay = exec_idle; + while (--delay); /* delay */ + if (SYSTEM_TICK > tstop) return 0; /* time is up! */ + } + return nloops; +} + +/*============================================================================ + * Read absolute adapter memory. + * Transfer data from adapter's memory to data buffer. + * + * Note: + * Care should be taken when crossing dual-port memory window boundary. + * This function is not atomic, so caller must disable interrupt if + * interrupt routines are accessing adapter shared memory. + */ +int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) +{ + unsigned long oldvec = hw->vector; + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + unsigned long curvec; /* current DPM window vector */ + int err = 0; + + if (addr + len > hw->memory) /* verify arguments */ + return -EINVAL + ; + while (len && !err) + { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; + + /* Relocate window and copy block of data */ + err = sdla_mapmem(hw, curvec); + memcpy((void*)buf, (void*)(hw->dpmbase + curpos), curlen); + addr += curlen; + (char*)buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + return err; +} + +/*============================================================================ + * Write Absolute Adapter Memory. + * Transfer data from data buffer to adapter's memory. + * + * Note: + * Care should be taken when crossing dual-port memory window boundary. + * This function is not atomic, so caller must disable interrupt if + * interrupt routines are accessing adapter shared memory. + */ +int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) +{ + unsigned long oldvec = hw->vector; + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + unsigned long curvec; /* current DPM window vector */ + int err = 0; + + if (addr + len > hw->memory) /* verify arguments */ + return -EINVAL + ; + while (len && !err) + { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; + + /* Relocate window and copy block of data */ + sdla_mapmem(hw, curvec); + memcpy((void*)(hw->dpmbase + curpos), (void*)buf, curlen); + addr += curlen; + (char*)buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + return err; +} + +#ifdef DONT_COMPIPLE_THIS +#endif /* DONT_COMPIPLE_THIS */ + +/****** Hardware-Specific Functions *****************************************/ + +/*============================================================================ + * Detect adapter type. + * o if adapter type is specified then call detection routine for that adapter + * type. Otherwise call detection routines for every adapter types until + * adapter is detected. + * + * Notes: + * 1) Detection tests are destructive! Adapter will be left in shutdown state + * after the test. + */ +static int sdla_detect (sdlahw_t* hw) +{ + unsigned port = hw->port; + int err = 0; + + if (!port) + return -EFAULT + ; + switch (hw->type) + { + case SDLA_S502A: + if (!detect_s502a(port)) err = -ENODEV; + break; + + case SDLA_S502E: + if (!detect_s502e(port)) err = -ENODEV; + break; + + case SDLA_S503: + if (!detect_s503(port)) err = -ENODEV; + break; + + case SDLA_S507: + if (!detect_s507(port)) err = -ENODEV; + break; + + case SDLA_S508: + if (!detect_s508(port)) err = -ENODEV; + break; + + default: + if (detect_s502a(port)) + hw->type = SDLA_S502A + ; + else if (detect_s502e(port)) + hw->type = SDLA_S502E + ; + else if (detect_s503(port)) + hw->type = SDLA_S503 + ; + else if (detect_s507(port)) + hw->type = SDLA_S507 + ; + else if (detect_s508(port)) + hw->type = SDLA_S508 + ; + else err = -ENODEV; + } + return err; +} + +/*============================================================================ + * Autoselect memory region. + * o try all available DMP address options from the top down until success. + */ +static int sdla_autodpm (sdlahw_t* hw) +{ + int i, err = -EINVAL; + unsigned* opt; + + switch (hw->type) + { + case SDLA_S502A: + opt = s502a_dpmbase_options; + break; + + case SDLA_S502E: + case SDLA_S503: + case SDLA_S508: + opt = s508_dpmbase_options; + break; + + case SDLA_S507: + opt = s507_dpmbase_options; + break; + + default: + return -EINVAL; + } + + for (i = opt[0]; i && err; --i) + { + hw->dpmbase = opt[i]; + err = sdla_setdpm(hw); + } + return err; +} + +/*============================================================================ + * Set up adapter dual-port memory window. + * o shut down adapter + * o make sure that no physical memory exists in this region, i.e entire + * region reads 0xFF and is not writable when adapter is shut down. + * o initialize adapter hardware + * o make sure that region is usable with SDLA card, i.e. we can write to it + * when adapter is configured. + */ +static int sdla_setdpm (sdlahw_t* hw) +{ + int err; + + /* Shut down card and verify memory region */ + sdla_down(hw); + if (check_memregion((void*)hw->dpmbase, hw->dpmsize)) + return -EINVAL + ; + + /* Initialize adapter and test on-board memory segment by segment. + * If memory size appears to be less than shared memory window size, + * assume that memory region is unusable. + */ + err = sdla_init(hw); + if (err) return err; + + if (sdla_memtest(hw) < hw->dpmsize) /* less than window size */ + { + sdla_down(hw); + return -EIO; + } + sdla_mapmem(hw, 0L); /* set window vector at bottom */ + return 0; +} + +/*============================================================================ + * Load adapter from the memory image of the SDLA firmware module. + * o verify firmware integrity and compatibility + * o start adapter up + */ +static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) +{ + int i; + + /* Verify firmware signature */ + if (strcmp(sfm->signature, SFM_SIGNATURE)) + { + printk(KERN_ERR "%s: not SDLA firmware!\n", + modname) + ; + return -EINVAL; + } + + /* Verify firmware module format version */ + if (sfm->version != SFM_VERSION) + { + printk(KERN_ERR + "%s: firmware format %u rejected! Expecting %u.\n", + modname, sfm->version, SFM_VERSION) + ; + return -EINVAL; + } + + /* Verify firmware module length and checksum */ + if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || + (checksum((void*)&sfm->info, + sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) + { + printk(KERN_ERR "%s: firmware corrupted!\n", modname); + return -EINVAL; + } + + /* Announce */ + printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, + (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", + sfm->info.codeid) + ; + + /* Scan through the list of compatible adapters and make sure our + * adapter type is listed. + */ + for (i = 0; + (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); + ++i) + ; + if (i == SFM_MAX_SDLA) + { + printk(KERN_ERR "%s: firmware is not compatible with S%u!\n", + modname, hw->type) + ; + return -EINVAL; + } + + /* Make sure there is enough on-board memory */ + if (hw->memory < sfm->info.memsize) + { + printk(KERN_ERR + "%s: firmware needs %lu bytes of on-board memory!\n", + modname, sfm->info.memsize) + ; + return -EINVAL; + } + + /* Move code onto adapter */ + if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) + { + printk(KERN_ERR "%s: failed to load code segment!\n", + modname) + ; + return -EIO; + } + + /* Prepare boot-time configuration data and kick-off CPU */ + sdla_bootcfg(hw, &sfm->info); + if (sdla_start(hw, sfm->info.startoffs)) + { + printk(KERN_ERR "%s: Damn... Adapter won't start!\n", + modname) + ; + return -EIO; + } + + /* position DPM window over the mailbox and enable interrupts */ + if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) + { + printk(KERN_ERR "%s: adapter hardware failure!\n", + modname) + ; + return -EIO; + } + hw->fwid = sfm->info.codeid; /* set firmware ID */ + return 0; +} + +/*============================================================================ + * Initialize SDLA hardware: setup memory window, IRQ, etc. + */ +static int sdla_init (sdlahw_t* hw) +{ + int i; + + for (i = 0; i < SDLA_MAXIORANGE; ++i) + hw->regs[i] = 0 + ; + switch (hw->type) + { + case SDLA_S502A: return init_s502a(hw); + case SDLA_S502E: return init_s502e(hw); + case SDLA_S503: return init_s503(hw); + case SDLA_S507: return init_s507(hw); + case SDLA_S508: return init_s508(hw); + } + return -EINVAL; +} + +/*============================================================================ + * Test adapter on-board memory. + * o slide DPM window from the bottom up and test adapter memory segment by + * segment. + * Return adapter memory size. + */ +static unsigned long sdla_memtest (sdlahw_t* hw) +{ + unsigned long memsize; + unsigned winsize; + + for (memsize = 0, winsize = hw->dpmsize; + !sdla_mapmem(hw, memsize) && + (test_memregion((void*)hw->dpmbase, winsize) == winsize) + ; + memsize += winsize) + ; + hw->memory = memsize; + return memsize; +} + +/*============================================================================ + * Prepare boot-time firmware configuration data. + * o position DPM window + * o initialize configuration data area + */ +static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) +{ + unsigned char* data; + + if (!sfminfo->datasize) return 0; /* nothing to do */ + + if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) + return -EIO + ; + data = (void*)(hw->dpmbase + (sfminfo->dataoffs - hw->vector)); + memset(data, 0, sfminfo->datasize); + + data[0x00] = make_config_byte(hw); + switch (sfminfo->codeid) + { + case SFID_X25_502: + case SFID_X25_508: + data[0x01] = 3; /* T1 timer */ + data[0x03] = 10; /* N2 */ + data[0x06] = 7; /* HDLC window size */ + data[0x0B] = 1; /* DTE */ + data[0x0C] = 2; /* X.25 packet window size */ + *(short*)&data[0x0D] = 128; /* default X.25 data size */ + *(short*)&data[0x0F] = 128; /* maximum X.25 data size */ + break; + } + return 0; +} + +/*============================================================================ + * Prepare configuration byte identifying adapter type and CPU clock rate. + */ +static unsigned char make_config_byte (sdlahw_t* hw) +{ + unsigned char byte = 0; + + switch (hw->pclk) + { + case 5000: byte = 0x01; break; + case 7200: byte = 0x02; break; + case 8000: byte = 0x03; break; + case 10000: byte = 0x04; break; + case 16000: byte = 0x05; break; + } + switch (hw->type) + { + case SDLA_S502E: byte |= 0x80; break; + case SDLA_S503: byte |= 0x40; break; + } + return byte; +} + +/*============================================================================ + * Start adapter's CPU. + * o calculate a pointer to adapter's cold boot entry point + * o position DPM window + * o place boot instruction (jp addr) at cold boot entry point + * o start CPU + */ +static int sdla_start (sdlahw_t* hw, unsigned addr) +{ + unsigned port = hw->port; + unsigned char* bootp; + int err, tmp, i; + + if (!port) return -EFAULT; + + switch (hw->type) + { + case SDLA_S502A: + bootp = (void*)(hw->dpmbase + 0x66); + break; + + case SDLA_S502E: + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + bootp = (void*)hw->dpmbase; + break; + + default: + return -EINVAL; + } + + err = sdla_mapmem(hw, 0); + if (err) return err; + + *bootp = 0xC3; /* Z80: 'jp' opcode */ + bootp++; + *((unsigned short*)(bootp)) = addr; + + switch (hw->type) + { + case SDLA_S502A: + _OUTB(port, 0x10); /* issue NMI to CPU */ + hw->regs[0] = 0x10; + break; + + case SDLA_S502E: + _OUTB(port + 3, 0x01); /* start CPU */ + hw->regs[3] = 0x01; + for (i = 0; i < SDLA_IODELAY; ++i); + if (_INB(port) & 0x01) /* verify */ + { + /* + * Enabling CPU changes functionality of the + * control register, so we have to reset its + * mirror. + */ + _OUTB(port, 0); /* disable interrupts */ + hw->regs[0] = 0; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + if (!(_INB(port) & 0x01)) /* verify */ + return -EIO + ; + break; + + case SDLA_S507: + tmp = hw->regs[0] | 0x02; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + if (!(_INB(port) & 0x04)) /* verify */ + return -EIO + ; + break; + + case SDLA_S508: + tmp = hw->regs[0] | 0x02; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + if (!(_INB(port + 1) & 0x02)) /* verify */ + return -EIO + ; + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Initialize S502A adapter. + */ +static int init_s502a (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s502a(port)) + return -ENODEV + ; + hw->regs[0] = 0x08; + hw->regs[1] = 0xFF; + + /* Verify configuration options */ + i = get_option_index(s502a_dpmbase_options, hw->dpmbase); + if (i == 0) + return -EINVAL + ; + + tmp = s502a_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window (this also enables memory access) */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + hw->regs[0] = 0x08; + return 0; +} + +/*============================================================================ + * Initialize S502E adapter. + */ +static int init_s502e (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s502e(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s508_dpmbase_options, hw->dpmbase); + if (i == 0) + return -EINVAL + ; + + tmp = s502e_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + _OUTB(port, 0x02); + hw->regs[0] = 0x02; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + return (_INB(port) & 0x02) ? 0 : -EIO; +} + +/*============================================================================ + * Initialize S503 adapter. + * --------------------------------------------------------------------------- + */ +static int init_s503 (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s503(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s508_dpmbase_options, hw->dpmbase); + if (i == 0) + return -EINVAL + ; + + tmp = s502e_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + _OUTB(port, 0x02); + hw->regs[0] = 0x02; /* update mirror */ + return 0; +} + +/*============================================================================ + * Initialize S507 adapter. + */ +static int init_s507 (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s507(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s507_dpmbase_options, hw->dpmbase); + if (i == 0) + return -EINVAL + ; + + tmp = s507_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Enable adapter's logic */ + _OUTB(port, 0x01); + hw->regs[0] = 0x01; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (!(_INB(port) & 0x20)) + return -EIO + ; + + /* Setup dual-port memory window */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + tmp = hw->regs[0] | 0x04; + if (hw->irq) + { + i = get_option_index(s508_irq_options, hw->irq); + if (i) tmp |= s507_irqmask[i - 1]; + } + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + return (_INB(port) & 0x08) ? 0 : -EIO; +} + +/*============================================================================ + * Initialize S508 adapter. + */ +static int init_s508 (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s508(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s508_dpmbase_options, hw->dpmbase); + if (i == 0) + return -EINVAL + ; + + /* Setup memory configuration */ + tmp = s508_hmcr[i - 1]; + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + _OUTB(port, 0x04); + hw->regs[0] = 0x04; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + return (_INB(port + 1) & 0x04) ? 0 : -EIO; +} + +/*============================================================================ + * Detect S502A adapter. + * Following tests are used to detect S502A adapter: + * 1. All registers other than status (BASE) should read 0xFF + * 2. After writing 00001000b to control register, status register should + * read 01000000b. + * 3. After writing 0 to control register, status register should still + * read 01000000b. + * 4. After writing 00000100b to control register, status register should + * read 01000100b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s502a (int port) +{ + int i, j; + + if (!get_option_index(s502_port_options, port)) + return 0 + ; + for (j = 1; j < SDLA_MAXIORANGE; ++j) + { + if (_INB(port + j) != 0xFF) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port, 0x08); /* halt CPU */ + _OUTB(port, 0x08); + _OUTB(port, 0x08); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0x40) + return 0 + ; + _OUTB(port, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0x40) + return 0 + ; + _OUTB(port, 0x04); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0x44) + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0x08); + _OUTB(port, 0x08); + _OUTB(port, 0x08); + _OUTB(port + 1, 0xFF); + return 1; +} + +/*============================================================================ + * Detect S502E adapter. + * Following tests are used to verify adapter presence: + * 1. All registers other than status (BASE) should read 0xFF. + * 2. After writing 0 to CPU control register (BASE+3), status register + * (BASE) should read 11111000b. + * 3. After writing 00000100b to port BASE (set bit 2), status register + * (BASE) should read 11111100b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s502e (int port) +{ + int i, j; + + if (!get_option_index(s502_port_options, port)) + return 0 + ; + for (j = 1; j < SDLA_MAXIORANGE; ++j) + { + if (_INB(port + j) != 0xFF) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port + 3, 0); /* CPU control reg. */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xF8) /* read status */ + return 0 + ; + _OUTB(port, 0x04); /* set bit 2 */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xFC) /* verify */ + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0); + return 1; +} + +/*============================================================================ + * Detect s503 adapter. + * Following tests are used to verify adapter presence: + * 1. All registers other than status (BASE) should read 0xFF. + * 2. After writing 0 to control register (BASE), status register (BASE) + * should read 11110000b. + * 3. After writing 00000100b (set bit 2) to control register (BASE), + * status register should read 11110010b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s503 (int port) +{ + int i, j; + + if (!get_option_index(s503_port_options, port)) + return 0 + ; + for (j = 1; j < SDLA_MAXIORANGE; ++j) + { + if (_INB(port + j) != 0xFF) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port, 0); /* reset control reg.*/ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xF0) /* read status */ + return 0 + ; + _OUTB(port, 0x04); /* set bit 2 */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xF2) /* verify */ + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0); + return 1; +} + +/*============================================================================ + * Detect s507 adapter. + * Following tests are used to detect s507 adapter: + * 1. All ports should read the same value. + * 2. After writing 0x00 to control register, status register should read + * ?011000?b. + * 3. After writing 0x01 to control register, status register should read + * ?011001?b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s507 (int port) +{ + int tmp, i, j; + + if (!get_option_index(s508_port_options, port)) + return 0 + ; + tmp = _INB(port); + for (j = 1; j < S507_IORANGE; ++j) + { + if (_INB(port + j) != tmp) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port) & 0x7E) != 0x30) + return 0 + ; + _OUTB(port, 0x01); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port) & 0x7E) != 0x32) + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0x00); + return 1; +} + +/*============================================================================ + * Detect s508 adapter. + * Following tests are used to detect s508 adapter: + * 1. After writing 0x00 to control register, status register should read + * ??000000b. + * 2. After writing 0x10 to control register, status register should read + * ??010000b + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s508 (int port) +{ + int i; + + if (!get_option_index(s508_port_options, port)) + return 0 + ; + _OUTB(port, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port + 1) & 0x3F) != 0x00) + return 0 + ; + _OUTB(port, 0x10); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port + 1) & 0x3F) != 0x10) + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0x00); + return 1; +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Calibrate SDLA memory access delay. + * Count number of idle loops made within 1 second and then calculate the + * number of loops that should be made to achive desired delay. + */ +static int calibrate_delay (int mks) +{ + unsigned int delay; + unsigned long stop; + + for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); + return (delay/(1000000L/mks) + 1); +} + +/*============================================================================ + * Get option's index into the options list. + * Return option's index (1 .. N) or zero if option is invalid. + */ +static int get_option_index (unsigned* optlist, unsigned optval) +{ + int i; + + for (i = 1; i <= optlist[0]; ++i) + if (optlist[i] == optval) return i + ; + return 0; +} + +/*============================================================================ + * Check memory region to see if it's available. + * Return: 0 ok. + */ +static unsigned check_memregion (void* ptr, unsigned len) +{ + volatile unsigned char* p = ptr; + + for (; len && (*p == 0xFF); --len, ++p) + { + *p = 0; /* attempt to write 0 */ + if (*p != 0xFF) /* still has to read 0xFF */ + { + *p = 0xFF; /* restore original value */ + break; /* not good */ + } + } + return len; +} + +/*============================================================================ + * Test memory region. + * Return: size of the region that passed the test. + * Note: Region size must be multiple of 2 ! + */ +static unsigned test_memregion (void* ptr, unsigned len) +{ + volatile unsigned short* w_ptr; + unsigned len_w = len >> 1; /* region len in words */ + unsigned i; + + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + *w_ptr = 0xAA55 + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + if (*w_ptr != 0xAA55) + { + len_w = i; + break; + } + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + *w_ptr = 0x55AA + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + if (*w_ptr != 0x55AA) + { + len_w = i; + break; + } + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0; + return len_w << 1; +} + +/*============================================================================ + * Calculate 16-bit CRC using CCITT polynomial. + */ +static unsigned short checksum (unsigned char* buf, unsigned len) +{ + unsigned short crc = 0; + unsigned mask, flag; + + for (; len; --len, ++buf) + { + for (mask = 0x80; mask; mask >>= 1) + { + flag = (crc & 0x8000); + crc <<= 1; + crc |= ((*buf & mask) ? 1 : 0); + if (flag) crc ^= 0x1021; + } + } + return crc; +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.1.24/linux/drivers/net/sdlamain.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sdlamain.c Sun Feb 2 15:18:41 1997 @@ -0,0 +1,587 @@ +/***************************************************************************** +* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. +* +* Author: Gene Kozin +* +* 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 /* OS configuration options */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* printk(), and other useful stuff */ +#include /* support for loadable modules */ +#include /* request_region(), release_region() */ +#include /* for kernel task queues */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* 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 *****************************************************************/ diff -u --recursive --new-file v2.1.24/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.1.24/linux/drivers/net/seeq8005.c Wed Oct 9 08:55:20 1996 +++ linux/drivers/net/seeq8005.c Sun Feb 2 15:18:41 1997 @@ -64,7 +64,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_driver_stats stats; unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */ long open_time; /* Useless example local info. */ }; @@ -84,7 +84,7 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void seeq8005_rx(struct device *dev); static int seeq8005_close(struct device *dev); -static struct enet_statistics *seeq8005_get_stats(struct device *dev); +static struct net_driver_stats *seeq8005_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); /* Example routines you must write ;->. */ @@ -593,8 +593,7 @@ /* 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.1.24/linux/drivers/net/shaper.c Thu Jan 2 15:55:19 1997 +++ linux/drivers/net/shaper.c Sun Feb 2 15:18:41 1997 @@ -416,7 +416,7 @@ 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; } diff -u --recursive --new-file v2.1.24/linux/drivers/net/shaper.h linux/drivers/net/shaper.h --- v2.1.24/linux/drivers/net/shaper.h Thu Dec 12 19:37:06 1996 +++ linux/drivers/net/shaper.h Sun Feb 2 15:18:42 1997 @@ -36,7 +36,7 @@ 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; }; diff -u --recursive --new-file v2.1.24/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.1.24/linux/drivers/net/sk_g16.c Wed Oct 9 08:55:20 1996 +++ linux/drivers/net/sk_g16.c Sun Feb 2 15:18:42 1997 @@ -457,7 +457,7 @@ int tmdlast; /* last sent descriptor used for error handling, etc */ void *rmdbufs[RMDNUM]; /* pointer to the receive buffers */ void *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */ - struct enet_statistics stats; /* Device driver statistics */ + struct net_driver_stats stats; /* Device driver statistics */ }; /* global variable declaration */ @@ -491,7 +491,7 @@ static void SK_txintr(struct device *dev); static int SK_close(struct device *dev); -static struct enet_statistics *SK_get_stats(struct device *dev); +static struct net_driver_stats *SK_get_stats(struct device *dev); unsigned int SK_rom_addr(void); @@ -1681,14 +1681,14 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v2.1.24/linux/drivers/net/skeleton.c Wed Oct 9 08:55:20 1996 +++ linux/drivers/net/skeleton.c Sun Feb 2 15:18:42 1997 @@ -84,7 +84,7 @@ /* Information that need to be kept for each board. */ struct net_local { - struct enet_statistics stats; + struct net_device_stats stats; long open_time; /* Useless example local info. */ }; @@ -97,19 +97,19 @@ extern int netcard_probe(struct device *dev); -static int netcard_probe1(struct device *dev, int ioaddr); -static int net_open(struct device *dev); +static int netcard_probe1(struct device *dev, int ioaddr); +static int net_open(struct device *dev); static int net_send_packet(struct sk_buff *skb, struct device *dev); -static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void net_rx(struct device *dev); -static int net_close(struct device *dev); -static struct enet_statistics *net_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev); +static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void net_rx(struct device *dev); +static int net_close(struct device *dev); +static struct net_device_stats *net_get_stats(struct device *dev); +static void set_multicast_list(struct device *dev); /* Example routines you must write ;->. */ #define tx_done(dev) 1 extern void hardware_send_packet(short ioaddr, char *buf, int length); -extern void chipset_init(struct device *dev, int startp); +extern void chipset_init(struct device *dev, int startp); /* * Check for a network adaptor of this type, and return '0' iff one exists. @@ -286,8 +286,8 @@ dev->open = net_open; dev->stop = net_close; - dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; dev->set_multicast_list = &set_multicast_list; /* Fill in the fields of the device structure with ethernet values. */ @@ -340,8 +340,7 @@ return 0; } -static int -net_send_packet(struct sk_buff *skb, struct device *dev) +static int net_send_packet(struct sk_buff *skb, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; @@ -361,15 +360,7 @@ dev->tbusy=0; dev->trans_start = jiffies; } - /* - * If some higher layer thinks we've missed an tx-done interrupt - * we are passed NULL. Caution: dev_tint() handles the cli()/sti() - * itself. - */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } + /* * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. @@ -379,7 +370,7 @@ else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; - + lp->stats.tx_bytes+=skb->len; hardware_send_packet(ioaddr, buf, length); dev->trans_start = jiffies; } @@ -396,8 +387,7 @@ * The typical workload of the driver: * Handle the network interface interrupts. */ -static void -net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; @@ -458,6 +448,8 @@ /* Malloc up new buffer. */ struct sk_buff *skb; + lp->stats.rx_bytes+=pkt_len; + skb = dev_alloc_skb(pkt_len); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", @@ -522,8 +514,7 @@ * 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.1.24/linux/drivers/net/slip.c Tue Jan 28 18:50:02 1997 +++ linux/drivers/net/slip.c Sun Feb 2 15:18:42 1997 @@ -372,6 +372,8 @@ } #endif /* SL_INCLUDE_CSLIP */ + sl->rx_bytes+=count; + skb = dev_alloc_skb(count); if (skb == NULL) { printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); @@ -508,8 +510,10 @@ } /* We were not busy, so we are now... :-) */ - if (skb != NULL) { + if (skb != NULL) + { sl_lock(sl); + sl->tx_bytes+=skb->len; sl_encaps(sl, skb->data, skb->len); dev_kfree_skb(skb, FREE_WRITE); } @@ -625,8 +629,7 @@ return 0; } -static int -slip_receive_room(struct tty_struct *tty) +static int slip_receive_room(struct tty_struct *tty) { return 65536; /* We can handle an infinite amount of data. :-) */ } @@ -637,8 +640,8 @@ * a block of SLIP data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ -static void -slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) + +static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct slip *sl = (struct slip *) tty->disc_data; @@ -752,19 +755,21 @@ } -static struct enet_statistics * +static struct net_device_stats * sl_get_stats(struct device *dev) { - static struct enet_statistics stats; + static struct net_device_stats stats; struct slip *sl = (struct slip*)(dev->priv); #ifdef SL_INCLUDE_CSLIP struct slcompress *comp; #endif - memset(&stats, 0, sizeof(struct enet_statistics)); + memset(&stats, 0, sizeof(struct net_device_stats)); stats.rx_packets = sl->rx_packets; stats.tx_packets = sl->tx_packets; + stats.rx_bytes = sl->rx_bytes; + stats.tx_bytes = sl->tx_bytes; stats.rx_dropped = sl->rx_dropped; stats.tx_dropped = sl->tx_dropped; stats.tx_errors = sl->tx_errors; @@ -828,8 +833,7 @@ 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) { diff -u --recursive --new-file v2.1.24/linux/drivers/net/slip.h linux/drivers/net/slip.h --- v2.1.24/linux/drivers/net/slip.h Wed Dec 18 15:58:47 1996 +++ linux/drivers/net/slip.h Sun Feb 2 15:18:42 1997 @@ -68,6 +68,8 @@ /* 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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.1.24/linux/drivers/net/smc9194.c Tue Dec 31 21:41:06 1996 +++ linux/drivers/net/smc9194.c Sun Feb 2 15:18:42 1997 @@ -175,7 +175,7 @@ can find out semi-useless statistics of how well the card is performing */ - struct enet_statistics stats; + struct net_driver_stats stats; /* If I have to wait until memory is available to send @@ -234,7 +234,7 @@ . This routine allows the proc file system to query the driver's . statistics. */ -static struct enet_statistics * smc_query_statistics( struct device *dev); +static struct net_driver_stats * smc_query_statistics( struct device *dev); /* . Finally, a call to set promiscuous mode ( for TCPDUMP and related @@ -1643,7 +1643,7 @@ . 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.1.24/linux/drivers/net/strip.c Tue Jan 28 18:50:02 1997 +++ linux/drivers/net/strip.c Sun Feb 2 15:18:42 1997 @@ -1,5 +1,3 @@ -#error "Doesn't run with 2.1.x" - /* * Copyright 1996 The Board of Trustees of The Leland Stanford * Junior University. All Rights Reserved. @@ -1623,20 +1621,12 @@ */ if (haddr.c[0] == 0xFF) { - /*IPaddr a; - a.l = strip_info->dev.pa_brdaddr; - printk(KERN_INFO "%s: Broadcast packet! Sending to %d.%d.%d.%d\n", - strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);*/ - - if (!arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev)) - { - /*IPaddr a; - a.l = strip_info->dev.pa_brdaddr; - printk(KERN_INFO "%s: No ARP cache entry for %d.%d.%d.%d\n", - strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]); - strip_info->tx_dropped++;*/ - return(NULL); - } + memcpy(haddr.c, dev->broadcast, sizeof(haddr)); + if (haddr.c[0] == 0xFF) + { + strip_info->tx_dropped++; + return(NULL); + } } *ptr++ = '*'; @@ -2294,12 +2284,12 @@ return -1; /* You cannot override a Metricom radio's address */ } -static struct enet_statistics *strip_get_stats(struct device *dev) +static struct net_device_stats *strip_get_stats(struct device *dev) { - static struct enet_statistics stats; + static struct net_device_stats stats; struct strip *strip_info = (struct strip *)(dev->priv); - memset(&stats, 0, sizeof(struct enet_statistics)); + memset(&stats, 0, sizeof(struct net_device_stats)); stats.rx_packets = strip_info->rx_packets; stats.tx_packets = strip_info->tx_packets; @@ -2355,12 +2345,6 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.24/linux/drivers/net/sunhme.c Wed Dec 18 15:58:47 1996 +++ linux/drivers/net/sunhme.c Sun Feb 2 15:18:42 1997 @@ -573,7 +573,7 @@ static void happy_meal_get_counters(struct happy_meal *hp, struct hmeal_bigmacregs *bregs) { - struct enet_statistics *stats = &hp->enet_stats; + struct net_device_stats *stats = &hp->net_stats; stats->rx_crc_errors += bregs->rcrce_ctr; bregs->rcrce_ctr = 0; @@ -1501,9 +1501,11 @@ break; skb = hp->tx_skbs[elem]; hp->tx_skbs[elem] = NULL; + hp->net_stats.tx_bytes+=skb->len; + dev_kfree_skb(skb, FREE_WRITE); - hp->enet_stats.tx_packets++; + hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; @@ -1525,7 +1527,7 @@ if(this->tx_flags & TXFLAG_OWN) break; - hp->enet_stats.tx_packets++; + hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; @@ -1562,17 +1564,17 @@ /* Check for errors. */ if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { RXD(("ERR(%08lx)]", flags)); - hp->enet_stats.rx_errors++; + hp->net_stats.rx_errors++; if(len < ETH_ZLEN) - hp->enet_stats.rx_length_errors++; + hp->net_stats.rx_length_errors++; if(len & (RXFLAG_OVERFLOW >> 16)) { - hp->enet_stats.rx_over_errors++; - hp->enet_stats.rx_fifo_errors++; + hp->net_stats.rx_over_errors++; + hp->net_stats.rx_fifo_errors++; } /* Return it to the Happy meal. */ drop_it: - hp->enet_stats.rx_dropped++; + hp->net_stats.rx_dropped++; this->rx_addr = (unsigned int) hp->rx_skbs[elem]->data; this->rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); @@ -1630,7 +1632,7 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - hp->enet_stats.rx_packets++; + hp->net_stats.rx_packets++; next: elem = NEXT_RX(elem); this = &rxbase[elem]; @@ -1662,20 +1664,20 @@ /* Check for errors. */ if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { RXD(("ERR(%08lx)]", flags)); - hp->enet_stats.rx_errors++; + hp->net_stats.rx_errors++; if(len < ETH_ZLEN) - hp->enet_stats.rx_length_errors++; + hp->net_stats.rx_length_errors++; if(len & (RXFLAG_OVERFLOW >> 16)) { - hp->enet_stats.rx_over_errors++; - hp->enet_stats.rx_fifo_errors++; + hp->net_stats.rx_over_errors++; + hp->net_stats.rx_fifo_errors++; } - hp->enet_stats.rx_dropped++; + hp->net_stats.rx_dropped++; } else { skb = dev_alloc_skb(len + 2); if(skb == 0) { drops++; - hp->enet_stats.rx_dropped++; + hp->net_stats.rx_dropped++; } else { RXD(("len=%d]", len)); skb->dev = hp->dev; @@ -1684,7 +1686,7 @@ eth_copy_and_sum(skb, (thisbuf+2), len, 0); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - hp->enet_stats.rx_packets++; + hp->net_stats.rx_packets++; } } /* Return the buffer to the Happy Meal. */ @@ -1846,7 +1848,7 @@ return 1; } else { printk ("%s: transmit timed out, resetting\n", dev->name); - hp->enet_stats.tx_errors++; + hp->net_stats.tx_errors++; happy_meal_init(hp, 0); dev->tbusy = 0; dev->trans_start = jiffies; @@ -1854,12 +1856,6 @@ } } - if(skb == NULL || skb->len <= 0) { - printk("%s: skb is NULL\n", dev->name); - dev_tint(dev); - return 0; - } - if(set_bit(0, (void *) &dev->tbusy) != 0) { printk("happy meal: Transmitter access conflict.\n"); return 1; @@ -1902,7 +1898,7 @@ return 1; } else { printk ("%s: transmit timed out, resetting\n", dev->name); - hp->enet_stats.tx_errors++; + hp->net_stats.tx_errors++; happy_meal_init(hp, 0); dev->tbusy = 0; dev->trans_start = jiffies; @@ -1948,12 +1944,12 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.1.24/linux/drivers/net/sunhme.h Tue Jan 28 18:50:02 1997 +++ linux/drivers/net/sunhme.h Sun Feb 2 15:18:42 1997 @@ -540,7 +540,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.1.24/linux/drivers/net/sunlance.c Tue Jan 28 18:50:06 1997 +++ linux/drivers/net/sunlance.c Sun Feb 2 15:18:42 1997 @@ -220,7 +220,7 @@ int rx_new, tx_new; int rx_old, tx_old; - struct enet_statistics stats; + struct net_device_stats stats; struct Linux_SBus_DMA *ledma; /* If set this points to ledma */ /* and arch = sun4m */ @@ -786,17 +786,6 @@ return status; } - if (skb == NULL) { - dev_tint (dev); - printk ("skb is NULL\n"); - return 0; - } - - if (skb->len <= 0) { - printk ("skb len is %d\n", skb->len); - return 0; - } - /* Block a timer-based transmit from overlapping. */ if (set_bit (0, (void *) &dev->tbusy) != 0) { printk ("Transmitter access conflict.\n"); @@ -813,6 +802,9 @@ } len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; + + lp->stats.tx_bytes+=len; + entry = lp->tx_new & TX_RING_MOD_MASK; ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; @@ -820,6 +812,7 @@ memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); /* Clear the slack of the packet, do I need this? */ + /* For a firewall its a good idea - AC */ if (len != skblen) memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); @@ -845,7 +838,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.1.24/linux/drivers/net/sunqe.c Wed Dec 18 15:58:48 1996 +++ linux/drivers/net/sunqe.c Sun Feb 2 15:18:42 1997 @@ -281,31 +281,31 @@ if(qe_status & CREG_STAT_EDEFER) { printk("%s: Excessive transmit defers.\n", dev->name); - qep->enet_stats.tx_errors++; + qep->net_stats.tx_errors++; } if(qe_status & CREG_STAT_CLOSS) { printk("%s: Carrier lost, link down?\n", dev->name); - qep->enet_stats.tx_errors++; - qep->enet_stats.tx_carrier_errors++; + qep->net_stats.tx_errors++; + qep->net_stats.tx_carrier_errors++; } if(qe_status & CREG_STAT_ERETRIES) { printk("%s: Excessive transmit retries (more than 16).\n", dev->name); - qep->enet_stats.tx_errors++; + qep->net_stats.tx_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_LCOLL) { printk("%s: Late transmit collision.\n", dev->name); - qep->enet_stats.tx_errors++; - qep->enet_stats.collisions++; + qep->net_stats.tx_errors++; + qep->net_stats.collisions++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_FUFLOW) { printk("%s: Transmit fifo underflow, driver bug.\n", dev->name); - qep->enet_stats.tx_errors++; + qep->net_stats.tx_errors++; mace_hwbug_workaround = 1; } @@ -318,104 +318,104 @@ } if(qe_status & CREG_STAT_CCOFLOW) { - qep->enet_stats.tx_errors += 256; - qep->enet_stats.collisions += 256; + qep->net_stats.tx_errors += 256; + qep->net_stats.collisions += 256; } if(qe_status & CREG_STAT_TXDERROR) { printk("%s: Transmit descriptor is bogus, driver bug.\n", dev->name); - qep->enet_stats.tx_errors++; - qep->enet_stats.tx_aborted_errors++; + qep->net_stats.tx_errors++; + qep->net_stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_TXLERR) { printk("%s: Transmit late error.\n", dev->name); - qep->enet_stats.tx_errors++; + qep->net_stats.tx_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_TXPERR) { printk("%s: Transmit DMA parity error.\n", dev->name); - qep->enet_stats.tx_errors++; - qep->enet_stats.tx_aborted_errors++; + qep->net_stats.tx_errors++; + qep->net_stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_TXSERR) { printk("%s: Transmit DMA sbus error ack.\n", dev->name); - qep->enet_stats.tx_errors++; - qep->enet_stats.tx_aborted_errors++; + qep->net_stats.tx_errors++; + qep->net_stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_RCCOFLOW) { - qep->enet_stats.rx_errors += 256; - qep->enet_stats.collisions += 256; + qep->net_stats.rx_errors += 256; + qep->net_stats.collisions += 256; } if(qe_status & CREG_STAT_RUOFLOW) { - qep->enet_stats.rx_errors += 256; - qep->enet_stats.rx_over_errors += 256; + qep->net_stats.rx_errors += 256; + qep->net_stats.rx_over_errors += 256; } if(qe_status & CREG_STAT_MCOFLOW) { - qep->enet_stats.rx_errors += 256; - qep->enet_stats.rx_missed_errors += 256; + qep->net_stats.rx_errors += 256; + qep->net_stats.rx_missed_errors += 256; } if(qe_status & CREG_STAT_RXFOFLOW) { printk("%s: Receive fifo overflow.\n", dev->name); - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_over_errors++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_over_errors++; } if(qe_status & CREG_STAT_RLCOLL) { printk("%s: Late receive collision.\n", dev->name); - qep->enet_stats.rx_errors++; - qep->enet_stats.collisions++; + qep->net_stats.rx_errors++; + qep->net_stats.collisions++; } if(qe_status & CREG_STAT_FCOFLOW) { - qep->enet_stats.rx_errors += 256; - qep->enet_stats.rx_frame_errors += 256; + qep->net_stats.rx_errors += 256; + qep->net_stats.rx_frame_errors += 256; } if(qe_status & CREG_STAT_CECOFLOW) { - qep->enet_stats.rx_errors += 256; - qep->enet_stats.rx_crc_errors += 256; + qep->net_stats.rx_errors += 256; + qep->net_stats.rx_crc_errors += 256; } if(qe_status & CREG_STAT_RXDROP) { printk("%s: Receive packet dropped.\n", dev->name); - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_dropped++; - qep->enet_stats.rx_missed_errors++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_dropped++; + qep->net_stats.rx_missed_errors++; } if(qe_status & CREG_STAT_RXSMALL) { printk("%s: Receive buffer too small, driver bug.\n", dev->name); - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_length_errors++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_length_errors++; } if(qe_status & CREG_STAT_RXLERR) { printk("%s: Receive late error.\n", dev->name); - qep->enet_stats.rx_errors++; + qep->net_stats.rx_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_RXPERR) { printk("%s: Receive DMA parity error.\n", dev->name); - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_missed_errors++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_missed_errors++; mace_hwbug_workaround = 1; } if(qe_status & CREG_STAT_RXSERR) { printk("%s: Receive DMA sbus error ack.\n", dev->name); - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_missed_errors++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_missed_errors++; mace_hwbug_workaround = 1; } @@ -439,9 +439,10 @@ break; skb = qep->tx_skbs[elem]; qep->tx_skbs[elem] = NULL; + qep->net_stats.tx_bytes+=skb->len; dev_kfree_skb(skb, FREE_WRITE); - qep->enet_stats.tx_packets++; + qep->net_stats.tx_packets++; elem = NEXT_TX(elem); } qep->tx_old = elem; @@ -457,7 +458,7 @@ this = &txbase[elem]; if(this->tx_flags & TXD_OWN) break; - qep->enet_stats.tx_packets++; + qep->net_stats.tx_packets++; elem = NEXT_TX(elem); } qep->tx_old = elem; @@ -480,12 +481,12 @@ /* Check for errors. */ if(len < ETH_ZLEN) { - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_length_errors++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_length_errors++; drop_it: /* Return it to the QE. */ - qep->enet_stats.rx_dropped++; + qep->net_stats.rx_dropped++; this->rx_addr = (unsigned int) qep->rx_skbs[elem]->data; this->rx_flags = (RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH)); @@ -536,7 +537,7 @@ /* No checksums are done by this card ;-( */ skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); - qep->enet_stats.rx_packets++; + qep->net_stats.rx_packets++; next: elem = NEXT_RX(elem); this = &rxbase[elem]; @@ -565,14 +566,14 @@ /* Check for errors. */ if(len < ETH_ZLEN) { - qep->enet_stats.rx_errors++; - qep->enet_stats.rx_length_errors++; - qep->enet_stats.rx_dropped++; + qep->net_stats.rx_errors++; + qep->net_stats.rx_length_errors++; + qep->net_stats.rx_dropped++; } else { skb = dev_alloc_skb(len + 2); if(skb == 0) { drops++; - qep->enet_stats.rx_dropped++; + qep->net_stats.rx_dropped++; } else { skb->dev = qep->dev; skb_reserve(skb, 2); @@ -581,7 +582,7 @@ len, 0); skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); - qep->enet_stats.rx_packets++; + qep->net_stats.rx_packets++; } } end_rxd->rx_addr = (unsigned int) this_qbuf; @@ -710,12 +711,6 @@ if(dev->tbusy) return 1; - if(skb == NULL || skb->len <= 0) { - printk("%s: skb is NULL\n", dev->name); - dev_tint(dev); - return 0; - } - if(set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; @@ -756,12 +751,6 @@ if(dev->tbusy) return 1; - if(skb == NULL || skb->len <= 0) { - printk("%s: skb is NULL\n", dev->name); - dev_tint(dev); - return 0; - } - if(set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; @@ -788,6 +777,8 @@ /* Get it going. */ qep->qcregs->ctrl = CREG_CTRL_TWAKEUP; + qep->stats.tx_bytes+=skb->len; + dev_kfree_skb(skb, FREE_WRITE); if(SUN4C_TX_BUFFS_AVAIL(qep)) @@ -796,11 +787,11 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h --- v2.1.24/linux/drivers/net/sunqe.h Wed Dec 18 15:58:48 1996 +++ linux/drivers/net/sunqe.h Sun Feb 2 15:18:42 1997 @@ -360,7 +360,7 @@ 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? */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.24/linux/drivers/net/tulip.c Sun Dec 22 16:37:36 1996 +++ linux/drivers/net/tulip.c Sun Feb 2 15:18:42 1997 @@ -15,6 +15,9 @@ Subscribe to linux-tulip@cesdis.gsfc.nasa.gov and linux-tulip-bugs@cesdis.gsfc.nasa.gov for late breaking news and exciting develovements. + + This has Baldur Norddahl's one liner fix for the AC/AE boards. If it + stops working please change TINTR_ENABLE to 0xFFFFFFFF */ static char *version = @@ -240,7 +243,7 @@ #define TCMOD_AUTO (TCMOD_SW100TP|TCMOD_TH128|TCMOD_10TP) /* description of CSR7 interrupt mask register */ -#define TINTR_ENABLE 0xFFFFFFFF +#define TINTR_ENABLE 0xFFFFBBFF #define TINTR_DISABLE 0x00000000 /* description of CSR11 G.P. timer (21041/21140) register */ @@ -334,7 +337,7 @@ struct sk_buff* tx_skbuff[TX_RING_SIZE]; char rx_buffs[RX_RING_SIZE][PKT_BUF_SZ]; /* temporary Rx buffers. */ - struct enet_statistics stats; + struct net_device_stats stats; int setup_frame[48]; /* Pseudo-Tx frame to init address table. */ void (*port_select)(struct device *dev); int (*port_fail)(struct device *dev); @@ -371,7 +374,7 @@ static int tulip_rx(struct device *dev); static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int tulip_close(struct device *dev); -static struct enet_statistics *tulip_get_stats(struct device *dev); +static struct net_device_stats *tulip_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); #define generic21140_fail NULL @@ -881,6 +884,7 @@ } else { daddr = virt_to_bus(skb->data); len = skb->len; + tp->stats.tx_bytes+=len; } tp->tx_skbuff[entry] = skb; tp->tx_ring[entry].length = len | @@ -1120,8 +1124,7 @@ 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;*/ diff -u --recursive --new-file v2.1.24/linux/drivers/net/tunnel.c linux/drivers/net/tunnel.c --- v2.1.24/linux/drivers/net/tunnel.c Thu Jan 23 21:06:49 1997 +++ linux/drivers/net/tunnel.c Sun Feb 2 15:18:42 1997 @@ -120,13 +120,13 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev) { - struct enet_statistics *stats; /* This device's statistics */ + struct net_device_stats *stats; /* This device's statistics */ struct rtable *rt; /* Route to the other host */ struct device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ - stats = (struct enet_statistics *)dev->priv; + stats = (struct net_device_stats *)dev->priv; /* * First things first. Look up the destination address in the @@ -194,6 +194,8 @@ iph->id = htons(ip_id_count++); /* Race condition here? */ ip_send_check(iph); + stats->tx_bytes+=skb->len; + ip_send(skb); /* Record statistics and return */ @@ -201,9 +203,9 @@ return 0; } -static struct enet_statistics *tunnel_get_stats(struct device *dev) +static struct net_device_stats *tunnel_get_stats(struct device *dev) { - return((struct enet_statistics*) dev->priv); + return((struct net_device_stats*) dev->priv); } /* @@ -226,10 +228,10 @@ dev->stop = tunnel_close; dev->hard_start_xmit = tunnel_xmit; dev->get_stats = tunnel_get_stats; - dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct enet_statistics)); + memset(dev->priv, 0, sizeof(struct net_device_stats)); /* Initialize the tunnel device structure */ @@ -302,7 +304,7 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.1.24/linux/drivers/net/wavelan.p.h Sun Dec 22 16:37:36 1996 +++ linux/drivers/net/wavelan.p.h Sun Feb 2 15:18:42 1997 @@ -367,7 +367,7 @@ /* Shortcuts */ typedef struct device device; -typedef struct enet_statistics en_stats; +typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; typedef struct iw_freq iw_freq; diff -u --recursive --new-file v2.1.24/linux/drivers/net/wic.c linux/drivers/net/wic.c --- v2.1.24/linux/drivers/net/wic.c Thu Jan 23 21:06:49 1997 +++ linux/drivers/net/wic.c Thu Jan 1 02:00:00 1970 @@ -1,1440 +0,0 @@ -/* $Id: wic.c,v 1.0 1995/02/11 10:26:05 hayes Exp $ */ -/* WIC: A parallel port "network" driver for Linux. */ -/* based on the plip network driver */ -/* Modified for Linux 1.3.x by Alan Cox */ - -char *version = "NET3 WIC version 0.9 hayes@netplumbing.com"; - -/* - Sources: - Ideas and protocols came from Russ Nelson's - "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 -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#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 " -#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: - */ diff -u --recursive --new-file v2.1.24/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.1.24/linux/drivers/net/znet.c Fri Mar 1 07:50:49 1996 +++ linux/drivers/net/znet.c Sun Feb 2 15:18:43 1997 @@ -121,7 +121,7 @@ #define net_local znet_private struct znet_private { int rx_dma, tx_dma; - struct enet_statistics stats; + struct net_device_stats stats; /* The starting, current, and end pointers for the packet buffers. */ ushort *rx_start, *rx_cur, *rx_end; ushort *tx_start, *tx_cur, *tx_end; @@ -185,7 +185,7 @@ static void znet_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void znet_rx(struct device *dev); static int znet_close(struct device *dev); -static struct enet_statistics *net_get_stats(struct device *dev); +static struct net_device_stats *net_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); static void hardware_init(struct device *dev); static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); @@ -317,6 +317,7 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev) { int ioaddr = dev->base_addr; + struct net_local *lp = (struct net_local *)dev->priv; if (znet_debug > 4) printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy); @@ -340,11 +341,6 @@ hardware_init(dev); } - if (skb == NULL) { - dev_tint(dev); - return 0; - } - /* Check that the part hasn't reset itself, probably from suspend. */ outb(CMD0_STAT0, ioaddr); if (inw(ioaddr) == 0x0010 @@ -361,6 +357,8 @@ unsigned char *buf = (void *)skb->data; ushort *tx_link = zn.tx_cur - 1; ushort rnd_len = (length + 1)>>1; + + lp->stats.tx_bytes+=length; { short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; @@ -616,7 +614,7 @@ /* 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; diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.24/linux/drivers/scsi/Config.in Wed Jan 15 19:45:41 1997 +++ linux/drivers/scsi/Config.in Sun Feb 2 15:18:43 1997 @@ -35,7 +35,7 @@ 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 diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c --- v2.1.24/linux/drivers/scsi/qlogicfas.c Mon Dec 30 15:39:11 1996 +++ linux/drivers/scsi/qlogicfas.c Sun Feb 2 15:34:32 1997 @@ -18,7 +18,7 @@ Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 (you can reference it, but it is incomplete and inaccurate in places) - Version 0.45 6/9/96 - kernel 1.2.0+ + Version 0.46 1/30/97 - kernel 1.2.0+ Functions as standalone, loadable, and PCMCIA driver, the latter from Dave Hind's PCMCIA package. @@ -130,7 +130,7 @@ #include "qlogicfas.h" #include -struct proc_dir_entry proc_scsi_qlogicfas = { +static struct proc_dir_entry proc_scsi_qlogicfas = { PROC_SCSI_QLOGICFAS, 6, "qlogicfas", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; @@ -620,7 +620,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.1.24/linux/drivers/scsi/qlogicisp.c Wed Jul 10 13:11:25 1996 +++ linux/drivers/scsi/qlogicisp.c Sun Feb 2 15:34:32 1997 @@ -2,6 +2,7 @@ * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI) * Written by Erik H. Moe, ehm@cris.com * Copyright 1995, Erik H. Moe + * Copyright 1996, 1997 Michael A. Griffith * * 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 @@ -14,32 +15,6 @@ * General Public License for more details. */ -/* Renamed and updated to 1.3.x by Michael Griffith */ - -/* - * $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 #include #include @@ -390,7 +365,7 @@ #define PACKB(a, b) (((a)<<4)|(b)) -const u_char mbox_param[] = { +static const u_char mbox_param[] = { PACKB(1, 1), /* MBOX_NO_OP */ PACKB(5, 5), /* MBOX_LOAD_RAM */ PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ @@ -534,7 +509,7 @@ 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 *); diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/qlogicisp_asm.c linux/drivers/scsi/qlogicisp_asm.c --- v2.1.24/linux/drivers/scsi/qlogicisp_asm.c Tue Jun 4 06:06:38 1996 +++ linux/drivers/scsi/qlogicisp_asm.c Sun Feb 2 15:34:32 1997 @@ -2,13 +2,13 @@ * Version 2.10 Initiator Firmware (16:13 Oct 18, 1995) */ -unsigned short risc_code_version = 2*1024+10; +static const unsigned short risc_code_version = 2*1024+10; -unsigned short risc_code_addr01 = 0x1000 ; +static const unsigned short risc_code_addr01 = 0x1000 ; #if RELOAD_FIRMWARE -unsigned short risc_code01[] = { +static const unsigned short risc_code01[] = { 0x0078, 0x1041, 0x0000, 0x283a, 0x0000, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, @@ -1301,4 +1301,4 @@ #endif /* RELOAD_FIRMWARE */ -unsigned short risc_code_length01 = 0x283a; +static const unsigned short risc_code_length01 = 0x283a; diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.24/linux/drivers/scsi/scsi.c Tue Jan 28 18:50:14 1997 +++ linux/drivers/scsi/scsi.c Fri Jan 31 14:27:00 1997 @@ -238,6 +238,7 @@ {"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 */ diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.1.24/linux/drivers/scsi/wd7000.c Mon Dec 30 15:39:11 1996 +++ linux/drivers/scsi/wd7000.c Sun Feb 2 15:34:32 1997 @@ -143,6 +143,7 @@ #include #include #include +#include #include #include #include @@ -215,7 +216,7 @@ * 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 diff -u --recursive --new-file v2.1.24/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c --- v2.1.24/linux/fs/proc/procfs_syms.c Wed Jan 15 19:45:43 1997 +++ linux/fs/proc/procfs_syms.c Sun Feb 2 15:18:43 1997 @@ -18,6 +18,7 @@ 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); diff -u --recursive --new-file v2.1.24/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.24/linux/fs/proc/root.c Sun Feb 2 15:46:20 1997 +++ linux/fs/proc/root.c Wed Jan 29 13:32:21 1997 @@ -511,7 +511,7 @@ 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 = { diff -u --recursive --new-file v2.1.24/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c --- v2.1.24/linux/fs/smbfs/sock.c Wed Dec 18 15:58:51 1996 +++ linux/fs/smbfs/sock.c Sun Feb 2 15:18:47 1997 @@ -240,6 +240,10 @@ (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", diff -u --recursive --new-file v2.1.24/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h --- v2.1.24/linux/include/asm-i386/checksum.h Sun Nov 10 20:12:13 1996 +++ linux/include/asm-i386/checksum.h Sun Feb 2 15:18:47 1997 @@ -17,20 +17,39 @@ /* * 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, diff -u --recursive --new-file v2.1.24/linux/include/asm-i386/smp_lock.h linux/include/asm-i386/smp_lock.h --- v2.1.24/linux/include/asm-i386/smp_lock.h Tue Jan 28 18:50:42 1997 +++ linux/include/asm-i386/smp_lock.h Sun Feb 2 16:39:41 1997 @@ -6,7 +6,24 @@ #define lock_kernel() do { } while(0) #define unlock_kernel() do { } while(0) +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED + +#define spin_lock_init(lock) do { } while(0) +#define spin_lock(lock) do { } while(0) +#define spin_trylock(lock) do { } while(0) +#define spin_unlock(lock) do { } while(0) + +#define spin_lock_cli(lock) \ +({ unsigned long flags; \ + save_flags(flags); cli(); \ + return flags; \ +}) + +#define spin_unlock_restore(lock, flags) restore_flags(flags) + #else +#include /* Locking the kernel */ extern __inline__ void lock_kernel(void) @@ -44,6 +61,92 @@ : "m" (current->lock_depth), "i" (NO_PROC_ID) : "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__ */ diff -u --recursive --new-file v2.1.24/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v2.1.24/linux/include/linux/ax25.h Thu Jan 23 21:06:51 1997 +++ linux/include/linux/ax25.h Sun Feb 2 15:18:47 1997 @@ -6,7 +6,6 @@ #ifndef AX25_KERNEL_H #define AX25_KERNEL_H -#define PF_AX25 AF_AX25 #define AX25_MTU 256 #define AX25_MAX_DIGIS 6 /* This is wrong, should be 8 */ diff -u --recursive --new-file v2.1.24/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.1.24/linux/include/linux/if_arp.h Sun Dec 22 16:37:41 1996 +++ linux/include/linux/if_arp.h Sun Feb 2 16:41:45 1997 @@ -57,6 +57,7 @@ #define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */ #define ARPHRD_BIF 775 /* AP1000 BIF */ #define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ +#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */ /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request */ diff -u --recursive --new-file v2.1.24/linux/include/linux/if_ether.h linux/include/linux/if_ether.h --- v2.1.24/linux/include/linux/if_ether.h Fri Apr 12 09:49:46 1996 +++ linux/include/linux/if_ether.h Sun Feb 2 15:18:47 1997 @@ -85,35 +85,11 @@ }; /* - * Ethernet statistics collection data. + * We Have changed the ethernet statistics collection data. This + * is just for partial compatibility for now. */ -struct enet_statistics -{ - int rx_packets; /* total packets received */ - int tx_packets; /* total packets transmitted */ - int rx_errors; /* bad packets received */ - int tx_errors; /* packet transmit problems */ - int rx_dropped; /* no space in linux buffers */ - int tx_dropped; /* no space available in linux */ - int multicast; /* multicast packets received */ - int collisions; - - /* detailed rx_errors: */ - int rx_length_errors; - int rx_over_errors; /* receiver ring buff overflow */ - int rx_crc_errors; /* recved pkt with crc error */ - int rx_frame_errors; /* recv'd frame alignment error */ - int rx_fifo_errors; /* recv'r fifo overrun */ - int rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - int tx_aborted_errors; - int tx_carrier_errors; - int tx_fifo_errors; - int tx_heartbeat_errors; - int tx_window_errors; -}; - + +#define enet_statistics net_device_stats #endif /* _LINUX_IF_ETHER_H */ diff -u --recursive --new-file v2.1.24/linux/include/linux/if_ltalk.h linux/include/linux/if_ltalk.h --- v2.1.24/linux/include/linux/if_ltalk.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/if_ltalk.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,12 @@ +#ifndef __LINUX_LTALK_H +#define __LINUX_LTALK_H + +#define LTALK_HLEN 1 +#define LTALK_MTU 600 +#define LTALK_ALEN 1 + +#ifdef __KERNEL__ +extern void ltalk_setup(struct device *); +#endif + +#endif diff -u --recursive --new-file v2.1.24/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.1.24/linux/include/linux/netdevice.h Thu Jan 23 21:06:51 1997 +++ linux/include/linux/netdevice.h Sun Feb 2 16:41:43 1997 @@ -96,6 +96,42 @@ }; /* + * 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 * data with strictly "high-level" data, and it has to know about @@ -155,7 +191,7 @@ * 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); /* diff -u --recursive --new-file v2.1.24/linux/include/linux/rose.h linux/include/linux/rose.h --- v2.1.24/linux/include/linux/rose.h Thu Jan 23 21:06:52 1997 +++ linux/include/linux/rose.h Sun Feb 2 15:18:47 1997 @@ -10,7 +10,6 @@ #define PF_ROSE AF_ROSE #define ROSE_MTU 128 -#define ROSE_T0 1 #define ROSE_T1 2 #define ROSE_T2 3 #define ROSE_T3 4 diff -u --recursive --new-file v2.1.24/linux/include/linux/sdla_fr.h linux/include/linux/sdla_fr.h --- v2.1.24/linux/include/linux/sdla_fr.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/sdla_fr.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,416 @@ +/***************************************************************************** +* sdla_fr.h Sangoma frame relay firmware API definitions. +* +* Author: Gene Kozin <74604.152@compuserve.com> +* +* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Dec 23, 1996 Gene Kozin v2.0 +* Apr 29, 1996 Gene Kozin v1.0 (merged version S502 & S508 definitions). +* Sep 26, 1995 Gene Kozin Initial version. +*****************************************************************************/ +#ifndef _SDLA_FR_H +#define _SDLA_FR_H + +/*---------------------------------------------------------------------------- + * Notes: + * ------ + * 1. All structures defined in this file are byte-alined. To ensure + * portability of this code between different platforms and compilers, one + * of the following defines must be defined before including this file: + * + * Compiler Platform Define Use option + * -------- -------- ------ ---------- + * GNU C Linux _GNUC_ - + * Microsoft C DOS/Windows _MSC_ - + */ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + +/* Adapter memory layout */ +#define FR_MB_VECTOR 0xE000 /* mailbox window vector */ +#define FR502_RX_VECTOR 0xA000 /* S502 direct receive window vector */ +#define FR502_MBOX_OFFS 0xF60 /* S502 mailbox offset */ +#define FR508_MBOX_OFFS 0 /* S508 mailbox offset */ +#define FR502_FLAG_OFFS 0x1FF0 /* S502 status flags offset */ +#define FR508_FLAG_OFFS 0x1000 /* S508 status flags offset */ +#define FR502_RXMB_OFFS 0x900 /* S502 direct receive mailbox offset */ +#define FR508_TXBC_OFFS 0x1100 /* S508 Tx buffer info offset */ +#define FR508_RXBC_OFFS 0x1120 /* S508 Rx buffer info offset */ + +/* Important constants */ +#define FR502_MAX_DATA 4096 /* maximum data buffer length */ +#define FR508_MAX_DATA 4080 /* maximum data buffer length */ + +/****** Data Structures *****************************************************/ + +/*---------------------------------------------------------------------------- + * Frame relay command block. + */ +typedef struct fr_cmd +{ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* length of data buffer */ + unsigned char result PACKED; /* return code */ + unsigned short dlci PACKED; /* DLCI number */ + unsigned char attr PACKED; /* FECN, BECN, DE and C/R bits */ + unsigned short rxlost1 PACKED; /* frames discarded at int. level */ + unsigned long rxlost2 PACKED; /* frames discarded at app. level */ + unsigned char rsrv[2] PACKED; /* reserved for future use */ +} fr_cmd_t; + +/* 'command' field defines */ +#define FR_WRITE 0x01 +#define FR_READ 0x02 +#define FR_ISSUE_IS_FRAME 0x03 +#define FR_SET_CONFIG 0x10 +#define FR_READ_CONFIG 0x11 +#define FR_COMM_DISABLE 0x12 +#define FR_COMM_ENABLE 0x13 +#define FR_READ_STATUS 0x14 +#define FR_READ_STATISTICS 0x15 +#define FR_FLUSH_STATISTICS 0x16 +#define FR_LIST_ACTIVE_DLCI 0x17 +#define FR_FLUSH_DATA_BUFFERS 0x18 +#define FR_ADD_DLCI 0x20 +#define FR_DELETE_DLCI 0x21 +#define FR_ACTIVATE_DLCI 0x22 +#define FR_DEACTIVATE_DLCI 0x22 +#define FR_READ_MODEM_STATUS 0x30 +#define FR_SET_MODEM_STATUS 0x31 +#define FR_READ_ERROR_STATS 0x32 +#define FR_FLUSH_ERROR_STATS 0x33 +#define FR_READ_CODE_VERSION 0x40 +#define FR_SET_INTR_MODE 0x50 +#define FR_READ_INTR_MODE 0x51 + +/* 'result' field defines */ +#define FRRES_OK 0x00 /* command executed successfully */ +#define FRRES_DISABLED 0x01 /* communications not enabled */ +#define FRRES_INOPERATIVE 0x02 /* channel inoperative */ +#define FRRES_DLCI_INACTIVE 0x03 /* DLCI is inactive */ +#define FRRES_DLCI_INVALID 0x04 /* DLCI is not configured */ +#define FRRES_TOO_LONG 0x04 +#define FRRES_TOO_MANY 0x05 +#define FRRES_CIR_OVERFLOW 0x07 /* Tx throughput has exceeded CIR */ +#define FRRES_BUFFER_OVERFLOW 0x08 +#define FRRES_MODEM_FAILURE 0x10 /* DCD and/or CTS dropped */ +#define FRRES_CHANNEL_DOWN 0x11 /* channel became inoperative */ +#define FRRES_CHANNEL_UP 0x12 /* channel became operative */ +#define FRRES_DLCI_CHANGE 0x13 /* DLCI status (or number) changed */ +#define FRRES_DLCI_MISMATCH 0x14 +#define FRRES_INVALID_CMD 0x1F /* invalid command */ + +/* 'attr' field defines */ +#define FRATTR_ + +/*---------------------------------------------------------------------------- + * Frame relay mailbox. + * This structure is located at offset FR50?_MBOX_OFFS into FR_MB_VECTOR. + * For S502 it is also located at offset FR502_RXMB_OFFS into + * FR502_RX_VECTOR. + */ +typedef struct fr_mbox +{ + unsigned char opflag PACKED; /* 00h: execution flag */ + fr_cmd_t cmd PACKED; /* 01h: command block */ + unsigned char data[1] PACKED; /* 10h: variable length data buffer */ +} fr_mbox_t; + +/*---------------------------------------------------------------------------- + * S502 frame relay status flags. + * This structure is located at offset FR502_FLAG_OFFS into FR_MB_VECTOR. + */ +typedef struct fr502_flags +{ + unsigned char rsrv1[1] PACKED; /* 00h: */ + unsigned char tx_ready PACKED; /* 01h: Tx buffer available */ + unsigned char rx_ready PACKED; /* 02h: Rx frame available */ + unsigned char event PACKED; /* 03h: asynchronous event */ + unsigned char mstatus PACKED; /* 04h: modem status */ + unsigned char rsrv2[8] PACKED; /* 05h: */ + unsigned char iflag PACKED; /* 0Dh: interrupt flag */ + unsigned char imask PACKED; /* 0Eh: interrupt mask */ +} fr502_flags_t; + +/*---------------------------------------------------------------------------- + * S508 frame relay status flags. + * This structure is located at offset FR508_FLAG_OFFS into FR_MB_VECTOR. + */ +typedef struct fr508_flags +{ + unsigned char rsrv1[3] PACKED; /* 00h: reserved */ + unsigned char event PACKED; /* 03h: asynchronous event */ + unsigned char mstatus PACKED; /* 04h: modem status */ + unsigned char rsrv2[11] PACKED; /* 05h: reserved */ + unsigned char iflag PACKED; /* 10h: interrupt flag */ + unsigned char imask PACKED; /* 11h: interrupt mask */ + unsigned long tse_offs PACKED; /* 12h: Tx status element */ +} fr508_flags_t; + +/* 'event' field defines */ +#define FR_EVENT_STATUS 0x01 /* channel status change ??? */ +#define FR_EVENT_DLC_STATUS 0x02 /* DLC status change */ +#define FR_EVENT_BAD_DLCI 0x04 /* FSR included wrong DLCI */ +#define FR_EVENT_LINK_DOWN 0x40 /* DCD or CTS low */ + +/* 'mstatus' field defines */ +#define FR_MDM_DCD 0x08 /* mdm_status: DCD */ +#define FR_MDM_CTS 0x20 /* mdm_status: CTS */ + +/* 'iflag' & 'imask' fields defines */ +#define FR_INTR_RXRDY 0x01 /* Rx ready */ +#define FR_INTR_TXRDY 0x02 /* Tx ready */ +#define FR_INTR_MODEM 0x04 /* modem status change (DCD, CTS) */ +#define FR_INTR_READY 0x08 /* interface command completed */ +#define FR_INTR_DLC 0x10 /* DLC status change */ +#define FR_INTR_TIMER 0x20 /* millisecond timer */ + +/*---------------------------------------------------------------------------- + * Receive Buffer Configuration Info. S508 only! + * This structure is located at offset FR508_RXBC_OFFS into FR_MB_VECTOR. + */ +typedef struct fr_buf_info +{ + unsigned short rse_num PACKED; /* 00h: number of status elements */ + unsigned long rse_base PACKED; /* 02h: receive status array base */ + unsigned long rse_next PACKED; /* 06h: next status element */ + unsigned long buf_base PACKED; /* 0Ah: rotational buffer base */ + unsigned short reserved PACKED; /* 0Eh: */ + unsigned long buf_top PACKED; /* 10h: rotational buffer top */ +} fr_buf_info_t; + +/*---------------------------------------------------------------------------- + * Buffer Status Element. S508 only! + * Array of structures of this type is located at offset defined by the + * 'rse_base' field of the frBufInfo_t structure into absolute adapter + * memory address space. + */ +typedef struct fr_buf_ctl +{ + unsigned char flag PACKED; /* 00h: ready flag */ + unsigned short length PACKED; /* 01h: frame length */ + unsigned short dlci PACKED; /* 03h: DLCI */ + unsigned char attr PACKED; /* 05h: FECN/BECN/DE/CR */ + unsigned short tmstamp PACKED; /* 06h: time stamp */ + unsigned short rsrv[2] PACKED; /* 08h: */ + unsigned long offset PACKED; /* 0Ch: buffer absolute address */ +} fr_buf_ctl_t; + +/*---------------------------------------------------------------------------- + * Global Configuration Block. Passed to FR_SET_CONFIG command when dlci == 0. + */ +typedef struct fr_conf +{ + unsigned short station PACKED; /* 00h: CPE/Node */ + unsigned short options PACKED; /* 02h: configuration options */ + unsigned short kbps PACKED; /* 04h: baud rate in kbps */ + unsigned short port PACKED; /* 06h: RS-232/V.35 */ + unsigned short mtu PACKED; /* 08h: max. transmit length */ + unsigned short t391 PACKED; /* 0Ah: */ + unsigned short t392 PACKED; /* 0Ch: */ + unsigned short n391 PACKED; /* 0Eh: */ + unsigned short n392 PACKED; /* 10h: */ + unsigned short n393 PACKED; /* 12h: */ + unsigned short cir_fwd PACKED; /* 14h: */ + unsigned short bc_fwd PACKED; /* 16h: */ + unsigned short be_fwd PACKED; /* 18h: */ + unsigned short cir_bwd PACKED; /* 1Ah: */ + unsigned short bc_bwd PACKED; /* 1Ch: */ + unsigned short be_bwd PACKED; /* 1Eh: */ + unsigned short dlci[0] PACKED; /* 20h: */ +} fr_conf_t; + +/* 'station_type' defines */ +#define FRCFG_STATION_CPE 0 +#define FRCFG_STATION_NODE 1 + +/* 'conf_flags' defines */ +#define FRCFG_IGNORE_TX_CIR 0x0001 +#define FRCFG_IGNORE_RX_CIR 0x0002 +#define FRCFG_DONT_RETRANSMIT 0x0004 +#define FRCFG_IGNORE_CBS 0x0008 +#define FRCFG_THROUGHPUT 0x0010 /* enable throughput calculation */ +#define FRCFG_DIRECT_RX 0x0080 /* enable direct receive buffer */ +#define FRCFG_AUTO_CONFIG 0x8000 /* enable auto DLCI configuration */ + +/* 'baud_rate' defines */ +#define FRCFG_BAUD_1200 12 +#define FRCFG_BAUD_2400 24 +#define FRCFG_BAUD_4800 48 +#define FRCFG_BAUD_9600 96 +#define FRCFG_BAUD_19200 19 +#define FRCFG_BAUD_38400 38 +#define FRCFG_BAUD_56000 56 +#define FRCFG_BAUD_64000 64 +#define FRCFG_BAUD_128000 128 + +/* 'port_mode' defines */ +#define FRCFG_MODE_EXT_CLK 0x0000 +#define FRCFG_MODE_INT_CLK 0x0001 +#define FRCFG_MODE_V35 0x0000 /* S508 only */ +#define FRCFG_MODE_RS232 0x0002 /* S508 only */ + +/*---------------------------------------------------------------------------- + * Channel configuration. + * This structure is passed to the FR_SET_CONFIG command when dlci != 0. + */ +typedef struct fr_dlc_conf +{ + unsigned short conf_flags PACKED; /* 00h: configuration bits */ + unsigned short cir_fwd PACKED; /* 02h: */ + unsigned short bc_fwd PACKED; /* 04h: */ + unsigned short be_fwd PACKED; /* 06h: */ + unsigned short cir_bwd PACKED; /* 08h: */ + unsigned short bc_bwd PACKED; /* 0Ah: */ + unsigned short be_bwd PACKED; /* 0Ch: */ +} fr_dlc_conf_t; + +/*---------------------------------------------------------------------------- + * S502 Interrupt mode control block. + * This structure is passed to the FR_SET_INTR_FLAGS and returned by the + * FR_READ_INTR_FLAGS commands. + */ +typedef struct fr502_intr_ctl +{ + unsigned char mode PACKED; /* 00h: interrupt enable flags */ + unsigned short tx_len PACKED; /* 01h: required Tx buffer size */ +} fr502_intr_ctl_t; + +/*---------------------------------------------------------------------------- + * S508 Interrupt mode control block. + * This structure is passed to the FR_SET_INTR_FLAGS and returned by the + * FR_READ_INTR_FLAGS commands. + */ +typedef struct fr508_intr_ctl +{ + unsigned char mode PACKED; /* 00h: interrupt enable flags */ + unsigned short tx_len PACKED; /* 01h: required Tx buffer size */ + unsigned char irq PACKED; /* 03h: IRQ level to activate */ + unsigned char flags PACKED; /* 04h: ?? */ + unsigned short timeout PACKED; /* 05h: ms, for timer interrupt */ +} fr508_intr_ctl_t; + +/*---------------------------------------------------------------------------- + * Channel Status. + * This structure is returned by the FR_READ_STATUS command. + */ +typedef struct frDLCStatus +{ + unsigned char status PACKED; /* 00h: link/DLCI status */ + struct + { + unsigned short dlci PACKED; /* 01h: DLCI number */ + unsigned char status PACKED; /* 03h: DLCI status */ + } circuit[1] PACKED; +} frDLCStatus_t; + +/* 'status' defines */ +#define FR_LINK_INOPER 0x00 /* for global status (DLCI == 0) */ +#define FR_LINK_OPER 0x01 +#define FR_DLCI_DELETED 0x01 /* for circuit status (DLCI != 0) */ +#define FR_DLCI_ACTIVE 0x02 +#define FR_DLCI_WAITING 0x04 +#define FR_DLCI_NEW 0x08 +#define FR_DLCI_REPORT 0x40 + +/*---------------------------------------------------------------------------- + * Global Statistics Block. + * This structure is returned by the FR_READ_STATISTICS command when + * dcli == 0. + */ +typedef struct frLinkStat +{ + unsigned short rx_too_long PACKED; /* 00h: */ + unsigned short rx_dropped PACKED; /* 02h: */ + unsigned short rx_dropped2 PACKED; /* 04h: */ + unsigned short rx_bad_dlci PACKED; /* 06h: */ + unsigned short rx_bad_format PACKED; /* 08h: */ + unsigned short retransmitted PACKED; /* 0Ah: */ + unsigned short cpe_tx_FSE PACKED; /* 0Ch: */ + unsigned short cpe_tx_LIV PACKED; /* 0Eh: */ + unsigned short cpe_rx_FSR PACKED; /* 10h: */ + unsigned short cpe_rx_LIV PACKED; /* 12h: */ + unsigned short node_rx_FSE PACKED; /* 14h: */ + unsigned short node_rx_LIV PACKED; /* 16h: */ + unsigned short node_tx_FSR PACKED; /* 18h: */ + unsigned short node_tx_LIV PACKED; /* 1Ah: */ + unsigned short rx_ISF_err PACKED; /* 1Ch: */ + unsigned short rx_unsolicited PACKED; /* 1Eh: */ + unsigned short rx_SSN_err PACKED; /* 20h: */ + unsigned short rx_RSN_err PACKED; /* 22h: */ + unsigned short T391_timeouts PACKED; /* 24h: */ + unsigned short T392_timeouts PACKED; /* 26h: */ + unsigned short N392_reached PACKED; /* 28h: */ + unsigned short cpe_SSN_RSN PACKED; /* 2Ah: */ + unsigned short current_SSN PACKED; /* 2Ch: */ + unsigned short current_RSN PACKED; /* 2Eh: */ + unsigned short curreny_T391 PACKED; /* 30h: */ + unsigned short current_T392 PACKED; /* 32h: */ + unsigned short current_N392 PACKED; /* 34h: */ + unsigned short current_N393 PACKED; /* 36h: */ +} frLinkStat_t; + +/*---------------------------------------------------------------------------- + * DLCI Statistics. + * This structure is returned by the FR_READ_STATISTICS command when + * dlci != 0. + */ +typedef struct frDLCIStat +{ + unsigned long tx_frames PACKED; /* 00h: */ + unsigned long tx_bytes PACKED; /* 04h: */ + unsigned long rx_frames PACKED; /* 08h: */ + unsigned long rx_bytes PACKED; /* 0Ch: */ + unsigned long rx_dropped PACKED; /* 10h: */ + unsigned long rx_inactive PACKED; /* 14h: */ + unsigned long rx_exceed_CIR PACKED; /* 18h: */ + unsigned long rx_DE_set PACKED; /* 1Ch: */ + unsigned long tx_throughput PACKED; /* 20h: */ + unsigned long tx_calc_timer PACKED; /* 24h: */ + unsigned long rx_throughput PACKED; /* 28h: */ + unsigned long rx_calc_timer PACKED; /* 2Ch: */ +} frDLCIStat_t; + +/*---------------------------------------------------------------------------- + * Communications Error Statistics. + * This structure is returned by the FR_READ_ERROR_STATS command. + */ +typedef struct frCommStat +{ + unsigned char rx_overruns PACKED; /* 00h: */ + unsigned char rx_bad_crc PACKED; /* 01h: */ + unsigned char rx_aborts PACKED; /* 02h: */ + unsigned char rx_too_long PACKED; /* 03h: */ + unsigned char tx_aborts PACKED; /* 04h: */ + unsigned char tx_underruns PACKED; /* 05h: */ + unsigned char tx_missed_undr PACKED; /* 06h: */ + unsigned char dcd_dropped PACKED; /* 07h: */ + unsigned char cts_dropped PACKED; /* 08h: */ +} frCommStat_t; + +/*---------------------------------------------------------------------------- + * Defines for the FR_ISSUE_IS_FRAME command. + */ +#define FR_ISF_LVE 2 /* issue Link Verification Enquiry */ +#define FR_ISF_FSE 3 /* issue Full Status Enquiry */ + +#ifdef _MSC_ +# pragma pack() +#endif +#endif /* _SDLA_FR_H */ + diff -u --recursive --new-file v2.1.24/linux/include/linux/sdla_ppp.h linux/include/linux/sdla_ppp.h --- v2.1.24/linux/include/linux/sdla_ppp.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/sdla_ppp.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,536 @@ +/***************************************************************************** +* sdla_ppp.h Sangoma PPP firmware API definitions. +* +* Author: Gene Kozin <74604.152@compuserve.com> +* +* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 06, 1997 Gene Kozin v2.0 +* Apr 11, 1996 Gene Kozin Initial version. +*****************************************************************************/ +#ifndef _SDLA_PPP_H +#define _SDLA_PPP_H + +/*---------------------------------------------------------------------------- + * Notes: + * ------ + * 1. All structures defined in this file are byte-alined. To ensure + * portability of this code between different platforms and compilers, one + * of the following defines must be defined before including this file: + * + * Compiler Platform Define Use option + * -------- -------- ------ ---------- + * GNU C Linux _GNUC_ - + * Microsoft C DOS/Windows _MSC_ - + */ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + +/* Adapter memory layout and important constants */ + +#define PPP502_MB_VECT 0xA000 /* mailbox window vector */ +#define PPP502_MB_OFFS 0x1C00 /* mailbox offset */ +#define PPP502_FLG_OFFS 0 /* status flags offset */ +#define PPP502_BUF_OFFS 0x0010 /* buffer info block offset */ + +#define PPP508_MB_VECT 0xE000 /* mailbox window vector */ +#define PPP508_MB_OFFS 0 /* mailbox offset */ +#define PPP508_FLG_OFFS 0x1000 /* status flags offset */ +#define PPP508_BUF_OFFS 0x1100 /* buffer info block offset */ + +#define PPP_MAX_DATA 1008 /* command block data buffer length */ + +/****** Data Structures *****************************************************/ + +/*---------------------------------------------------------------------------- + * PPP Command Block. + */ +typedef struct ppp_cmd +{ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* length of data buffer */ + unsigned char result PACKED; /* return code */ + unsigned char rsrv[11] PACKED; /* reserved for future use */ +} ppp_cmd_t; + +/* 'command' field defines */ +#define PPP_READ_CODE_VERSION 0x10 /* configuration commands */ +#define PPP_SET_CONFIG 0x05 +#define PPP_READ_CONFIG 0x06 +#define PPP_SET_INTR_FLAGS 0x20 +#define PPP_READ_INTR_FLAGS 0x21 +#define PPP_SET_INBOUND_AUTH 0x30 +#define PPP_SET_OUTBOUND_AUTH 0x31 +#define PPP_GET_CONNECTION_INFO 0x32 + +#define PPP_COMM_ENABLE 0x03 /* operational commands */ +#define PPP_COMM_DISABLE 0x04 +#define PPP_SEND_SIGN_FRAME 0x23 +#define PPP_READ_SIGN_RESPONSE 0x24 +#define PPP_DATALINE_MONITOR 0x33 + +#define PPP_READ_STATISTICS 0x07 /* statistics commands */ +#define PPP_FLUSH_STATISTICS 0x08 +#define PPP_READ_ERROR_STATS 0x09 +#define PPP_FLUSH_ERROR_STATS 0x0A +#define PPP_READ_PACKET_STATS 0x12 +#define PPP_FLUSH_PACKET_STATS 0x13 +#define PPP_READ_LCP_STATS 0x14 +#define PPP_FLUSH_LCP_STATS 0x15 +#define PPP_READ_LPBK_STATS 0x16 +#define PPP_FLUSH_LPBK_STATS 0x17 +#define PPP_READ_IPCP_STATS 0x18 +#define PPP_FLUSH_IPCP_STATS 0x19 +#define PPP_READ_IPXCP_STATS 0x1A +#define PPP_FLUSH_IPXCP_STATS 0x1B +#define PPP_READ_PAP_STATS 0x1C +#define PPP_FLUSH_PAP_STATS 0x1D +#define PPP_READ_CHAP_STATS 0x1E +#define PPP_FLUSH_CHAP_STATS 0x1F + +/* 'result' field defines */ +#define PPPRES_OK 0x00 /* command executed successfully */ +#define PPPRES_INVALID_STATE 0x09 /* invalid command in this context */ + +/*---------------------------------------------------------------------------- + * PPP Mailbox. + * This structure is located at offset PPP???_MB_OFFS into PPP???_MB_VECT + */ +typedef struct ppp_mbox +{ + unsigned char flag PACKED; /* 00h: command execution flag */ + ppp_cmd_t cmd PACKED; /* 01h: command block */ + unsigned char data[1] PACKED; /* 10h: variable length data buffer */ +} ppp_mbox_t; + +/*---------------------------------------------------------------------------- + * PPP Status Flags. + * This structure is located at offset PPP???_FLG_OFFS into + * PPP???_MB_VECT. + */ +typedef struct ppp_flags +{ + unsigned char iflag PACKED; /* 00: interrupt flag */ + unsigned char imask PACKED; /* 01: interrupt mask */ + unsigned char resrv PACKED; + unsigned char mstatus PACKED; /* 03: modem status */ + unsigned char lcp_state PACKED; /* 04: LCP state */ + unsigned char ppp_phase PACKED; /* 05: PPP phase */ + unsigned char ip_state PACKED; /* 06: IPCP state */ + unsigned char ipx_state PACKED; /* 07: IPXCP state */ + unsigned char pap_state PACKED; /* 08: PAP state */ + unsigned char chap_state PACKED; /* 09: CHAP state */ + unsigned short disc_cause PACKED; /* 0A: disconnection cause */ +} ppp_flags_t; + +/* 'iflag' defines */ +#define PPP_INTR_RXRDY 0x01 /* Rx ready */ +#define PPP_INTR_TXRDY 0x02 /* Tx ready */ +#define PPP_INTR_MODEM 0x04 /* modem status change (DCD, CTS) */ +#define PPP_INTR_CMD 0x08 /* interface command completed */ +#define PPP_INTR_DISC 0x10 /* data link disconnected */ +#define PPP_INTR_OPEN 0x20 /* data link open */ +#define PPP_INTR_DROP_DTR 0x40 /* DTR drop timeout expired */ + +/* 'mstatus' defines */ +#define PPP_MDM_DCD 0x08 /* mdm_status: DCD */ +#define PPP_MDM_CTS 0x20 /* mdm_status: CTS */ + +/*---------------------------------------------------------------------------- + * PPP Buffer Info. + * This structure is located at offset PPP502_BUF_OFFS into + * PPP502_MB_VECT. + */ +typedef struct ppp502_buf_info +{ + unsigned short txb_num PACKED; /* 00: number of transmit buffers */ + unsigned short txb_offs PACKED; /* 02: offset of the buffer ctl. */ + unsigned char rsrv1[4] PACKED; + unsigned short rxb_num PACKED; /* 08: number of receive buffers */ + unsigned short rxb_offs PACKED; /* 0A: offset of the buffer ctl. */ + unsigned char rsrv2[2] PACKED; + unsigned short rxb_next PACKED; /* 0E: index of the next buffer */ +} ppp502_buf_info_t; + +/*---------------------------------------------------------------------------- + * PPP Buffer Info. + * This structure is located at offset PPP508_BUF_OFFS into + * PPP508_MB_VECT. + */ +typedef struct ppp508_buf_info +{ + unsigned short txb_num PACKED; /* 00: number of transmit buffers */ + unsigned long txb_ptr PACKED; /* 02: pointer to the buffer ctl. */ + unsigned char rsrv1[26] PACKED; + unsigned short rxb_num PACKED; /* 20: number of receive buffers */ + unsigned long rxb_ptr PACKED; /* 22: pointer to the buffer ctl. */ + unsigned long rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */ + unsigned long rxb_base PACKED; /* 2A: pointer to the buffer base */ + unsigned char rsrv2[2] PACKED; + unsigned long rxb_end PACKED; /* 30: pointer to the buffer end */ +} ppp508_buf_info_t; + +/*---------------------------------------------------------------------------- + * Transmit/Receive Buffer Control Block. + */ +typedef struct ppp_buf_ctl +{ + unsigned char flag PACKED; /* 00: 'buffer ready' flag */ + unsigned short length PACKED; /* 01: length of data */ + unsigned char reserved1[1] PACKED; /* 03: */ + unsigned char proto PACKED; /* 04: protocol */ + unsigned short timestamp PACKED; /* 05: time stamp (Rx only) */ + unsigned char reserved2[5] PACKED; /* 07: */ + union + { + unsigned short o_p[2]; /* 1C: buffer offset & page (S502) */ + unsigned long ptr; /* 1C: buffer pointer (S508) */ + } buf PACKED; +} ppp_buf_ctl_t; + +/*---------------------------------------------------------------------------- + * S502 Adapter Configuration Block (passed to the PPP_SET_CONFIG command). + */ +typedef struct ppp502_conf +{ + unsigned char line_speed PACKED; /* 00: 0 - external clk. */ + unsigned short txbuf_num PACKED; /* 01: number of Tx buffers */ + unsigned short conf_flags PACKED; /* 03: configuration bits */ + unsigned short mtu_local PACKED; /* 05: local MTU */ + unsigned short mtu_remote PACKED; /* 07: remote MTU */ + unsigned short restart_tmr PACKED; /* 09: restart timer */ + unsigned short auth_rsrt_tmr PACKED; /* 0B: authentication timer */ + unsigned short auth_wait_tmr PACKED; /* 0D: authentication timer */ + unsigned short mdm_fail_tmr PACKED; /* 0F: modem failure timer */ + unsigned short dtr_drop_tmr PACKED; /* 11: DTR drop timer */ + unsigned short connect_tmout PACKED; /* 13: connection timeout */ + unsigned short conf_retry PACKED; /* 15: max. retry */ + unsigned short term_retry PACKED; /* 17: max. retry */ + unsigned short fail_retry PACKED; /* 19: max. retry */ + unsigned short auth_retry PACKED; /* 1B: max. retry */ + unsigned char auth_options PACKED; /* 1D: authentication opt. */ + unsigned char ip_options PACKED; /* 1E: IP options */ + unsigned char ip_local[4] PACKED; /* 1F: local IP address */ + unsigned char ip_remote[4] PACKED; /* 23: remote IP address */ + unsigned char ipx_options PACKED; /* 27: IPX options */ + unsigned char ipx_netno[4] PACKED; /* 28: IPX net number */ + unsigned char ipx_local[6] PACKED; /* 2C: local IPX node number*/ + unsigned char ipx_remote[6] PACKED; /* 32: remote IPX node num.*/ + unsigned char ipx_router[48] PACKED; /* 38: IPX router name*/ +} ppp502_conf_t; + +/*---------------------------------------------------------------------------- + * S508 Adapter Configuration Block (passed to the PPP_SET_CONFIG command). + */ +typedef struct ppp508_conf +{ + unsigned long line_speed PACKED; /* 00: baud rate, bps */ + unsigned short txbuf_percent PACKED; /* 04: % of Tx buffer */ + unsigned short conf_flags PACKED; /* 06: configuration bits */ + unsigned short mtu_local PACKED; /* 08: local MTU */ + unsigned short mtu_remote PACKED; /* 0A: remote MTU */ + unsigned short restart_tmr PACKED; /* 0C: restart timer */ + unsigned short auth_rsrt_tmr PACKED; /* 0E: authentication timer */ + unsigned short auth_wait_tmr PACKED; /* 10: authentication timer */ + unsigned short mdm_fail_tmr PACKED; /* 12: modem failure timer */ + unsigned short dtr_drop_tmr PACKED; /* 14: DTR drop timer */ + unsigned short connect_tmout PACKED; /* 16: connection timeout */ + unsigned short conf_retry PACKED; /* 18: max. retry */ + unsigned short term_retry PACKED; /* 1A: max. retry */ + unsigned short fail_retry PACKED; /* 1C: max. retry */ + unsigned short auth_retry PACKED; /* 1E: max. retry */ + unsigned char auth_options PACKED; /* 20: authentication opt. */ + unsigned char ip_options PACKED; /* 21: IP options */ + unsigned char ip_local[4] PACKED; /* 22: local IP address */ + unsigned char ip_remote[4] PACKED; /* 26: remote IP address */ + unsigned char ipx_options PACKED; /* 2A: IPX options */ + unsigned char ipx_netno[4] PACKED; /* 2B: IPX net number */ + unsigned char ipx_local[6] PACKED; /* 2F: local IPX node number*/ + unsigned char ipx_remote[6] PACKED; /* 35: remote IPX node num.*/ + unsigned char ipx_router[48] PACKED; /* 3B: IPX router name*/ + unsigned long alt_cpu_clock PACKED; /* 6B: */ +} ppp508_conf_t; + +/* 'line_speed' field */ +#define PPP_BITRATE_1200 0x01 +#define PPP_BITRATE_2400 0x02 +#define PPP_BITRATE_4800 0x03 +#define PPP_BITRATE_9600 0x04 +#define PPP_BITRATE_19200 0x05 +#define PPP_BITRATE_38400 0x06 +#define PPP_BITRATE_45000 0x07 +#define PPP_BITRATE_56000 0x08 +#define PPP_BITRATE_64000 0x09 +#define PPP_BITRATE_74000 0x0A +#define PPP_BITRATE_112000 0x0B +#define PPP_BITRATE_128000 0x0C +#define PPP_BITRATE_156000 0x0D + +/* Defines for the 'conf_flags' field */ +#define PPP_IGNORE_TX_ABORT 0x01 /* don't re-transmit aborted frames */ +#define PPP_ENABLE_TX_STATS 0x02 /* enable Tx statistics */ +#define PPP_ENABLE_RX_STATS 0x04 /* enable Rx statistics */ +#define PPP_ENABLE_TIMESTAMP 0x08 /* enable timestamp */ + +/* 'ip_options' defines */ +#define PPP_LOCAL_IP_LOCAL 0x01 +#define PPP_LOCAL_IP_REMOTE 0x02 +#define PPP_REMOTE_IP_LOCAL 0x04 +#define PPP_REMOTE_IP_REMOTE 0x08 + +/* 'ipx_options' defines */ +#define PPP_REMOTE_IPX_NETNO 0x01 +#define PPP_REMOTE_IPX_LOCAL 0x02 +#define PPP_REMOTE_IPX_REMOTE 0x04 +#define PPP_IPX_ROUTE_RIP_SAP 0x08 +#define PPP_IPX_ROUTE_NLSP 0x10 +#define PPP_IPX_ROUTE_DEFAULT 0x20 +#define PPP_IPX_CONF_COMPLETE 0x40 +#define PPP_IPX_ENABLE 0x80 + +/*---------------------------------------------------------------------------- + * S502 Adapter Configuration Block (returned by the PPP_READ_CONFIG command). + */ +typedef struct ppp502_get_conf +{ + ppp502_conf_t conf PACKED; /* 00: requested config. */ + unsigned short txb_num PACKED; /* 68: number of Tx buffers */ + unsigned short rxb_num PACKED; /* 6A: number of Rx buffers */ +} ppp502_get_conf_t; + +/*---------------------------------------------------------------------------- + * S508 Adapter Configuration Block (returned by the PPP_READ_CONFIG command). + */ +typedef struct ppp508_get_conf +{ + unsigned long bps PACKED; /* 00: baud rate, bps */ + ppp508_conf_t conf PACKED; /* 04: requested config. */ + unsigned short txb_num PACKED; /* 6F: number of Tx buffers */ + unsigned short rxb_num PACKED; /* 71: number of Rx buffers */ +} ppp508_get_conf_t; + +/*---------------------------------------------------------------------------- + * S502 Operational Statistics (returned by the PPP_READ_STATISTIC command). + */ +typedef struct ppp502_Stats +{ + unsigned short rx_lost_intr PACKED; /* 00: */ + unsigned short rx_lost_buff PACKED; /* 02: */ + unsigned short tx_abort PACKED; /* 04: */ + unsigned long tx_frames PACKED; /* 06: */ + unsigned long tx_bytes PACKED; /* 0A: */ + unsigned long rx_frames PACKED; /* 0E: */ + unsigned long rx_bytes PACKED; /* 12: */ +} ppp502_Stats_t; + +/*---------------------------------------------------------------------------- + * S508 Operational Statistics (returned by the PPP_READ_STATISTIC command). + */ +typedef struct ppp508_stats +{ + unsigned short reserved1 PACKED; /* 00: */ + unsigned short rx_bad_len PACKED; /* 02: */ + unsigned short reserved2 PACKED; /* 04: */ + unsigned long tx_frames PACKED; /* 06: */ + unsigned long tx_bytes PACKED; /* 0A: */ + unsigned long rx_frames PACKED; /* 0E: */ + unsigned long rx_bytes PACKED; /* 12: */ +} ppp508_stats_t; + +/*---------------------------------------------------------------------------- + * Adapter Error Statistics (returned by the PPP_READ_ERROR_STATS command). + */ +typedef struct ppp_err_stats +{ + unsigned char rx_overrun PACKED; /* 00: Rx overrun errors */ + unsigned char rx_bad_crc PACKED; /* 01: Rx CRC errors */ + unsigned char rx_abort PACKED; /* 02: Rx aborted frames */ + unsigned char rx_lost PACKED; /* 03: Rx frames lost */ + unsigned char tx_abort PACKED; /* 04: Tx aborted frames */ + unsigned char tx_underrun PACKED; /* 05: Tx underrun errors */ + unsigned char tx_missed_intr PACKED; /* 06: Tx underruns missed */ + unsigned char reserved PACKED; /* 07: Tx underruns missed */ + unsigned char dcd_trans PACKED; /* 08: DCD transitions */ + unsigned char cts_trans PACKED; /* 09: CTS transitions */ +} ppp_err_stats_t; + +/*---------------------------------------------------------------------------- + * Packet Statistics (returned by the PPP_READ_PACKET_STATS command). + */ +typedef struct ppp_pkt_stats +{ + unsigned short rx_bad_header PACKED; /* 00: */ + unsigned short rx_prot_unknwn PACKED; /* 02: */ + unsigned short rx_too_large PACKED; /* 04: */ + unsigned short rx_lcp PACKED; /* 06: */ + unsigned short tx_lcp PACKED; /* 08: */ + unsigned short rx_ipcp PACKED; /* 0A: */ + unsigned short tx_ipcp PACKED; /* 0C: */ + unsigned short rx_ipxcp PACKED; /* 0E: */ + unsigned short tx_ipxcp PACKED; /* 10: */ + unsigned short rx_pap PACKED; /* 12: */ + unsigned short tx_pap PACKED; /* 14: */ + unsigned short rx_chap PACKED; /* 16: */ + unsigned short tx_chap PACKED; /* 18: */ + unsigned short rx_lqr PACKED; /* 1A: */ + unsigned short tx_lqr PACKED; /* 1C: */ + unsigned short rx_ip PACKED; /* 1E: */ + unsigned short tx_ip PACKED; /* 20: */ + unsigned short rx_ipx PACKED; /* 22: */ + unsigned short tx_ipx PACKED; /* 24: */ +} ppp_pkt_stats_t; + +/*---------------------------------------------------------------------------- + * LCP Statistics (returned by the PPP_READ_LCP_STATS command). + */ +typedef struct ppp_lcp_stats +{ + unsigned short rx_unknown PACKED; /* 00: unknown LCP type */ + unsigned short rx_conf_rqst PACKED; /* 02: Configure-Request */ + unsigned short rx_conf_ack PACKED; /* 04: Configure-Ack */ + unsigned short rx_conf_nak PACKED; /* 06: Configure-Nak */ + unsigned short rx_conf_rej PACKED; /* 08: Configure-Reject */ + unsigned short rx_term_rqst PACKED; /* 0A: Terminate-Request */ + unsigned short rx_term_ack PACKED; /* 0C: Terminate-Ack */ + unsigned short rx_code_rej PACKED; /* 0E: Code-Reject */ + unsigned short rx_proto_rej PACKED; /* 10: Protocol-Reject */ + unsigned short rx_echo_rqst PACKED; /* 12: Echo-Request */ + unsigned short rx_echo_reply PACKED; /* 14: Echo-Reply */ + unsigned short rx_disc_rqst PACKED; /* 16: Discard-Request */ + unsigned short tx_conf_rqst PACKED; /* 18: Configure-Request */ + unsigned short tx_conf_ack PACKED; /* 1A: Configure-Ack */ + unsigned short tx_conf_nak PACKED; /* 1C: Configure-Nak */ + unsigned short tx_conf_rej PACKED; /* 1E: Configure-Reject */ + unsigned short tx_term_rqst PACKED; /* 20: Terminate-Request */ + unsigned short tx_term_ack PACKED; /* 22: Terminate-Ack */ + unsigned short tx_code_rej PACKED; /* 24: Code-Reject */ + unsigned short tx_proto_rej PACKED; /* 26: Protocol-Reject */ + unsigned short tx_echo_rqst PACKED; /* 28: Echo-Request */ + unsigned short tx_echo_reply PACKED; /* 2A: Echo-Reply */ + unsigned short tx_disc_rqst PACKED; /* 2E: Discard-Request */ + unsigned short rx_too_large PACKED; /* 30: packets too large */ + unsigned short rx_ack_inval PACKED; /* 32: invalid Conf-Ack */ + unsigned short rx_rej_inval PACKED; /* 34: invalid Conf-Reject */ + unsigned short rx_rej_badid PACKED; /* 36: Conf-Reject w/bad ID */ +} ppp_lcp_stats_t; + +/*---------------------------------------------------------------------------- + * Loopback Error Statistics (returned by the PPP_READ_LPBK_STATS command). + */ +typedef struct ppp_lpbk_stats +{ + unsigned short conf_magic PACKED; /* 00: */ + unsigned short loc_echo_rqst PACKED; /* 02: */ + unsigned short rem_echo_rqst PACKED; /* 04: */ + unsigned short loc_echo_reply PACKED; /* 06: */ + unsigned short rem_echo_reply PACKED; /* 08: */ + unsigned short loc_disc_rqst PACKED; /* 0A: */ + unsigned short rem_disc_rqst PACKED; /* 0C: */ + unsigned short echo_tx_collsn PACKED; /* 0E: */ + unsigned short echo_rx_collsn PACKED; /* 10: */ +} ppp_lpbk_stats_t; + +/*---------------------------------------------------------------------------- + * Protocol Statistics (returned by the PPP_READ_IPCP_STATS and + * PPP_READ_IPXCP_STATS commands). + */ +typedef struct ppp_prot_stats +{ + unsigned short rx_unknown PACKED; /* 00: unknown type */ + unsigned short rx_conf_rqst PACKED; /* 02: Configure-Request */ + unsigned short rx_conf_ack PACKED; /* 04: Configure-Ack */ + unsigned short rx_conf_nak PACKED; /* 06: Configure-Nak */ + unsigned short rx_conf_rej PACKED; /* 08: Configure-Reject */ + unsigned short rx_term_rqst PACKED; /* 0A: Terminate-Request */ + unsigned short rx_term_ack PACKED; /* 0C: Terminate-Ack */ + unsigned short rx_code_rej PACKED; /* 0E: Code-Reject */ + unsigned short reserved PACKED; /* 10: */ + unsigned short tx_conf_rqst PACKED; /* 12: Configure-Request */ + unsigned short tx_conf_ack PACKED; /* 14: Configure-Ack */ + unsigned short tx_conf_nak PACKED; /* 16: Configure-Nak */ + unsigned short tx_conf_rej PACKED; /* 18: Configure-Reject */ + unsigned short tx_term_rqst PACKED; /* 1A: Terminate-Request */ + unsigned short tx_term_ack PACKED; /* 1C: Terminate-Ack */ + unsigned short tx_code_rej PACKED; /* 1E: Code-Reject */ + unsigned short rx_too_large PACKED; /* 20: packets too large */ + unsigned short rx_ack_inval PACKED; /* 22: invalid Conf-Ack */ + unsigned short rx_rej_inval PACKED; /* 24: invalid Conf-Reject */ + unsigned short rx_rej_badid PACKED; /* 26: Conf-Reject w/bad ID */ +} ppp_prot_stats_t; + +/*---------------------------------------------------------------------------- + * PAP Statistics (returned by the PPP_READ_PAP_STATS command). + */ +typedef struct ppp_pap_stats +{ + unsigned short rx_unknown PACKED; /* 00: unknown type */ + unsigned short rx_auth_rqst PACKED; /* 02: Authenticate-Request */ + unsigned short rx_auth_ack PACKED; /* 04: Authenticate-Ack */ + unsigned short rx_auth_nak PACKED; /* 06: Authenticate-Nak */ + unsigned short reserved PACKED; /* 08: */ + unsigned short tx_auth_rqst PACKED; /* 0A: Authenticate-Request */ + unsigned short tx_auth_ack PACKED; /* 0C: Authenticate-Ack */ + unsigned short tx_auth_nak PACKED; /* 0E: Authenticate-Nak */ + unsigned short rx_too_large PACKED; /* 10: packets too large */ + unsigned short rx_bad_peerid PACKED; /* 12: invalid peer ID */ + unsigned short rx_bad_passwd PACKED; /* 14: invalid password */ +} ppp_pap_stats_t; + +/*---------------------------------------------------------------------------- + * CHAP Statistics (returned by the PPP_READ_CHAP_STATS command). + */ +typedef struct ppp_chap_stats +{ + unsigned short rx_unknown PACKED; /* 00: unknown type */ + unsigned short rx_challenge PACKED; /* 02: Authenticate-Request */ + unsigned short rx_response PACKED; /* 04: Authenticate-Ack */ + unsigned short rx_success PACKED; /* 06: Authenticate-Nak */ + unsigned short rx_failure PACKED; /* 08: Authenticate-Nak */ + unsigned short reserved PACKED; /* 0A: */ + unsigned short tx_challenge PACKED; /* 0C: Authenticate-Request */ + unsigned short tx_response PACKED; /* 0E: Authenticate-Ack */ + unsigned short tx_success PACKED; /* 10: Authenticate-Nak */ + unsigned short tx_failure PACKED; /* 12: Authenticate-Nak */ + unsigned short rx_too_large PACKED; /* 14: packets too large */ + unsigned short rx_bad_peerid PACKED; /* 16: invalid peer ID */ + unsigned short rx_bad_passwd PACKED; /* 18: invalid password */ + unsigned short rx_bad_md5 PACKED; /* 1A: invalid MD5 format */ + unsigned short rx_bad_resp PACKED; /* 1C: invalid response */ +} ppp_chap_stats_t; + +/*---------------------------------------------------------------------------- + * Connection Information (returned by the PPP_GET_CONNECTION_INFO command). + */ +typedef struct ppp_conn_info +{ + unsigned short remote_mru PACKED; /* 00: */ + unsigned char ip_options PACKED; /* 02: */ + unsigned char ip_local[4] PACKED; /* 03: */ + unsigned char ip_remote[4] PACKED; /* 07: */ + unsigned char ipx_options PACKED; /* 0B: */ + unsigned char ipx_network[4] PACKED; /* 0C: */ + unsigned char ipx_local[6] PACKED; /* 10: */ + unsigned char ipx_remote[6] PACKED; /* 16: */ + unsigned char ipx_router[48] PACKED; /* 1C: */ + unsigned char auth_status PACKED; /* 4C: */ + unsigned char peer_id[0] PACKED; /* 4D: */ +} ppp_conn_info_t; + +#ifdef _MSC_ +# pragma pack() +#endif +#endif /* _SDLA_PPP_H */ diff -u --recursive --new-file v2.1.24/linux/include/linux/sdla_x25.h linux/include/linux/sdla_x25.h --- v2.1.24/linux/include/linux/sdla_x25.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/sdla_x25.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,624 @@ +/***************************************************************************** +* sdla_x25.h Sangoma X.25 firmware API definitions. +* +* Author: Gene Kozin <74604.152@compuserve.com> +* +* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Dec 13, 1996 Gene Kozin Initial version +*****************************************************************************/ +#ifndef _SDLA_X25_H +#define _SDLA_X25_H + +/*---------------------------------------------------------------------------- + * Notes: + * ------ + * 1. All structures defined in this file are byte-alined. To ensure + * portability of this code between different platforms and compilers, one + * of the following defines must be defined before including this file: + * + * Compiler Platform Define Use option + * -------- -------- ------ ---------- + * GNU C Linux _GNUC_ - + * Microsoft C DOS/Windows _MSC_ - + * + */ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + +/****** CONSTANTS DEFINITIONS ***********************************************/ + +#define X25_MAX_CHAN 255 /* max number of open X.25 circuits */ +#define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ + +/* + * X.25 shared memory layout. + */ +#define X25_MBOX_OFFS 0x16B0 /* general mailbox block */ +#define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */ +#define X25_STATUS_OFFS 0x1EF0 /* X.25 status structure */ + +/****** DATA STRUCTURES *****************************************************/ + +/*---------------------------------------------------------------------------- + * X.25 Command Block. + */ +typedef struct X25Cmd +{ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} TX25Cmd; + +/* + * Defines for the 'command' field. + */ +/*----- General commands --------------*/ +#define X25_SET_GLOBAL_VARS 0x0B /* set global variables */ +#define X25_READ_MODEM_STATUS 0x0C /* read modem status */ +#define X25_READ_CODE_VERSION 0x15 /* read firmware version number */ +#define X25_TRACE_CONFIGURE 0x14 /* configure trace facility */ +#define X25_READ_TRACE_DATA 0x16 /* read trace data */ +#define X25_SET_INTERRUPT_MODE 0x17 /* set interrupt generation mode */ +#define X25_READ_INTERRUPT_MODE 0x18 /* read interrupt generation mode */ +/*----- HDLC-level commands -----------*/ +#define X25_HDLC_LINK_CONFIGURE 0x01 /* configure HDLC link level */ +#define X25_HDLC_LINK_OPEN 0x02 /* open HDLC link */ +#define X25_HDLC_LINK_CLOSE 0x03 /* close HDLC link */ +#define X25_HDLC_LINK_SETUP 0x04 /* set up HDLC link */ +#define X25_HDLC_LINK_DISC 0x05 /* disconnect DHLC link */ +#define X25_HDLC_LINK_STATUS 0x06 /* read DHLC link status */ +#define X25_HDLC_READ_STATS 0x07 /* read operational statistics */ +#define X25_HDLC_FLUSH_STATS 0x08 /* flush operational statistics */ +#define X25_HDLC_READ_COMM_ERR 0x09 /* read error statistics */ +#define X25_HDLC_FLUSH_COMM_ERR 0x0A /* flush error statistics */ +#define X25_HDLC_FLUSH_BUFFERS 0x0D /* flush HDLC-level data buffers */ +#define X25_HDLC_SPRVS_CNT_STAT 0x0F /* read surervisory count status */ +#define X25_HDLC_SEND_UI_FRAME 0x10 /* send unnumbered information frame */ +#define X25_HDLC_WRITE 0x11 /* send HDLC information frame */ +#define X25_HDLC_READ 0x21 /* read HDLC information frame */ +#define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */ +#define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */ +/*----- X.25-level commands -----------*/ +#define X25_READ 0x22 /* read X.25 packet */ +#define X25_WRITE 0x23 /* send X.25 packet */ +#define X25_PLACE_CALL 0x30 /* place a call on SVC */ +#define X25_ACCEPT_CALL 0x31 /* accept incomming call */ +#define X25_CLEAR_CALL 0x32 /* clear call */ +#define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ +#define X25_RESET 0x34 /* send reset request packet */ +#define X25_RESET_CONFRM 0x35 /* send reset confirmation packet */ +#define X25_RESTART 0x36 /* send restart request packet */ +#define X25_RESTART_CONFRM 0x37 /* send restart confirmation packet */ +#define X25_INTERRUPT 0x38 /* send interrupt request packet */ +#define X25_INTERRUPT_CONFRM 0x39 /* send interrupt confirmation pkt */ +#define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ +#define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ +#define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ +#define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ +#define X25_CONFIGURE_PVC 0x42 /* configure PVC */ +#define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ +#define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ +#define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ +#define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ +#define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ +#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ +#define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ +#define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ +#define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ +#define X25_SET_CONFIGURATION 0x51 /* set HDLC & X.25 configuration */ + +/* + * Defines for the 'result' field. + */ +/*----- General results ---------------*/ +#define X25RES_OK 0x00 +#define X25RES_ERROR 0x01 +#define X25RES_LINK_NOT_IN_ABM 0x02 /* link is not in ABM mode */ +#define X25RES_LINK_CLOSED 0x03 +#define X25RES_INVAL_LENGTH 0x04 +#define X25RES_INVAL_CMD 0x05 +#define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ +#define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ +#define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ +#define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ +#define X25RES_INVAL_LCN 0x30 /* invalid logical channel number */ +#define X25RES_INVAL_STATE 0x31 /* channel is not in data xfer mode */ +#define X25RES_INVAL_DATA_LEN 0x32 /* invalid data length */ +#define X25RES_NOT_READY 0x33 /* no data available / buffers full */ +#define X25RES_NETWORK_DOWN 0x34 +#define X25RES_CHANNEL_IN_USE 0x35 /* there is data queued on this LCN */ +#define X25RES_REGST_NOT_SUPPRT 0x36 /* registration not supported */ +#define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ +#define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ +#define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ +#define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ +#define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ +#define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ +#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ +#define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ +#define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ +/*----- Command-dependant results -----*/ +#define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ +#define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ +#define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ +#define X25RES_TRACE_INACTIVE 0x02 /* READ_TRACE_DATA */ +#define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ +#define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ +#define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ +#define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ +#define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ + +/* + * Defines for the 'qdm_bits' field. + */ +#define X25CMD_Q_BIT_MASK 0x04 +#define X25CMD_D_BIT_MASK 0x02 +#define X25CMD_M_BIT_MASK 0x01 + +/* + * Defines for the 'pkt_type' field. + */ +/*----- Asynchronous events ------*/ +#define ASE_CLEAR_RQST 0x02 +#define ASE_RESET_RQST 0x04 +#define ASE_RESTART_RQST 0x08 +#define ASE_INTERRUPT 0x10 +#define ASE_DTE_REGISTR_RQST 0x20 +#define ASE_CALL_RQST 0x30 +#define ASE_CALL_ACCEPTED 0x31 +#define ASE_CLEAR_CONFRM 0x32 +#define ASE_RESET_CONFRM 0x33 +#define ASE_RESTART_CONFRM 0x34 +#define ASE_INTERRUPT_CONFRM 0x35 +#define ASE_DCE_REGISTR_CONFRM 0x36 +#define ASE_DIAGNOSTIC 0x37 +#define ASE_CALL_AUTO_CLEAR 0x38 +#define AUTO_RESPONSE_FLAG 0x80 +/*----- Time-Out events ----------*/ +#define TOE_RESTART_RQST 0x03 +#define TOE_CALL_RQST 0x05 +#define TOE_CLEAR_RQST 0x08 +#define TOE_RESET_RQST 0x0A +/*----- Protocol Violation events */ +#define PVE_CLEAR_RQST 0x32 +#define PVE_RESET_RQST 0x33 +#define PVE_RESTART_RQST 0x34 +#define PVE_DIAGNOSTIC 0x37 + +/*---------------------------------------------------------------------------- + * X.25 Mailbox. + * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS + * into shared memory window. + */ +typedef struct X25Mbox +{ + unsigned char opflag PACKED; /* 00h: execution flag */ + TX25Cmd cmd PACKED; /* 01h: command block */ + unsigned char data[1] PACKED; /* 10h: data buffer */ +} TX25Mbox; + +/*---------------------------------------------------------------------------- + * X.25 Time Stamp Structure. + */ +typedef struct X25TimeStamp +{ + unsigned char month PACKED; + unsigned char date PACKED; + unsigned char sec PACKED; + unsigned char min PACKED; + unsigned char hour PACKED; +} TX25TimeStamp; + +/*---------------------------------------------------------------------------- + * X.25 Status Block. + * This structure is located at offset X25_STATUS_OFF into shared memory + * window. + */ +typedef struct X25Status +{ + unsigned short pvc_map PACKED; /* 00h: PVC map */ + unsigned short icc_map PACKED; /* 02h: Incomming Chan. map */ + unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */ + unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */ + TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ + unsigned char iflags PACKED; /* 0Dh: interrupt flags */ + unsigned char resrv[2] PACKED; /* 0Eh: */ + unsigned char gflags PACKED; /* 10h: misc. HDLC/X25 flags */ + unsigned char cflags[X25_MAX_CHAN] PACKED; /* channel status bytes */ +} TX25Status; + +/* + * Bitmasks for the 'iflags' field. + */ +#define X25_RX_INTR 0x01 /* receive interrupt */ +#define X25_TX_INTR 0x02 /* transmit interrupt */ +#define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ +#define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ +#define X25_CMD_INTR 0x08 /* interface command complete */ + +/* + * Bitmasks for the 'gflags' field. + */ +#define X25_HDLC_ABM 0x01 /* HDLC is in ABM mode */ +#define X25_RX_READY 0x02 /* X.25 data available */ +#define X25_TRACE_READY 0x08 /* trace data available */ +#define X25_EVENT_IND 0x20 /* asynchronous event indicator */ +#define X25_TX_READY 0x40 /* space is available in Tx buf.*/ + +/* + * Bitmasks for the 'cflags' field. + */ +#define X25_XFER_MODE 0x80 /* channel is in data transfer mode */ +#define X25_TXWIN_OPEN 0x40 /* transmit window open */ +#define X25_RXBUF_MASK 0x3F /* number of data buffers available */ + +/***************************************************************************** + * Following definitions structurize contents of the TX25Mbox.data field for + * different X.25 interface commands. + ****************************************************************************/ + +/* --------------------------------------------------------------------------- + * X25_SET_GLOBAL_VARS Command. + */ +typedef struct X25GlobalVars +{ + unsigned char resrv PACKED; /* 00h: reserved */ + unsigned char dtrCtl PACKED; /* 01h: DTR control code */ + unsigned char resErr PACKED; /* 01h: '1' - reset modem error */ +} TX25GlobalVars; + +/* + * Defines for the 'dtrCtl' field. + */ +#define X25_RAISE_DTR 0x01 +#define X25_DROP_DTR 0x02 + +/* --------------------------------------------------------------------------- + * X25_READ_MODEM_STATUS Command. + */ +typedef struct X25ModemStatus +{ + unsigned char status PACKED; /* 00h: modem status */ +} TX25ModemStatus; + +/* + * Defines for the 'status' field. + */ +#define X25_CTS_MASK 0x20 +#define X25_DCD_MASK 0x08 + +/* --------------------------------------------------------------------------- + * X25_HDLC_LINK_STATUS Command. + */ +typedef struct X25LinkStatus +{ + unsigned char txQueued PACKED; /* 00h: queued Tx I-frames*/ + unsigned char rxQueued PACKED; /* 01h: queued Rx I-frames*/ + unsigned char station PACKED; /* 02h: DTE/DCE config. */ + unsigned char reserved PACKED; /* 03h: reserved */ + unsigned char sfTally PACKED; /* 04h: supervisory frame tally */ +} TX25LinkStatus; + +/* + * Defines for the 'station' field. + */ +#define X25_STATION_DTE 0x01 /* station configured as DTE */ +#define X25_STATION_DCE 0x02 /* station configured as DCE */ + +/* --------------------------------------------------------------------------- + * X25_HDLC_READ_STATS Command. + */ +typedef struct HdlcStats +{ /* a number of ... */ + unsigned short rxIFrames PACKED; /* 00h: ready Rx I-frames */ + unsigned short rxNoseq PACKED; /* 02h: frms out-of-sequence */ + unsigned short rxNodata PACKED; /* 04h: I-frms without data */ + unsigned short rxDiscarded PACKED; /* 06h: discarded frames */ + unsigned short rxTooLong PACKED; /* 08h: frames too long */ + unsigned short rxBadAddr PACKED; /* 0Ah: frms with inval.addr*/ + unsigned short txAcked PACKED; /* 0Ch: acknowledged I-frms */ + unsigned short txRetransm PACKED; /* 0Eh: re-transmit. I-frms */ + unsigned short t1Timeout PACKED; /* 10h: T1 timeouts */ + unsigned short rxSABM PACKED; /* 12h: received SABM frames */ + unsigned short rxDISC PACKED; /* 14h: received DISC frames */ + unsigned short rxDM PACKED; /* 16h: received DM frames */ + unsigned short rxFRMR PACKED; /* 18h: FRMR frames received */ + unsigned short txSABM PACKED; /* 1Ah: transm. SABM frames*/ + unsigned short txDISC PACKED; /* 1Ch: transm. DISC frames*/ + unsigned short txDM PACKED; /* 1Eh: transm. DM frames */ + unsigned short txFRMR PACKED; /* 20h: transm. FRMR frames*/ +} THdlcStats; + +/* --------------------------------------------------------------------------- + * X25_HDLC_READ_COMM_ERR Command. + */ +typedef struct HdlcCommErr +{ /* a number of ... */ + unsigned char rxOverrun PACKED; /* 00h: Rx overrun errors */ + unsigned char rxBadCrc PACKED; /* 01h: Rx CRC errors */ + unsigned char rxAborted PACKED; /* 02h: Rx aborted frames */ + unsigned char rxDropped PACKED; /* 03h: frames lost */ + unsigned char txAborted PACKED; /* 04h: Tx aborted frames */ + unsigned char txUnderrun PACKED; /* 05h: Tx underrun errors */ + unsigned char txMissIntr PACKED; /* 06h: missed underrun ints */ + unsigned char reserved PACKED; /* 07h: reserved */ + unsigned char droppedDCD PACKED; /* 08h: times DCD dropped */ + unsigned char droppedCTS PACKED; /* 09h: times CTS dropped */ +} THdlcCommErr; + +/* --------------------------------------------------------------------------- + * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands. + */ +typedef struct X25Config +{ + unsigned char baudRate PACKED; /* 00h: */ + unsigned char t1 PACKED; /* 01h: */ + unsigned char t2 PACKED; /* 02h: */ + unsigned char n2 PACKED; /* 03h: */ + unsigned short hdlcMTU PACKED; /* 04h: */ + unsigned char hdlcWindow PACKED; /* 06h: */ + unsigned char t4 PACKED; /* 07h: */ + unsigned char autoModem PACKED; /* 08h: */ + unsigned char autoHdlc PACKED; /* 09h: */ + unsigned char hdlcOptions PACKED; /* 0Ah: */ + unsigned char station PACKED; /* 0Bh: */ + unsigned char pktWindow PACKED; /* 0Ch: */ + unsigned short defPktSize PACKED; /* 0Dh: */ + unsigned short pktMTU PACKED; /* 0Fh: */ + unsigned short loPVC PACKED; /* 11h: */ + unsigned short hiPVC PACKED; /* 13h: */ + unsigned short loIncommingSVC PACKED; /* 15h: */ + unsigned short hiIncommingSVC PACKED; /* 17h: */ + unsigned short loTwoWaySVC PACKED; /* 19h: */ + unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ + unsigned short loOutgoingSVC PACKED; /* 1Dh: */ + unsigned short hiOutgoingSVC PACKED; /* 1Fh: */ + unsigned short options PACKED; /* 21h: */ + unsigned char responseOpt PACKED; /* 23h: */ + unsigned short facil1 PACKED; /* 24h: */ + unsigned short facil2 PACKED; /* 26h: */ + unsigned short ccittFacil PACKED; /* 28h: */ + unsigned short otherFacil PACKED; /* 2Ah: */ + unsigned short ccittCompat PACKED; /* 2Ch: */ + unsigned char t10t20 PACKED; /* 2Eh: */ + unsigned char t11t21 PACKED; /* 2Fh: */ + unsigned char t12t22 PACKED; /* 30h: */ + unsigned char t13t23 PACKED; /* 31h: */ + unsigned char t16t26 PACKED; /* 32H: */ + unsigned char t28 PACKED; /* 33h: */ + unsigned char r10r20 PACKED; /* 34h: */ + unsigned char r12r22 PACKED; /* 35h: */ + unsigned char r13r23 PACKED; /* 36h: */ +} TX25Config; + +/* --------------------------------------------------------------------------- + * X25_READ_CHANNEL_CONFIG Command. + */ +typedef struct X25ChanAlloc /*----- Channel allocation -*/ +{ + unsigned short loPVC PACKED; /* 00h: lowest PVC number */ + unsigned short hiPVC PACKED; /* 02h: highest PVC number */ + unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ + unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ + unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ + unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ + unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ + unsigned short hiOutgoingSVC PACKED; /* 0Eh: highest outgoing SVC */ +} TX25ChanAlloc; + +typedef struct X25ChanCfg /*------ Channel configuration -----*/ +{ + unsigned char type PACKED; /* 00h: channel type */ + unsigned char txConf PACKED; /* 01h: Tx packet and window sizes */ + unsigned char rxConf PACKED; /* 01h: Rx packet and window sizes */ +} TX25ChanCfg; + +/* + * Defines for the 'type' field. + */ +#define X25_PVC 0x01 /* PVC */ +#define X25_SVC_IN 0x03 /* Incoming SVC */ +#define X25_SVC_TWOWAY 0x07 /* Two-way SVC */ +#define X25_SVC_OUT 0x0B /* Outgoing SVC */ + +/*---------------------------------------------------------------------------- + * X25_READ_STATISTICS Command. + */ +typedef struct X25Stats +{ /* number of packets Tx/Rx'ed */ + unsigned short txRestartRqst PACKED; /* 00h: Restart Request */ + unsigned short rxRestartRqst PACKED; /* 02h: Restart Request */ + unsigned short txRestartConf PACKED; /* 04h: Restart Confirmation */ + unsigned short rxRestartConf PACKED; /* 06h: Restart Confirmation */ + unsigned short txResetRqst PACKED; /* 08h: Reset Request */ + unsigned short rxResetRqst PACKED; /* 0Ah: Reset Request */ + unsigned short txResetConf PACKED; /* 0Ch: Reset Confirmation */ + unsigned short rxResetConf PACKED; /* 0Eh: Reset Confirmation */ + unsigned short txCallRequest PACKED; /* 10h: Call Request */ + unsigned short rxCallRequest PACKED; /* 12h: Call Request */ + unsigned short txCallAccept PACKED; /* 14h: Call Accept */ + unsigned short rxCallAccept PACKED; /* 16h: Call Accept */ + unsigned short txClearRqst PACKED; /* 18h: Clear Request */ + unsigned short rxClearRqst PACKED; /* 1Ah: Clear Request */ + unsigned short txClearConf PACKED; /* 1Ch: Clear Confirmation */ + unsigned short rxClearConf PACKED; /* 1Eh: Clear Confirmation */ + unsigned short txDiagnostic PACKED; /* 20h: Diagnostic */ + unsigned short rxDiagnostic PACKED; /* 22h: Diagnostic */ + unsigned short txRegRqst PACKED; /* 24h: Registration Request */ + unsigned short rxRegRqst PACKED; /* 26h: Registration Request */ + unsigned short txRegConf PACKED; /* 28h: Registration Confirm.*/ + unsigned short rxRegConf PACKED; /* 2Ah: Registration Confirm.*/ + unsigned short txInterrupt PACKED; /* 2Ch: Interrupt */ + unsigned short rxInterrupt PACKED; /* 2Eh: Interrupt */ + unsigned short txIntrConf PACKED; /* 30h: Interrupt Confirm. */ + unsigned short rxIntrConf PACKED; /* 32h: Interrupt Confirm. */ + unsigned short txData PACKED; /* 34h: Data */ + unsigned short rxData PACKED; /* 36h: Data */ + unsigned short txRR PACKED; /* 38h: RR */ + unsigned short rxRR PACKED; /* 3Ah: RR */ + unsigned short txRNR PACKED; /* 3Ch: RNR */ + unsigned short rxRNR PACKED; /* 3Eh: RNR */ +} X25Stats; + +/*---------------------------------------------------------------------------- + * X25_READ_HISTORY_TABLE Command. + */ +typedef struct X25EventLog +{ + unsigned char type PACKED; /* 00h: transaction type */ + unsigned short lcn PACKED; /* 01h: logical channel num */ + unsigned char packet PACKED; /* 03h: async packet type */ + unsigned char cause PACKED; /* 04h: X.25 cause field */ + unsigned char diag PACKED; /* 05h: X.25 diag field */ + TX25TimeStamp ts PACKED; /* 06h: time stamp */ +} TX25EventLog; + +/* + * Defines for the 'type' field. + */ +#define X25LOG_INCOMMING 0x00 +#define X25LOG_APPLICATION 0x01 +#define X25LOG_AUTOMATIC 0x02 +#define X25LOG_ERROR 0x04 +#define X25LOG_TIMEOUT 0x08 +#define X25LOG_RECOVERY 0x10 + +/* + * Defines for the 'packet' field. + */ +#define X25LOG_CALL_RQST 0x0B +#define X25LOG_CALL_ACCEPTED 0x0F +#define X25LOG_CLEAR_RQST 0x13 +#define X25LOG_CLEAR_CONFRM 0x17 +#define X25LOG_RESET_RQST 0x1B +#define X25LOG_RESET_CONFRM 0x1F +#define X25LOG_RESTART_RQST 0xFB +#define X25LOG_RESTART_COMFRM 0xFF +#define X25LOG_DIAGNOSTIC 0xF1 +#define X25LOG_DTE_REG_RQST 0xF3 +#define X25LOG_DTE_REG_COMFRM 0xF7 + +/* --------------------------------------------------------------------------- + * X25_TRACE_CONFIGURE Command. + */ +typedef struct X25TraceCfg +{ + unsigned char flags PACKED; /* 00h: trace configuration flags */ + unsigned char timeout PACKED; /* 01h: timeout for trace delay mode*/ +} TX25TraceCfg; + +/* + * Defines for the 'flags' field. + */ +#define X25_TRC_ENABLE 0x01 /* bit0: '1' - trace enabled */ +#define X25_TRC_TIMESTAMP 0x02 /* bit1: '1' - time stamping enabled*/ +#define X25_TRC_DELAY 0x04 /* bit2: '1' - trace delay enabled */ +#define X25_TRC_DATA 0x08 /* bit3: '1' - trace data packets */ +#define X25_TRC_SUPERVISORY 0x10 /* bit4: '1' - trace suprvisory pkts*/ +#define X25_TRC_ASYNCHRONOUS 0x20 /* bit5: '1' - trace asynch. packets*/ +#define X25_TRC_HDLC 0x40 /* bit6: '1' - trace all packets */ +#define X25_TRC_READ 0x80 /* bit7: '1' - get current config. */ + +/* --------------------------------------------------------------------------- + * X25_READ_TRACE_DATA Command. + */ +typedef struct X25Trace /*----- Trace data structure -------*/ +{ + unsigned short length PACKED; /* 00h: trace data length */ + unsigned char type PACKED; /* 02h: trace type */ + unsigned char lost_cnt PACKED; /* 03h: N of traces lost */ + TX25TimeStamp tstamp PACKED; /* 04h: mon/date/sec/min/hour */ + unsigned short millisec PACKED; /* 09h: ms time stamp */ + unsigned char data[0] PACKED; /* 0Bh: traced frame */ +} TX25Trace; + +/* + * Defines for the 'type' field. + */ +#define X25_TRC_TYPE_MASK 0x0F /* bits 0..3: trace type */ +#define X25_TRC_TYPE_RX_FRAME 0x00 /* received frame trace */ +#define X25_TRC_TYPE_TX_FRAME 0x01 /* transmitted frame */ +#define X25_TRC_TYPE_ERR_FRAME 0x02 /* error frame */ + +#define X25_TRC_ERROR_MASK 0xF0 /* bits 4..7: error code */ +#define X25_TRCERR_RX_ABORT 0x10 /* receive abort error */ +#define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ +#define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ +#define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ +#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ +#define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ + +/***************************************************************************** + * Following definitions describe HDLC frame and X.25 packet formats. + ****************************************************************************/ + +typedef struct HDLCFrame /*----- DHLC Frame Format ----------*/ +{ + unsigned char addr PACKED; /* address field */ + unsigned char cntl PACKED; /* control field */ + unsigned char data[0] PACKED; +} THDLCFrame; + +typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ +{ + unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ + unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ + unsigned char type PACKED; + unsigned char data[0] PACKED; +} TX25Pkt; + +/* + * Defines for the 'lcn_hi' field. + */ +#define X25_Q_BIT_MASK 0x80 /* Data Qualifier Bit mask */ +#define X25_D_BIT_MASK 0x40 /* Delivery Confirmation Bit mask */ +#define X25_M_BITS_MASK 0x30 /* Modulo Bits mask */ +#define X25_LCN_MSB_MASK 0x0F /* LCN most significant bits mask */ + +/* + * Defines for the 'type' field. + */ +#define X25PKT_DATA 0x01 /* Data packet mask */ +#define X25PKT_SUPERVISORY 0x02 /* Supervisory packet mask */ +#define X25PKT_CALL_RQST 0x0B /* Call Request/Incoming */ +#define X25PKT_CALL_ACCEPTED 0x0F /* Call Accepted/Connected */ +#define X25PKT_CLEAR_RQST 0x13 /* Clear Request/Indication */ +#define X25PKT_CLEAR_CONFRM 0x17 /* Clear Confirmation */ +#define X25PKT_RESET_RQST 0x1B /* Reset Request/Indication */ +#define X25PKT_RESET_CONFRM 0x1F /* Reset Confirmation */ +#define X25PKT_RESTART_RQST 0xFB /* Restart Request/Indication */ +#define X25PKT_RESTART_CONFRM 0xFF /* Restart Confirmation */ +#define X25PKT_INTERRUPT 0x23 /* Interrupt */ +#define X25PKT_INTERRUPT_CONFRM 0x27 /* Interrupt Confirmation */ +#define X25PKT_DIAGNOSTIC 0xF1 /* Diagnostic */ +#define X25PKT_REGISTR_RQST 0xF3 /* Registration Request */ +#define X25PKT_REGISTR_CONFRM 0xF7 /* Registration Confirmation */ +#define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */ +#define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */ + +#ifdef _MSC_ +# pragma pack() +#endif +#endif /* _SDLA_X25_H */ diff -u --recursive --new-file v2.1.24/linux/include/linux/sdladrv.h linux/include/linux/sdladrv.h --- v2.1.24/linux/include/linux/sdladrv.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/sdladrv.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,61 @@ +/***************************************************************************** +* sdladrv.h SDLA Support Module. Kernel API Definitions. +* +* Author: Gene Kozin +* +* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Dec 11, 1996 Gene Kozin Complete overhaul. +* Oct 17, 1996 Gene Kozin Minor bug fixes. +* Jun 12, 1996 Gene Kozin Added support for S503 card. +* Dec 06, 1995 Gene Kozin Initial version. +*****************************************************************************/ +#ifndef _SDLADRV_H +#define _SDLADRV_H + +#define SDLA_MAXIORANGE 4 /* maximum I/O port range */ +#define SDLA_WINDOWSIZE 0x2000 /* default dual-port memory window size */ + +/****** Data Structures *****************************************************/ + +/*---------------------------------------------------------------------------- + * Adapter hardware configuration. Pointer to this structure is passed to all + * APIs. + */ +typedef struct sdlahw +{ + unsigned type; /* adapter type */ + unsigned fwid; /* firmware ID */ + unsigned port; /* adapter I/O port base */ + int irq; /* interrupt request level */ + unsigned long dpmbase; /* dual-port memory base */ + unsigned dpmsize; /* dual-port memory size */ + unsigned pclk; /* CPU clock rate, kHz */ + unsigned long memory; /* memory size */ + unsigned long vector; /* local offset of the DPM window */ + unsigned io_range; /* I/O port range */ + unsigned char regs[SDLA_MAXIORANGE]; /* was written to registers */ + unsigned reserved[5]; +} sdlahw_t; + +/****** Function Prototypes *************************************************/ + +extern int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len); +extern int sdla_down (sdlahw_t* hw); +extern int sdla_inten (sdlahw_t* hw); +extern int sdla_intde (sdlahw_t* hw); +extern int sdla_intack (sdlahw_t* hw); +extern int sdla_intr (sdlahw_t* hw); +extern int sdla_mapmem (sdlahw_t* hw, unsigned long addr); +extern int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, + unsigned len); +extern int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, + unsigned len); +extern int sdla_exec (void* opflag); + +#endif /* _SDLADRV_H */ diff -u --recursive --new-file v2.1.24/linux/include/linux/sdlasfm.h linux/include/linux/sdlasfm.h --- v2.1.24/linux/include/linux/sdlasfm.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/sdlasfm.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,92 @@ +/***************************************************************************** +* sdlasfm.h WANPIPE(tm) Multiprotocol WAN Link Driver. +* Definitions for the SDLA Firmware Module (SFM). +* +* Author: Gene Kozin <74604.152@compuserve.com> +* +* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Dec 11, 1996 Gene Kozin Cosmetic changes +* Apr 16, 1996 Gene Kozin Changed adapter & firmware IDs. Version 2 +* Dec 15, 1995 Gene Kozin Structures chaned +* Nov 09, 1995 Gene Kozin Initial version. +*****************************************************************************/ +#ifndef _SDLASFM_H +#define _SDLASFM_H + +/****** Defines *************************************************************/ + +#define SFM_VERSION 2 +#define SFM_SIGNATURE "SFM - Sangoma SDLA Firmware Module" + +/* min/max */ +#define SFM_IMAGE_SIZE 0x8000 /* max size of SDLA code image file */ +#define SFM_DESCR_LEN 256 /* max length of description string */ +#define SFM_MAX_SDLA 16 /* max number of compatible adapters */ + +/* Adapter types */ +#define SDLA_S502A 5020 +#define SDLA_S502E 5021 +#define SDLA_S503 5030 +#define SDLA_S508 5080 +#define SDLA_S507 5070 +#define SDLA_S509 5090 + +/* Firmware identification numbers: + * 0 .. 999 Test & Diagnostics + * 1000 .. 1999 Streaming HDLC + * 2000 .. 2999 Bisync + * 3000 .. 3999 SDLC + * 4000 .. 4999 HDLC + * 5000 .. 5999 X.25 + * 6000 .. 6999 Frame Relay + * 7000 .. 7999 PPP + */ +#define SFID_CALIB502 200 +#define SFID_STRM502 1200 +#define SFID_STRM508 1800 +#define SFID_BSC502 2200 +#define SFID_SDLC502 3200 +#define SFID_HDLC502 4200 +#define SFID_X25_502 5200 +#define SFID_X25_508 5800 +#define SFID_FR502 6200 +#define SFID_FR508 6800 +#define SFID_PPP502 7200 +#define SFID_PPP508 7800 + +/****** Data Types **********************************************************/ + +typedef struct sfm_info /* firmware module information */ +{ + unsigned short codeid; /* firmware ID */ + unsigned short version; /* firmaware version number */ + unsigned short adapter[SFM_MAX_SDLA]; /* compatible adapter types */ + unsigned long memsize; /* minimum memory size */ + unsigned short reserved[2]; /* reserved */ + unsigned short startoffs; /* entry point offset */ + unsigned short winoffs; /* dual-port memory window offset */ + unsigned short codeoffs; /* code load offset */ + unsigned short codesize; /* code size */ + unsigned short dataoffs; /* configuration data load offset */ + unsigned short datasize; /* configuration data size */ +} sfm_info_t; + +typedef struct sfm /* SDLA firmware file structire */ +{ + char signature[80]; /* SFM file signature */ + unsigned short version; /* file format version */ + unsigned short checksum; /* info + image */ + unsigned short reserved[6]; /* reserved */ + char descr[SFM_DESCR_LEN]; /* description string */ + sfm_info_t info; /* firmware module info */ + unsigned char image[1]; /* code image (variable size) */ +} sfm_t; + +#endif /* _SDLASFM_H */ + diff -u --recursive --new-file v2.1.24/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.24/linux/include/linux/socket.h Thu Jan 23 21:06:52 1997 +++ linux/include/linux/socket.h Sun Feb 2 15:18:47 1997 @@ -74,7 +74,22 @@ (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; diff -u --recursive --new-file v2.1.24/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.24/linux/include/linux/sysctl.h Thu Jan 23 21:06:52 1997 +++ linux/include/linux/sysctl.h Sun Feb 2 15:18:47 1997 @@ -138,7 +138,6 @@ NET_NETROM_TRANSPORT_BUSY_DELAY, NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE, NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT, - NET_NETROM_TRANSPORT_PACKET_LENGTH, NET_NETROM_ROUTING_CONTROL, NET_NETROM_LINK_FAILS_COUNT }; @@ -154,7 +153,8 @@ 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 */ diff -u --recursive --new-file v2.1.24/linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h --- v2.1.24/linux/include/linux/tty_ldisc.h Tue Jan 28 18:50:56 1997 +++ linux/include/linux/tty_ldisc.h Sun Feb 2 16:39:28 1997 @@ -64,13 +64,12 @@ * This function notifies the line discpline that a change has * been made to the termios stucture. * - * int (*select)(struct tty_struct * tty, struct inode * inode, - * struct file * file, int sel_type, - * struct select_table_struct *wait); + * int (*poll)(struct tty_struct * tty, struct file * file, + * poll_table *wait); * - * This function is called when a user attempts to select on a + * This function is called when a user attempts to select/poll on a * tty device. It is solely the responsibility of the line - * discipline to handle select requests. + * discipline to handle poll requests. * * void (*receive_buf)(struct tty_struct *, const unsigned char *cp, * char *fp, int count); diff -u --recursive --new-file v2.1.24/linux/include/linux/wanpipe.h linux/include/linux/wanpipe.h --- v2.1.24/linux/include/linux/wanpipe.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/wanpipe.h Sun Feb 2 15:18:47 1997 @@ -0,0 +1,131 @@ +/***************************************************************************** +* wanpipe.h WANPIPE(tm) Multiprotocol WAN Link Driver. +* User-level API definitions. +* +* Author: Gene Kozin +* +* 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 + +/* 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 /* SDLA support module API definitions */ +#include /* SDLA firmware module definitions */ + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0) +#define is_alpha(ch) ((((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'z')||\ + ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'Z'))?1:0) +#define is_hex_digit(ch) ((((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')||\ + ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\ + ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0) + +/****** Data Structures *****************************************************/ + +/* Adapter Data Space. + * This structure is needed because we handle multiple cards, otherwise + * static data would do it. + */ +typedef struct sdla +{ + char devname[WAN_DRVNAME_SZ+1]; /* card name */ + sdlahw_t hw; /* hardware configuration */ + wan_device_t wandev; /* WAN device data space */ + unsigned open_cnt; /* number of open interfaces */ + unsigned long state_tick; /* link state timestamp */ + char in_isr; /* interrupt-in-service flag */ + void* mbox; /* -> mailbox */ + void* rxmb; /* -> receive mailbox */ + void* flags; /* -> adapter status flags */ + void (*isr)(struct sdla* card); /* interrupt service routine */ + void (*poll)(struct sdla* card); /* polling routine */ + int (*exec)(struct sdla* card, void* u_cmd, void* u_data); + union + { + struct + { /****** X.25 specific data **********/ + unsigned lo_pvc; + unsigned hi_pvc; + unsigned lo_svc; + unsigned hi_svc; + } x; + struct + { /****** frame relay specific data ***/ + void* rxmb_base; /* -> first Rx buffer */ + void* rxmb_last; /* -> last Rx buffer */ + unsigned rx_base; /* S508 receive buffer base */ + unsigned rx_top; /* S508 receive buffer end */ + unsigned short node_dlci; + unsigned short dlci_num; + } f; + struct /****** PPP-specific data ***********/ + { + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + void* txbuf; /* -> current Tx buffer */ + void* txbuf_base; /* -> first Tx buffer */ + void* txbuf_last; /* -> last Tx buffer */ + void* rxbuf_base; /* -> first Rx buffer */ + void* rxbuf_last; /* -> last Rx buffer */ + unsigned rx_base; /* S508 receive buffer base */ + unsigned rx_top; /* S508 receive buffer end */ + } p; + } u; +} sdla_t; + +/****** Public Functions ****************************************************/ + +void wanpipe_open (sdla_t* card); /* wpmain.c */ +void wanpipe_close (sdla_t* card); /* wpmain.c */ +void wanpipe_set_state (sdla_t* card, int state); /* wpmain.c */ + +int wpx_init (sdla_t* card, wandev_conf_t* conf); /* wpx.c */ +int wpf_init (sdla_t* card, wandev_conf_t* conf); /* wpf.c */ +int wpp_init (sdla_t* card, wandev_conf_t* conf); /* wpp.c */ + +#endif /* __KERNEL__ */ +#endif /* _WANPIPE_H */ + diff -u --recursive --new-file v2.1.24/linux/include/linux/wanrouter.h linux/include/linux/wanrouter.h --- v2.1.24/linux/include/linux/wanrouter.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/wanrouter.h Sun Feb 2 16:47:01 1997 @@ -0,0 +1,332 @@ +/***************************************************************************** +* wanrouter.h Definitions for the WAN Multiprotocol Router Module. +* This module provides API and common services for WAN Link +* Drivers and is completely hardware-independent. +* +* Author: Gene Kozin +* +* 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/ 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 /* support for device drivers */ +#include /* proc filesystem pragmatics */ +#include /* in_aton(), in_ntoa() prototypes */ +#include /* 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 */ diff -u --recursive --new-file v2.1.24/linux/include/net/ax25.h linux/include/net/ax25.h --- v2.1.24/linux/include/net/ax25.h Thu Jan 23 21:06:52 1997 +++ linux/include/net/ax25.h Sun Feb 2 16:41:47 1997 @@ -118,7 +118,7 @@ #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 */ @@ -135,7 +135,7 @@ #define AX25_DEF_IPDEFMODE 0 /* Datagram */ #define AX25_DEF_AXDEFMODE 0 /* Normal */ #define AX25_DEF_TEXT 1 /* PID=Text allowed */ -#define AX25_DEF_BACKOFF 1 /* Exponential backoff */ +#define AX25_DEF_BACKOFF 1 /* Linear backoff */ #define AX25_DEF_CONMODE 1 /* Connected mode allowed */ #define AX25_DEF_WINDOW 2 /* Window=2 */ #define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */ @@ -197,7 +197,7 @@ extern char *ax2asc(ax25_address *); extern ax25_address *asc2ax(char *); extern int ax25cmp(ax25_address *, ax25_address *); -extern int ax25_send_frame(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *, struct device *); +extern int ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *); extern int ax25_link_up(ax25_address *, ax25_address *, struct device *); extern void ax25_destroy_socket(ax25_cb *); extern struct device *ax25rtr_get_dev(ax25_address *); @@ -216,7 +216,7 @@ extern int ax25_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 *); diff -u --recursive --new-file v2.1.24/linux/include/net/netrom.h linux/include/net/netrom.h --- v2.1.24/linux/include/net/netrom.h Thu Jan 23 21:06:52 1997 +++ linux/include/net/netrom.h Sun Feb 2 15:18:47 1997 @@ -10,9 +10,6 @@ #define NR_SLOWHZ 10 /* Run timing at 1/10 second */ -#define NR_T1CLAMPLO (1 * NR_SLOWHZ) /* If defined, clamp at 1 second **/ -#define NR_T1CLAMPHI (300 * NR_SLOWHZ) /* If defined, clamp at 30 seconds **/ - #define NR_NETWORK_LEN 15 #define NR_TRANSPORT_LEN 5 @@ -51,12 +48,13 @@ #define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */ #define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */ #define NR_DEFAULT_TTL 16 /* Default Time To Live - 16 */ -#define NR_MODULUS 256 -#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */ -#define NR_DEFAULT_PACLEN 236 /* Default Packet Length - 236 */ #define NR_DEFAULT_ROUTING 1 /* Is routing enabled ? */ #define NR_DEFAULT_FAILS 2 /* Link fails until route fails */ +#define NR_MODULUS 256 +#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */ +#define NR_MAX_PACKET_SIZE 236 /* Maximum Packet Length - 236 */ + typedef struct { ax25_address user_addr, source_addr, dest_addr; struct device *device; @@ -65,9 +63,9 @@ unsigned char state, condition, bpqext, hdrincl, window; unsigned short vs, vr, va, vl; unsigned char n2, n2count; - unsigned short t1, t2, t4, idle, rtt; + unsigned short t1, t2, t4, idle; unsigned short t1timer, t2timer, t4timer, idletimer; - unsigned short fraglen, paclen; + unsigned short fraglen; struct sk_buff_head ack_queue; struct sk_buff_head reseq_queue; struct sk_buff_head frag_queue; @@ -95,7 +93,7 @@ struct nr_node { struct nr_node *next; ax25_address callsign; - char mnemonic[7]; + char mnemonic[7]; unsigned char which; unsigned char count; struct nr_route routes[3]; @@ -111,7 +109,6 @@ extern int sysctl_netrom_transport_busy_delay; extern int sysctl_netrom_transport_requested_window_size; extern int sysctl_netrom_transport_no_activity_timeout; -extern int sysctl_netrom_transport_packet_length; extern int sysctl_netrom_routing_control; extern int sysctl_netrom_link_fails_count; extern int nr_rx_frame(struct sk_buff *, struct device *); @@ -154,8 +151,6 @@ extern int nr_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 *); diff -u --recursive --new-file v2.1.24/linux/include/net/rose.h linux/include/net/rose.h --- v2.1.24/linux/include/net/rose.h Thu Jan 23 21:06:52 1997 +++ linux/include/net/rose.h Sun Feb 2 15:18:47 1997 @@ -52,10 +52,12 @@ #define ROSE_DEFAULT_T3 (180 * ROSE_SLOWHZ) /* Default T13 T23 value */ #define ROSE_DEFAULT_HB (5 * ROSE_SLOWHZ) /* Default Holdback value */ #define ROSE_DEFAULT_IDLE (20 * 60 * ROSE_SLOWHZ) /* Default No Activity value */ -#define ROSE_DEFAULT_WINDOW 2 /* Default Window Size */ +#define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */ +#define ROSE_DEFAULT_FAIL_TIMEOUT (120 * ROSE_SLOWHZ) /* Time until link considered usable */ + #define ROSE_MODULUS 8 -#define ROSE_MAX_WINDOW_SIZE 7 /* Maximum Window Allowable */ -#define ROSE_PACLEN 128 /* Default Packet Length */ +#define ROSE_MAX_WINDOW_SIZE 2 /* Maximum Window Allowable */ +#define ROSE_MAX_PACKET_SIZE 128 /* Maximum Packet Length */ #define ROSE_COND_ACK_PENDING 0x01 #define ROSE_COND_PEER_RX_BUSY 0x02 @@ -81,7 +83,7 @@ unsigned int number; int restarted; struct sk_buff_head queue; - unsigned short t0, t0timer; + unsigned short t0timer, ftimer; struct timer_list timer; }; @@ -89,7 +91,6 @@ struct rose_node *next; rose_address address; unsigned short mask; - unsigned char which; unsigned char count; struct rose_neigh *neighbour[3]; }; @@ -127,6 +128,7 @@ extern int sysctl_rose_no_activity_timeout; extern int sysctl_rose_ack_hold_back_timeout; extern int sysctl_rose_routing_control; +extern int sysctl_rose_link_fail_timeout; extern int rosecmp(rose_address *, rose_address *); extern int rosecmpm(rose_address *, rose_address *, unsigned short); extern char *rose2asc(rose_address *); @@ -145,6 +147,7 @@ extern int rose_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 *); diff -u --recursive --new-file v2.1.24/linux/init/main.c linux/init/main.c --- v2.1.24/linux/init/main.c Tue Jan 28 18:50:56 1997 +++ linux/init/main.c Sun Feb 2 15:53:10 1997 @@ -710,6 +710,7 @@ } if (checksetup(line)) continue; + /* * Then check if it's an environment variable or * an option. diff -u --recursive --new-file v2.1.24/linux/kernel/module.c linux/kernel/module.c --- v2.1.24/linux/kernel/module.c Tue Jan 28 18:50:57 1997 +++ linux/kernel/module.c Wed Jan 29 13:40:34 1997 @@ -583,7 +583,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.24/linux/kernel/sched.c Sun Feb 2 15:46:21 1997 +++ linux/kernel/sched.c Sun Feb 2 17:46:41 1997 @@ -1262,64 +1262,81 @@ * 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; - - lock_kernel(); - ret = current->p_opptr->pid; - unlock_kernel(); - return ret; + int pid; + struct task_struct * me = current; + struct task_struct * parent; + + parent = me->p_opptr; + for (;;) { + pid = parent->pid; +#if __SMP__ +{ + struct task_struct *old = parent; + mb(); + parent = me->p_opptr; + if (old != parent) + continue; +} +#endif + break; + } + return pid; } asmlinkage int sys_getuid(void) { - int ret; - - lock_kernel(); - ret = current->uid; - unlock_kernel(); - return ret; + /* Only we change this so SMP safe */ + return current->uid; } asmlinkage int sys_geteuid(void) { - int ret; - - lock_kernel(); - ret = current->euid; - unlock_kernel(); - return ret; + /* Only we change this so SMP safe */ + return current->euid; } asmlinkage int sys_getgid(void) { - int ret; - - lock_kernel(); - ret = current->gid; - unlock_kernel(); - return ret; + /* Only we change this so SMP safe */ + return current->gid; } asmlinkage int sys_getegid(void) { - int ret; - - lock_kernel(); - ret = current->egid; - unlock_kernel(); - return ret; + /* Only we change this so SMP safe */ + return current->egid; } /* @@ -1327,12 +1344,17 @@ * 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) { diff -u --recursive --new-file v2.1.24/linux/kernel/sys.c linux/kernel/sys.c --- v2.1.24/linux/kernel/sys.c Tue Jan 28 18:50:57 1997 +++ linux/kernel/sys.c Sun Feb 2 17:32:31 1997 @@ -766,12 +766,8 @@ asmlinkage int sys_getpgrp(void) { - int ret; - - lock_kernel(); - ret = current->pgrp; - unlock_kernel(); - return ret; + /* SMP - assuming writes are word atomic this is fine */ + return current->pgrp; } asmlinkage int sys_getsid(pid_t pid) @@ -779,10 +775,12 @@ struct task_struct * p; int ret; - lock_kernel(); + /* SMP: The 'self' case requires no lock */ if (!pid) { ret = current->session; } else { + /* Walking the process table needs locks */ + lock_kernel(); for_each_task(p) { if (p->pid == pid) { ret = p->session; @@ -790,9 +788,9 @@ } } ret = -ESRCH; - } out: - unlock_kernel(); + unlock_kernel(); + } return ret; } @@ -1117,11 +1115,7 @@ 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; } diff -u --recursive --new-file v2.1.24/linux/net/Config.in linux/net/Config.in --- v2.1.24/linux/net/Config.in Thu Jan 2 15:55:26 1997 +++ linux/net/Config.in Sun Feb 2 15:18:48 1997 @@ -26,6 +26,9 @@ fi fi tristate 'Appletalk DDP' CONFIG_ATALK +if [ "$CONFIG_ATALK" != "n" ]; then + bool 'IP-over-DDP support (EXPERIMENTAL)' CONFIG_IPDDP +fi tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25 if [ "$CONFIG_AX25" != "n" ]; then dep_tristate 'Amateur Radio NET/ROM' CONFIG_NETROM $CONFIG_AX25 @@ -36,5 +39,6 @@ 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 diff -u --recursive --new-file v2.1.24/linux/net/Makefile linux/net/Makefile --- v2.1.24/linux/net/Makefile Wed Jan 15 19:45:47 1997 +++ linux/net/Makefile Sun Feb 2 15:18:48 1997 @@ -9,7 +9,7 @@ MOD_SUB_DIRS := ipv4 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ - netrom rose lapb x25 #decnet + netrom rose lapb x25 wanrouter #decnet SUB_DIRS := core ethernet unix MOD_LIST_NAME := NET_MISC_MODULES @@ -46,6 +46,14 @@ else ifeq ($(CONFIG_ATALK),m) MOD_SUB_DIRS += appletalk + endif +endif + +ifeq ($(CONFIG_WAN_ROUTER),y) +SUB_DIRS += wanrouter +else + ifeq ($(CONFIG_WAN_ROUTER),m) + MOD_SUB_DIRS += wanrouter endif endif diff -u --recursive --new-file v2.1.24/linux/net/README linux/net/README --- v2.1.24/linux/net/README Thu Jan 2 15:55:26 1997 +++ linux/net/README Sun Feb 2 15:18:48 1997 @@ -14,6 +14,7 @@ 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 diff -u --recursive --new-file v2.1.24/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c --- v2.1.24/linux/net/appletalk/aarp.c Thu Jan 2 15:55:26 1997 +++ linux/net/appletalk/aarp.c Sun Feb 2 15:18:48 1997 @@ -441,9 +441,11 @@ * 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); /* diff -u --recursive --new-file v2.1.24/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.24/linux/net/appletalk/ddp.c Sun Feb 2 15:46:21 1997 +++ linux/net/appletalk/ddp.c Sun Feb 2 15:18:48 1997 @@ -23,6 +23,7 @@ * Alan Cox : Hooks for PPP (based on the * localtalk hook). * Alan Cox : Posix bits + * Bradford Johnson : IP-over-DDP (experimental) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -59,6 +60,8 @@ #include #include #include +#include +#include #include #include #include @@ -163,6 +166,7 @@ extern inline void atalk_destroy_socket(struct sock *sk) { sklist_destroy_socket(&atalk_socket_list,sk); + MOD_DEC_USE_COUNT; } /* @@ -1109,10 +1113,15 @@ if(addr->sat_family!=AF_APPLETALK) return -EAFNOSUPPORT; -#if 0 /* Netatalk doesn't check this - fix netatalk first!*/ if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) + { +#if 1 + printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n", + current->comm); +#else return -EACCES; -#endif +#endif + } if(sk->zapped) { if(atalk_autobind(sk)<0) @@ -1191,6 +1200,208 @@ return(0); } +/* + * IP-over-DDP support. Under construction. + */ + +#ifdef CONFIG_IPDDP + +#define SIOCADDIPDDPRT SIOCDEVPRIVATE +#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1 +#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2 + +struct ipddp_route { + struct device *dev; /* Carrier device */ + __u32 ip; /* IP address */ + struct at_addr at; /* Gateway appletalk address */ + int flags; + struct ipddp_route *next; +}; + +static struct ipddp_route *ipddp_route_head; + +static struct ipddp_route ipddp_route_test; + +int ipddp_open(struct device *dev) +{ + MOD_INC_USE_COUNT; + return 0; +} + +int ipddp_close(struct device *dev) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +int ipddp_xmit(struct sk_buff *skb, struct device *dev) +{ + /* Retrieve the saved address hint */ + struct at_addr *a=(struct at_addr *)skb->data; + skb_pull(skb,4); + + ((struct net_device_stats *) dev->priv)->tx_packets++; + + /* printk("ipddp_xmit called with headroom %d\n",skb_headroom(skb)); */ + + if( aarp_send_ddp(skb->dev,skb,a,NULL) < 0 ) + dev_kfree_skb(skb,FREE_WRITE); + + return 0; +} + +struct net_device_stats *ipddp_get_stats(struct device *dev) +{ + return (struct enet_statistics *) dev->priv; +} + +int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data; + + if(!suser()) + return -EPERM; + + /* for now we only have one route at a time */ + + switch(cmd) + { + case SIOCADDIPDDPRT: + if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route))) + return -EFAULT; + ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at); + if (dev==NULL) + return -ENETUNREACH; + ipddp_route_test.next = NULL; + printk("added ipddp route through %s\n",ipddp_route_test.dev->name); + ipddp_route_head = &ipddp_route_test; + return 0; + case SIOCFINDIPDDPRT: + if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route))) + return -EFAULT; + return 0; + case SIOCDELIPDDPRT: + ipddp_route_test.dev = NULL; + ipddp_route_head = NULL; + return 0; + default: + return -EINVAL; + } +} + +int ipddp_header (struct sk_buff *skb, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ + /* printk("ipddp_header\n"); */ + /* Push down the header space and the type byte */ + skb_push(skb, sizeof(struct ddpehdr)+1+4); + return 0; +} + +/* + * Now the packet really wants to go out. + */ + +int ipddp_rebuild_header (struct sk_buff *skb) +{ + struct ddpehdr *ddp; + struct at_addr at; + struct ipddp_route *rt; + struct at_addr *our_addr; + u32 paddr = ((struct rtable *)skb->dst)->rt_gateway; + + /* + * On entry skb->data points to the ddpehdr we reserved earlier. + * skb->h.raw will be the higher level header. + */ + + /* + * We created this earlier + */ + + ddp = (struct ddpehdr *) (skb->data+4); + + /* find appropriate route */ + + for(rt=ipddp_route_head;rt;rt=rt->next) + { + if(rt->ip == paddr) + break; + } + + if(!rt) { + printk("ipddp unreachable dst %08lx\n",ntohl(paddr)); + return -ENETUNREACH; + } + + our_addr = atalk_find_dev_addr(rt->dev); + + /* fill in ddpehdr */ + ddp->deh_len = skb->len; + ddp->deh_hops = 1; + ddp->deh_pad = 0; + ddp->deh_sum = 0; + ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ + ddp->deh_snet = our_addr->s_net; + ddp->deh_dnode = rt->at.s_node; + ddp->deh_snode = our_addr->s_node; + ddp->deh_dport = 72; + ddp->deh_sport = 72; + + *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ + + /* fix up length field */ + *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); + + /* set skb->dev to appropriate device */ + skb->dev = rt->dev; + + /* skb->raddr = (unsigned long) at */ + at = rt->at; + /* Hide it at the start of the buffer */ + memcpy(skb->data,(void *)&at,sizeof(at)); + skb->arp = 1; /* so the actual device doesn't try to arp it... */ + skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ + + return 0; +} + +int ipddp_init (struct device *dev) +{ + ether_setup(dev); + dev->hard_start_xmit = ipddp_xmit; + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + if(!dev->priv) + return -ENOMEM; + memset(dev->priv,0,sizeof(struct enet_statistics)); + dev->get_stats = ipddp_get_stats; + dev->do_ioctl = ipddp_ioctl; + dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ + dev->family = AF_INET; + dev->mtu = 585; + dev->flags |= IFF_NOARP; + dev->hard_header = ipddp_header; /* see ip_output.c */ + dev->rebuild_header = ipddp_rebuild_header; + /* + * The worst case header we will need is currently a + * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) + * We send over SNAP so that takes another 8 bytes. + */ + dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; + dev->open = ipddp_open; + dev->stop = ipddp_close; + + return 0; +} + +static struct device dev_ipddp = { + "ipddp0\0 ", + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NULL, ipddp_init }; + +#endif /* CONFIG_IPDDP */ + /* * Receive a packet (in skb) from device dev. This has come from the SNAP decoder, and on entry * skb->h.raw is the DDP header, skb->len is the DDP length. The physical headers have been @@ -1349,18 +1560,38 @@ tosat.sat_port = ddp->deh_dport; sock=atalk_search_socket( &tosat, atif ); - + if(sock==NULL) /* But not one of our sockets */ { kfree_skb(skb,FREE_READ); return(0); } +#ifdef CONFIG_IPDDP + /* + * Check if IP-over-DDP + */ + if(skb->data[12]==22) { + struct enet_statistics *estats = + (struct enet_statistics *) dev_ipddp.priv; + skb->protocol=htons(ETH_P_IP); + skb_pull(skb,13); + skb->dev=&dev_ipddp; + skb->h.raw = skb->data; + /* printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]); + * printk("tot_len %d, skb->len %d\n", + * ntohs(skb->h.iph->tot_len),skb->len); + */ + estats->rx_packets++; + netif_rx(skb); + return 0; + } +#endif /* CONFIG_IPDDP */ /* * Queue packet (standard) */ - + skb->sk = sock; if(sock_queue_rcv_skb(sock,skb)<0) @@ -1468,8 +1699,10 @@ return(-EINVAL); if(usat->sat_family != AF_APPLETALK) return -EINVAL; +#if 0 /* netatalk doesn't implement this check */ if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) return -EPERM; +#endif } else { @@ -1848,7 +2081,11 @@ 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"); } diff -u --recursive --new-file v2.1.24/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.24/linux/net/ax25/af_ax25.c Sun Feb 2 15:46:22 1997 +++ linux/net/ax25/af_ax25.c Sun Feb 2 15:18:48 1997 @@ -138,7 +138,7 @@ */ ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; -ax25_cb *ax25_list = NULL; +ax25_cb *volatile ax25_list = NULL; static struct proto_ops ax25_proto_ops; @@ -416,7 +416,6 @@ * Find an AX.25 control block given both ends. It will only pick up * floating AX.25 control blocks or non Raw socket bound control blocks. */ - static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev) { ax25_cb *s; @@ -477,10 +476,8 @@ if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) return; - skb_set_owner_r(copy, sk); - skb_queue_tail(&sk->receive_queue, copy); - if (!sk->dead) - sk->data_ready(sk, skb->len); + if (sock_queue_rcv_skb(sk, copy) != 0) + kfree_skb(copy, FREE_READ); } sk = sk->next; @@ -532,7 +529,7 @@ } if (ax25->sk != NULL) { - if (ax25->sk->wmem_alloc || ax25->sk->rmem_alloc) { /* Defer: outstanding buffers */ + if (ax25->sk->wmem_alloc > 0 || ax25->sk->rmem_alloc > 0) { /* Defer: outstanding buffers */ init_timer(&ax25->timer); ax25->timer.expires = jiffies + 10 * HZ; ax25->timer.function = ax25_destroy_timer; @@ -841,7 +838,7 @@ ax25->backoff = ax25_dev_get_value(dev, AX25_VALUES_BACKOFF); } -int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest, +int ax25_send_frame(struct sk_buff *skb, int fragment, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev) { ax25_cb *ax25; @@ -860,7 +857,7 @@ if (ax25_queue_length(ax25, skb) > ax25->maxqueue * ax25->window) { kfree_skb(skb, FREE_WRITE); } else { - ax25_output(ax25, skb); + ax25_output(ax25, fragment, skb); } ax25->idletimer = ax25->idle; return 1; /* It already existed */ @@ -900,7 +897,7 @@ ax25_set_timer(ax25); - ax25_output(ax25, skb); + ax25_output(ax25, fragment, skb); return 1; /* We had to create it */ } @@ -1004,7 +1001,9 @@ return 0; case AX25_BACKOFF: - sk->protinfo.ax25->backoff = opt ? 1 : 0; + if (opt < 0 || opt > 2) + return -EINVAL; + sk->protinfo.ax25->backoff = opt; return 0; case AX25_EXTSEQ: @@ -1097,7 +1096,7 @@ if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0) return err; - put_user(val, (int *) optval); + put_user(val, (int *)optval); return 0; } @@ -1171,12 +1170,11 @@ return -ENOMEM; } - sock_init_data(sock,sk); + sock_init_data(sock, sk); - sock->ops = &ax25_proto_ops; - - sk->protocol = protocol; - sk->mtu = AX25_MTU; /* 256 */ + sock->ops = &ax25_proto_ops; + sk->protocol = protocol; + sk->mtu = AX25_MTU; /* 256 */ ax25->sk = sk; sk->protinfo.ax25 = ax25; @@ -1199,9 +1197,6 @@ ax25_fillin_cb(ax25, dev); - sk->type = osk->type; - sk->socket = osk->socket; - switch (osk->type) { case SOCK_DGRAM: break; @@ -1213,17 +1208,19 @@ return NULL; } - sock_init_data(NULL,sk); + sock_init_data(NULL, sk); - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->mtu = osk->mtu; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; + sk->type = osk->type; + sk->socket = osk->socket; + sk->priority = osk->priority; + sk->protocol = osk->protocol; + sk->rcvbuf = osk->rcvbuf; + sk->sndbuf = osk->sndbuf; + sk->debug = osk->debug; + sk->state = TCP_ESTABLISHED; + sk->mtu = osk->mtu; + sk->sleep = osk->sleep; + sk->zapped = osk->zapped; ax25->modulus = osk->protinfo.ax25->modulus; ax25->backoff = osk->protinfo.ax25->backoff; @@ -1461,7 +1458,7 @@ } else { sk->protinfo.ax25->digipeat->repeated[ct] = 0; } - sk->protinfo.ax25->digipeat->calls[ct] = fsa->fsa_digipeater[ct]; + sk->protinfo.ax25->digipeat->calls[ct] = fsa->fsa_digipeater[ct]; ct++; } } @@ -1706,9 +1703,9 @@ return 0; } #endif - skb->arp = 1; - skb->dev = dev_out; + skb->dev = dev_out; skb->priority = SOPRI_NORMAL; + ax25_queue_xmit(skb); return 0; @@ -1771,10 +1768,8 @@ * Remove the control and PID. */ skb_pull(skb, 2); - skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - if (!sk->dead) - sk->data_ready(sk, skb->len); + if (sock_queue_rcv_skb(sk, skb) != 0) + kfree_skb(skb, FREE_READ); } } else { kfree_skb(skb, FREE_READ); @@ -1975,7 +1970,7 @@ if (sk->protinfo.ax25->device == NULL) return -ENETUNREACH; - if (usax) { + if (usax != NULL) { if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) return -EINVAL; if (usax->sax25_family != AF_AX25) @@ -2030,8 +2025,6 @@ if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; - skb->arp = 1; - skb_reserve(skb, size - len); SOCK_DEBUG(sk, "AX.25: Appending user data\n"); @@ -2052,14 +2045,15 @@ return -ENOTCONN; } - ax25_output(sk->protinfo.ax25, skb); /* Shove it onto the queue and kick */ + ax25_output(sk->protinfo.ax25, 1, skb); /* Shove it onto the queue and kick */ return len; } else { asmptr = skb_push(skb, 1 + size_ax25_addr(dp)); SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); - if(dp != 0) + + if (dp != NULL) SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); /* Build an AX.25 header */ @@ -2081,7 +2075,6 @@ return len; } - } static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, @@ -2468,9 +2461,10 @@ skb->protocol = htons(ETH_P_AX25); skb->dev = ax25_fwd_dev(skb->dev); + skb->arp = 1; - ptr = skb_push(skb, 1); - *ptr++ = 0; /* KISS */ + ptr = skb_push(skb, 1); + *ptr++ = 0x00; /* KISS */ dev_queue_xmit(skb); } @@ -2568,7 +2562,7 @@ 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; } diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.1.24/linux/net/ax25/ax25_in.c Thu Jan 23 21:06:54 1997 +++ linux/net/ax25/ax25_in.c Sun Feb 2 15:18:48 1997 @@ -90,11 +90,7 @@ return 1; } - skbn->arp = 1; - skbn->dev = ax25->device; - - if (ax25->sk != NULL) - skb_set_owner_r(skbn, ax25->sk); + skbn->dev = ax25->device; skb_reserve(skbn, AX25_MAX_HEADER_LEN); @@ -156,7 +152,7 @@ if (skb == NULL) return 0; ax25->idletimer = ax25->idle; - + pid = *skb->data; #ifdef CONFIG_INET @@ -217,7 +213,6 @@ case AX25_UA: if (pf || dama) { if (dama) ax25_dama_on(ax25); /* bke */ - ax25_calculate_rtt(ax25); ax25->t1timer = 0; ax25->t3timer = ax25->t3; @@ -228,7 +223,6 @@ ax25->state = AX25_STATE_3; ax25->n2count = 0; ax25->dama_slave = dama; /* bke */ - if (ax25->sk != NULL) { ax25->sk->state = TCP_ESTABLISHED; /* For WAIT_SABM connections we will produce an accept ready socket here */ @@ -298,22 +292,8 @@ } break; - case AX25_UA: - if (pf) { - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } - break; - case AX25_DM: + case AX25_UA: if (pf) { ax25->state = AX25_STATE_0; ax25_dama_off(ax25); @@ -358,24 +338,15 @@ switch (frametype) { case AX25_SABM: - if (dama) ax25_dama_on(ax25); - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->dama_slave = dama; - break; - case AX25_SABME: if (dama) ax25_dama_on(ax25); - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); + } ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25->condition = 0x00; ax25->t1timer = 0; @@ -385,6 +356,7 @@ ax25->va = 0; ax25->vr = 0; ax25->dama_slave = dama; + ax25_requeue_frames(ax25); break; case AX25_DISC: @@ -418,20 +390,12 @@ } break; - case AX25_RNR: - ax25->condition |= AX25_COND_PEER_RX_BUSY; - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_check_iframes_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - case AX25_RR: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + case AX25_RNR: + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; ax25_check_need_response(ax25, type, pf); if (ax25_validate_nr(ax25, nr)) { ax25_check_iframes_acked(ax25, nr); @@ -546,27 +510,15 @@ switch (frametype) { case AX25_SABM: - if (dama) ax25_dama_on(ax25); - ax25->dama_slave = dama; - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - break; - case AX25_SABME: if (dama) ax25_dama_on(ax25); - ax25->dama_slave = dama; - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); + } ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25->condition = 0x00; ax25->t1timer = 0; @@ -577,6 +529,8 @@ ax25->vr = 0; ax25->state = AX25_STATE_3; ax25->n2count = 0; + ax25->dama_slave = dama; + ax25_requeue_frames(ax25); break; case AX25_DISC: @@ -610,8 +564,12 @@ } break; + case AX25_RR: case AX25_RNR: - ax25->condition |= AX25_COND_PEER_RX_BUSY; + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; if (type == AX25_RESPONSE && pf) { ax25->t1timer = 0; if (ax25_validate_nr(ax25, nr)) { @@ -627,38 +585,6 @@ } break; } - - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_RR: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->n2count = 0; - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - ax25_check_need_response(ax25, type, pf); if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); @@ -689,8 +615,7 @@ } 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) { diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v2.1.24/linux/net/ax25/ax25_out.c Thu Jan 23 21:06:54 1997 +++ linux/net/ax25/ax25_out.c Sun Feb 2 15:18:48 1997 @@ -55,10 +55,12 @@ #include /* - * All outgoing AX.25 I frames pass via this routine. Therefore this is - * where the fragmentation of frames takes place. + * All outgoing AX.25 I frames pass via this routine. Therefore this is + * where the fragmentation of frames takes place. If fragment is set to + * zero then we are not allowed to do fragmentation, even if the frame + * is too large. */ -void ax25_output(ax25_cb *ax25, struct sk_buff *skb) +void ax25_output(ax25_cb *ax25, int fragment, struct sk_buff *skb) { struct sk_buff *skbn; unsigned char *p; @@ -67,7 +69,7 @@ mtu = ax25->paclen; - if ((skb->len - 1) > mtu) { + if ((skb->len - 1) > mtu && fragment) { if (*skb->data == AX25_P_TEXT) { skb_pull(skb, 1); /* skip PID */ ka9qfrag = 0; @@ -96,8 +98,6 @@ restore_flags(flags); - skbn->arp = 1; - len = (mtu > skb->len) ? skb->len : mtu; if (ka9qfrag == 1) { @@ -257,7 +257,6 @@ ptr = skb_push(skb, size_ax25_addr(ax25->digipeat)); build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); - skb->arp = 1; skb->dev = ax25->device; skb->priority = SOPRI_NORMAL; @@ -397,9 +396,9 @@ 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); } diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v2.1.24/linux/net/ax25/ax25_route.c Thu Jan 23 21:06:54 1997 +++ linux/net/ax25/ax25_route.c Sun Feb 2 15:18:48 1997 @@ -486,7 +486,7 @@ return; } - memcpy(&dest, skb->data , AX25_ADDR_LEN); + memcpy(&dest, skb->data + 0, AX25_ADDR_LEN); memcpy(&src, skb->data + 7, AX25_ADDR_LEN); bp = skb_push(skb, len); @@ -638,11 +638,11 @@ 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) { diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v2.1.24/linux/net/ax25/ax25_subr.c Sun Feb 2 15:46:22 1997 +++ linux/net/ax25/ax25_subr.c Sun Feb 2 15:18:48 1997 @@ -101,7 +101,8 @@ } } -/* Maybe this should be your ax25_invoke_retransmission(), which appears +/* + * Maybe this should be your ax25_invoke_retransmission(), which appears * to be used but not do anything. ax25_invoke_retransmission() used to * be in AX 0.29, but has now gone in 0.30. */ @@ -260,11 +261,9 @@ /* * Do the address ourselves */ - dptr = skb_push(skb, size_ax25_addr(digi)); dptr += build_ax25_addr(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS); - skb->arp = 1; skb->dev = dev; skb->priority = SOPRI_NORMAL; @@ -278,11 +277,19 @@ { int n, t = 2; - if (ax25->backoff) { - for (n = 0; n < ax25->n2count; n++) - t *= 2; - - if (t > 8) t = 8; + switch (ax25->backoff) { + case 0: + break; + + case 1: + t += 2 * ax25->n2count; + break; + + case 2: + for (n = 0; n < ax25->n2count; n++) + t *= 2; + if (t > 8) t = 8; + break; } return t * ax25->rtt; @@ -306,7 +313,7 @@ /* * Digipeated address processing */ - + /* * Given an AX.25 address pull of to, from, digi list, command/response and the start of data @@ -333,8 +340,10 @@ /* Copy to, from */ if (dest != NULL) memcpy(dest, buf + 0, AX25_ADDR_LEN); + if (src != NULL) memcpy(src, buf + 7, AX25_ADDR_LEN); + buf += 2 * AX25_ADDR_LEN; len -= 2 * AX25_ADDR_LEN; digi->lastrepeat = -1; @@ -486,7 +495,6 @@ /* * count the number of buffers of one socket on the write/ack-queue */ - int ax25_queue_length(ax25_cb *ax25, struct sk_buff *skb) { return ax25_list_length(&ax25->write_queue, skb) + ax25_list_length(&ax25->ack_queue, skb); @@ -500,7 +508,6 @@ * * Not to mention this request isn't currently reliable. */ - void ax25_kiss_cmd(ax25_cb *ax25, unsigned char cmd, unsigned char param) { struct sk_buff *skb; @@ -539,6 +546,7 @@ 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); diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c --- v2.1.24/linux/net/ax25/ax25_timer.c Sun Feb 2 15:46:22 1997 +++ linux/net/ax25/ax25_timer.c Sun Feb 2 15:18:48 1997 @@ -49,37 +49,20 @@ static void ax25_timer(unsigned long); /* - * Linux set/reset timer routines + * Linux set timer */ void ax25_set_timer(ax25_cb *ax25) { unsigned long flags; - save_flags(flags); - cli(); - del_timer(&ax25->timer); - restore_flags(flags); - - ax25->timer.next = ax25->timer.prev = NULL; - ax25->timer.data = (unsigned long)ax25; - ax25->timer.function = &ax25_timer; - - ax25->timer.expires = jiffies + 10; - add_timer(&ax25->timer); -} - -static void ax25_reset_timer(ax25_cb *ax25) -{ - unsigned long flags; - - save_flags(flags); - cli(); + save_flags(flags); cli(); del_timer(&ax25->timer); restore_flags(flags); ax25->timer.data = (unsigned long)ax25; ax25->timer.function = &ax25_timer; ax25->timer.expires = jiffies + 10; + add_timer(&ax25->timer); } @@ -158,7 +141,7 @@ ax25->sk->dead = 1; } - ax25_reset_timer(ax25); + ax25_set_timer(ax25); return; } @@ -207,9 +190,8 @@ /* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */ /* nevertheless we have to re-enqueue the timer struct... */ - if (ax25->t1timer == 0 || --ax25->t1timer > 0) { - ax25_reset_timer(ax25); + ax25_set_timer(ax25); return; } @@ -229,7 +211,7 @@ * 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: diff -u --recursive --new-file v2.1.24/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v2.1.24/linux/net/ax25/sysctl_net_ax25.c Thu Jan 23 21:06:54 1997 +++ linux/net/ax25/sysctl_net_ax25.c Sun Feb 2 15:18:48 1997 @@ -11,7 +11,7 @@ static int min_ax25[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0x00}; -static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ, +static int max_ax25[] = {1, 1, 1, 2, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ, 3600 * AX25_SLOWHZ, 65535 * AX25_SLOWHZ, 31, 512, 20, 0x03}; static struct ctl_table_header *ax25_table_header; diff -u --recursive --new-file v2.1.24/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.24/linux/net/core/dev.c Thu Jan 23 21:06:54 1997 +++ linux/net/core/dev.c Sun Feb 2 15:18:49 1997 @@ -1006,17 +1006,19 @@ #ifdef CONFIG_PROC_FS static int sprintf_stats(char *buffer, struct device *dev) { - struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); + struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL); int size; if (stats) - size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", + size = sprintf(buffer, "%6s:%8ld %7ld %4ld %4ld %4ld %4ld %8ld %8ld %4ld %4ld %4ld %5ld %4ld\n", dev->name, + stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, + stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors @@ -1043,7 +1045,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/net/core/firewall.c linux/net/core/firewall.c --- v2.1.24/linux/net/core/firewall.c Wed Jan 15 19:45:47 1997 +++ linux/net/core/firewall.c Sun Feb 2 15:18:49 1997 @@ -10,8 +10,9 @@ #include #include #include +#include -static int firewall_lock=0; +struct semaphore firewall_sem = MUTEX; static int firewall_policy[NPROTO]; static struct firewall_ops *firewall_chain[NPROTO]; @@ -30,13 +31,7 @@ * Don't allow two people to adjust at once. */ - /* - * FIXME: Swap for a kernel semaphore object - */ - - while(firewall_lock) - schedule(); - firewall_lock=1; + down(&firewall_sem); p=&firewall_chain[pf]; @@ -47,7 +42,6 @@ p=&((*p)->next); } - /* * We need to use a memory barrier to make sure that this * works correctly even in SMP with weakly ordered writes. @@ -56,6 +50,7 @@ * chain), but not wrt itself (so you can't call this from * an interrupt. Not that you'd want to). */ + fw->next=*p; mb(); *p = fw; @@ -64,7 +59,7 @@ * And release the sleep lock */ - firewall_lock=0; + up(&firewall_sem); return 0; } @@ -83,9 +78,7 @@ * Don't allow two people to adjust at once. */ - while(firewall_lock) - schedule(); - firewall_lock=1; + down(&firewall_sem); nl=&firewall_chain[pf]; @@ -95,12 +88,12 @@ { 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; } diff -u --recursive --new-file v2.1.24/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.1.24/linux/net/core/iovec.c Thu Jan 23 21:06:55 1997 +++ linux/net/core/iovec.c Sun Feb 2 15:18:49 1997 @@ -11,7 +11,8 @@ * Andrew Lunn : Errors in iovec copying. * Pedro Roque : Added memcpy_fromiovecend and * csum_..._fromiovecend. - * Andi Kleen : fixed error handling for 2.1 + * Andi Kleen : fixed error handling for 2.1 + * Alexey Kuznetsov: 2.1 optimisations */ @@ -35,6 +36,9 @@ /* * Verify iovec * verify area does a simple check for completly bogus addresses + * + * Save time not doing verify_area. copy_*_user will make this work + * in any case. */ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) @@ -48,14 +52,10 @@ if(mode==VERIFY_READ) { err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - } - else - { - err=verify_area(mode, m->msg_name, m->msg_namelen); + if(err<0) + return err; } - if(err<0) - return err; m->msg_name = address; } else m->msg_name = NULL; @@ -67,27 +67,18 @@ return -ENOMEM; } - for(ct=0;ctmsg_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;ctmsg_iovlen;ct++) + len+=iov[ct].iov_len; + + m->msg_iov=iov; return len; } @@ -131,7 +122,7 @@ err = copy_from_user(kdata, iov->iov_base, copy); if (err) { - return err; + return -EFAULT; } len-=copy; kdata+=copy; @@ -171,7 +162,7 @@ err = copy_from_user(kdata, base, copy); if (err) { - return err; + return -EFAULT; } len-=copy; kdata+=copy; @@ -185,7 +176,7 @@ err = copy_from_user(kdata, iov->iov_base, copy); if (err) { - return err; + return -EFAULT; } len-=copy; kdata+=copy; diff -u --recursive --new-file v2.1.24/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.1.24/linux/net/ipv4/Config.in Thu Dec 12 19:37:25 1996 +++ linux/net/ipv4/Config.in Sun Feb 2 15:18:49 1997 @@ -1,7 +1,6 @@ # # IP configuration # -bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD bool 'IP: multicasting' CONFIG_IP_MULTICAST if [ "$CONFIG_FIREWALL" = "y" ]; then bool 'IP: firewalling' CONFIG_IP_FIREWALL @@ -10,16 +9,12 @@ 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 diff -u --recursive --new-file v2.1.24/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.24/linux/net/ipv4/af_inet.c Tue Jan 28 18:50:58 1997 +++ linux/net/ipv4/af_inet.c Sun Feb 2 15:18:49 1997 @@ -1732,15 +1732,21 @@ /* * Set the ARP module up */ + arp_init(); + /* * Set the IP module up */ + ip_init(); + /* * Set the ICMP layer up */ + icmp_init(&inet_family_ops); + /* * Set the firewalling up */ @@ -1757,7 +1763,7 @@ #if defined(CONFIG_IP_MROUTE) ip_mr_init(); #endif - + /* * Initialise AF_INET alias type (register net_alias_type) */ diff -u --recursive --new-file v2.1.24/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.24/linux/net/ipv4/arp.c Tue Jan 28 18:50:58 1997 +++ linux/net/ipv4/arp.c Sun Feb 2 15:18:49 1997 @@ -1552,7 +1552,7 @@ } start_bh_atomic(); - arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags)); + arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags) && dev->type != ARPHRD_METRICOM); end_bh_atomic(); kfree_skb(skb, FREE_READ); return 0; @@ -1617,6 +1617,13 @@ 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; } diff -u --recursive --new-file v2.1.24/linux/net/ipv4/fib.c linux/net/ipv4/fib.c --- v2.1.24/linux/net/ipv4/fib.c Thu Jan 23 21:06:57 1997 +++ linux/net/ipv4/fib.c Sun Feb 2 15:18:49 1997 @@ -1571,11 +1571,9 @@ static int get_rt_from_user(struct in_rtmsg *rtm, void *arg) { - int err; struct rtentry r; - err = copy_from_user(&r, arg, sizeof(struct rtentry)); - if (err) + if (copy_from_user(&r, arg, sizeof(struct rtentry))) return -EFAULT; if (r.rt_dev) { struct device *dev; @@ -1662,18 +1660,16 @@ case SIOCRTMSG: if (!suser()) return -EPERM; - err = copy_from_user(&dummy_nlh, arg, sizeof(dummy_nlh)); - if (err) - return err; + if (copy_from_user(&dummy_nlh, arg, sizeof(dummy_nlh))) + return -EFAULT; switch (dummy_nlh.nlmsg_type) { case RTMSG_NEWROUTE: case RTMSG_DELROUTE: if (dummy_nlh.nlmsg_len < sizeof(m.rtmsg) + sizeof(dummy_nlh)) return -EINVAL; - err = copy_from_user(&m.rtmsg, arg+sizeof(dummy_nlh), sizeof(m.rtmsg)); - if (err) - return err; + if (copy_from_user(&m.rtmsg, arg+sizeof(dummy_nlh), sizeof(m.rtmsg))) + return -EFAULT; fib_lock(); err = rtmsg_process(&dummy_nlh, &m.rtmsg); fib_unlock(); @@ -1682,9 +1678,8 @@ case RTMSG_DELRULE: if (dummy_nlh.nlmsg_len < sizeof(m.rtrmsg) + sizeof(dummy_nlh)) return -EINVAL; - err = copy_from_user(&m.rtrmsg, arg+sizeof(dummy_nlh), sizeof(m.rtrmsg)); - if (err) - return err; + if (copy_from_user(&m.rtrmsg, arg+sizeof(dummy_nlh), sizeof(m.rtrmsg))) + return -EFAULT; fib_lock(); err = rtrulemsg_process(&dummy_nlh, &m.rtrmsg); fib_unlock(); @@ -1693,9 +1688,8 @@ case RTMSG_DELDEVICE: if (dummy_nlh.nlmsg_len < sizeof(m.ifmsg) + sizeof(dummy_nlh)) return -EINVAL; - err = copy_from_user(&m.ifmsg, arg+sizeof(dummy_nlh), sizeof(m.ifmsg)); - if (err) - return err; + if (copy_from_user(&m.ifmsg, arg+sizeof(dummy_nlh), sizeof(m.ifmsg))) + return -EFAULT; fib_lock(); err = ifmsg_process(&dummy_nlh, &m.ifmsg); fib_unlock(); @@ -1703,9 +1697,8 @@ 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(); diff -u --recursive --new-file v2.1.24/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.1.24/linux/net/ipv4/ip_forward.c Thu Jan 23 21:06:57 1997 +++ linux/net/ipv4/ip_forward.c Sun Feb 2 15:18:49 1997 @@ -173,7 +173,6 @@ } if (rt->rt_flags&RTCF_MASQ) goto skip_call_fw_firewall; - } #endif #ifdef CONFIG_FIREWALL fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL); @@ -191,6 +190,8 @@ #endif #ifdef CONFIG_IP_MASQUERADE + } + skip_call_fw_firewall: /* * If this fragment needs masquerading, make it so... @@ -219,7 +220,7 @@ } #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) diff -u --recursive --new-file v2.1.24/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.1.24/linux/net/ipv4/ip_fw.c Tue Jan 28 18:50:58 1997 +++ linux/net/ipv4/ip_fw.c Sun Feb 2 15:18:49 1997 @@ -1309,14 +1309,13 @@ 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); diff -u --recursive --new-file v2.1.24/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.24/linux/net/ipv4/tcp.c Sun Feb 2 15:46:22 1997 +++ linux/net/ipv4/tcp.c Sun Feb 2 15:18:49 1997 @@ -799,6 +799,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int len, int flags) { + int err = 0; int copied = 0; struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp); @@ -849,6 +850,8 @@ int tmp; struct sk_buff *skb; + if (err) + return (err); /* * Stop on errors */ @@ -1030,7 +1033,7 @@ skb->h.th->urg_ptr = ntohs(copy); } - skb->csum = csum_partial_copy_fromuser(from, + skb->csum = csum_partial_copy_from_user(&err, from, skb_put(skb, copy), copy, 0); from += copy; @@ -1044,6 +1047,9 @@ sk->err = 0; + if (err) + return (err); + return copied; } @@ -1124,7 +1130,7 @@ msg->msg_name); } if(addr_len) - *addr_len= tp->af_specific->sockaddr_len; + *addr_len = tp->af_specific->sockaddr_len; /* * Read urgent data */ @@ -1173,14 +1179,14 @@ break; tcp_eat_skb(sk, skb); } - + SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk)); - - /* - * We send a ACK if the sender is blocked - * else let tcp_data deal with the acking policy. - */ - + + /* + * We send a ACK if the sender is blocked + * else let tcp_data deal with the acking policy. + */ + if (sk->delayed_acks) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -1456,7 +1462,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.24/linux/net/ipv4/tcp_input.c Sun Feb 2 15:46:22 1997 +++ linux/net/ipv4/tcp_input.c Sun Feb 2 15:18:49 1997 @@ -760,21 +760,19 @@ } else tcp_clear_xmit_timer(sk, TIME_RETRANS); - - + tcp_fast_retrans(sk, ack_seq, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE))); /* * Remember the highest ack received. */ - + tp->snd_una = ack; - return 1; uninteresting_ack: - SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt); + SOCK_DEBUG(sk, "Ack ignored %u %u\n",ack,tp->snd_nxt); return 0; } @@ -893,21 +891,18 @@ break; if (!after(skb->end_seq, tp->rcv_nxt)) { - SOCK_DEBUG(sk, "ofo packet already received \n"); + SOCK_DEBUG(sk, "ofo packet was allready received \n"); skb_unlink(skb); kfree_skb(skb, FREE_READ); continue; } - SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", - tp->rcv_nxt, skb->seq, skb->end_seq); - - skb_unlink(skb); + SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq); + skb_unlink(skb); skb_queue_tail(&sk->receive_queue, skb); - tp->rcv_nxt = skb->end_seq; } } @@ -970,9 +965,7 @@ * Partial packet * seq < rcv_next < end_seq */ - SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", - tp->rcv_nxt, skb->seq, skb->end_seq); - + SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq); skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = skb->end_seq; @@ -999,8 +992,7 @@ tp->pred_flags = 0; - SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", - tp->rcv_nxt, skb->seq, skb->end_seq); + SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq); if (skb_peek(&sk->out_of_order_queue) == NULL) { skb_queue_head(&sk->out_of_order_queue,skb); @@ -1078,16 +1070,16 @@ } 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); } diff -u --recursive --new-file v2.1.24/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.24/linux/net/ipv4/tcp_ipv4.c Sun Feb 2 15:46:22 1997 +++ linux/net/ipv4/tcp_ipv4.c Sun Feb 2 15:18:49 1997 @@ -1004,6 +1004,8 @@ default: /* CHECKSUM_UNNECESSARY */ } + + tcp_statistics.TcpInSegs++; #ifdef CONFIG_IP_TRANSPARENT_PROXY if (IPCB(skb)->redirport) diff -u --recursive --new-file v2.1.24/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.24/linux/net/ipv4/udp.c Tue Jan 28 18:50:58 1997 +++ linux/net/ipv4/udp.c Sun Feb 2 15:18:49 1997 @@ -778,8 +778,8 @@ /* wants to know, who sent it, to go and stomp on the garbage sender... */ - /* RFC1122: OK. Discards the bad packet silently (as far as */ - /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */ + /* RFC1122: OK. Discards the bad packet silently (as far as */ + /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */ NETDEBUG(printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n", ntohl(saddr),ntohs(uh->source), @@ -793,11 +793,17 @@ 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. */ diff -u --recursive --new-file v2.1.24/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.1.24/linux/net/ipv6/af_inet6.c Tue Jan 28 18:50:59 1997 +++ linux/net/ipv6/af_inet6.c Sun Feb 2 15:18:51 1997 @@ -129,6 +129,7 @@ } sock_init_data(sock,sk); + sk->zapped=0; sk->family = AF_INET6; sk->protocol = protocol; @@ -779,8 +780,8 @@ 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); diff -u --recursive --new-file v2.1.24/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.1.24/linux/net/ipv6/tcp_ipv6.c Sun Feb 2 15:46:22 1997 +++ linux/net/ipv6/tcp_ipv6.c Sun Feb 2 15:18:51 1997 @@ -905,6 +905,8 @@ /* CHECKSUM_UNNECESSARY */ } + tcp_statistics.TcpInSegs++; + sk = inet6_get_sock(&tcpv6_prot, daddr, saddr, th->dest, th->source); diff -u --recursive --new-file v2.1.24/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c --- v2.1.24/linux/net/lapb/lapb_iface.c Thu Jan 23 21:06:58 1997 +++ linux/net/lapb/lapb_iface.c Sun Feb 2 15:18:51 1997 @@ -49,8 +49,6 @@ */ static void lapb_free_cb(lapb_cb *lapb) { - del_timer(&lapb->timer); - kfree_s(lapb, sizeof(lapb_cb)); MOD_DEC_USE_COUNT; @@ -161,6 +159,10 @@ lapb_insert_cb(lapb); + lapb->t1timer = lapb->t1; + + lapb_set_timer(lapb); + return LAPB_OK; } @@ -171,6 +173,8 @@ if ((lapb = lapb_tokentostruct(token)) == NULL) return LAPB_BADTOKEN; + del_timer(&lapb->timer); + lapb_clear_queues(lapb); lapb_remove_cb(lapb); @@ -225,14 +229,8 @@ return LAPB_INVALUE; } - lapb->mode = parms->mode; - lapb->window = parms->window; - - if (lapb->mode & LAPB_DCE) { - lapb_set_timer(lapb); - } else { - lapb->t1timer = 0; - } + lapb->mode = parms->mode; + lapb->window = parms->window; } lapb->t1 = parms->t1; @@ -265,8 +263,6 @@ lapb->state = LAPB_STATE_1; - lapb_set_timer(lapb); - return LAPB_OK; } @@ -290,7 +286,7 @@ #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: diff -u --recursive --new-file v2.1.24/linux/net/lapb/lapb_in.c linux/net/lapb/lapb_in.c --- v2.1.24/linux/net/lapb/lapb_in.c Thu Jan 23 21:06:58 1997 +++ linux/net/lapb/lapb_in.c Sun Feb 2 15:18:51 1997 @@ -198,7 +198,7 @@ #endif lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; + lapb->t1timer = lapb->t1; lapb->t2timer = 0; lapb_disconnect_indication(lapb, LAPB_REFUSED); } @@ -244,7 +244,7 @@ printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; + lapb->t1timer = lapb->t1; lapb->t2timer = 0; lapb_disconnect_confirmation(lapb, LAPB_OK); } @@ -259,7 +259,7 @@ printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; + lapb->t1timer = lapb->t1; lapb->t2timer = 0; lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); } @@ -315,6 +315,7 @@ lapb->vs = 0; lapb->vr = 0; lapb->va = 0; + lapb_requeue_frames(lapb); } break; @@ -333,6 +334,7 @@ lapb->vs = 0; lapb->vr = 0; lapb->va = 0; + lapb_requeue_frames(lapb); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, pf); @@ -351,7 +353,7 @@ lapb_clear_queues(lapb); lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; + lapb->t1timer = lapb->t1; lapb->t2timer = 0; lapb_disconnect_indication(lapb, LAPB_OK); break; @@ -365,7 +367,7 @@ #endif lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; + lapb->t1timer = lapb->t1; lapb->t2timer = 0; lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED); break; @@ -519,6 +521,7 @@ lapb->vs = 0; lapb->vr = 0; lapb->va = 0; + lapb_requeue_frames(lapb); } break; @@ -537,6 +540,7 @@ lapb->vs = 0; lapb->vr = 0; lapb->va = 0; + lapb_requeue_frames(lapb); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, pf); @@ -555,7 +559,7 @@ lapb_clear_queues(lapb); lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; + lapb->t1timer = lapb->t1; lapb->t2timer = 0; lapb_disconnect_indication(lapb, LAPB_OK); break; @@ -569,7 +573,7 @@ #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; diff -u --recursive --new-file v2.1.24/linux/net/lapb/lapb_timer.c linux/net/lapb/lapb_timer.c --- v2.1.24/linux/net/lapb/lapb_timer.c Thu Jan 23 21:06:58 1997 +++ linux/net/lapb/lapb_timer.c Sun Feb 2 15:18:51 1997 @@ -41,37 +41,20 @@ static void lapb_timer(unsigned long); /* - * Linux set/reset timer routines + * Linux set timer */ void lapb_set_timer(lapb_cb *lapb) { unsigned long flags; - save_flags(flags); - cli(); - del_timer(&lapb->timer); - restore_flags(flags); - - lapb->timer.next = lapb->timer.prev = NULL; - lapb->timer.data = (unsigned long)lapb; - lapb->timer.function = &lapb_timer; - - lapb->timer.expires = jiffies + 10; - add_timer(&lapb->timer); -} - -static void lapb_reset_timer(lapb_cb *lapb) -{ - unsigned long flags; - - save_flags(flags); - cli(); + save_flags(flags); cli(); del_timer(&lapb->timer); restore_flags(flags); lapb->timer.data = (unsigned long)lapb; lapb->timer.function = &lapb_timer; lapb->timer.expires = jiffies + 10; + add_timer(&lapb->timer); } @@ -98,7 +81,7 @@ } if (lapb->t1timer == 0 || --lapb->t1timer > 0) { - lapb_reset_timer(lapb); + lapb_set_timer(lapb); return; } @@ -111,7 +94,6 @@ if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; lapb->t2timer = 0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 @@ -137,7 +119,6 @@ if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; - lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0; lapb->t2timer = 0; lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 @@ -156,13 +137,15 @@ 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 diff -u --recursive --new-file v2.1.24/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.24/linux/net/netrom/af_netrom.c Sun Feb 2 15:46:23 1997 +++ linux/net/netrom/af_netrom.c Sun Feb 2 15:18:52 1997 @@ -74,7 +74,6 @@ int sysctl_netrom_transport_busy_delay = NR_DEFAULT_T4; int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW; int sysctl_netrom_transport_no_activity_timeout = NR_DEFAULT_IDLE; -int sysctl_netrom_transport_packet_length = NR_DEFAULT_PACLEN; int sysctl_netrom_routing_control = NR_DEFAULT_ROUTING; int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS; @@ -119,7 +118,6 @@ /* * Socket removal during an interrupt is now safe. */ - static void nr_remove_socket(struct sock *sk) { struct sock *s; @@ -310,7 +308,7 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */ + if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) { /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = nr_destroy_timer; @@ -365,7 +363,6 @@ case NETROM_T1: if (nr_ctl.arg < 1) return -EINVAL; - sk->protinfo.nr->rtt = (nr_ctl.arg * NR_SLOWHZ) / 2; sk->protinfo.nr->t1 = nr_ctl.arg * NR_SLOWHZ; save_flags(flags); cli(); if (sk->protinfo.nr->t1timer > sk->protinfo.nr->t1) @@ -410,14 +407,6 @@ restore_flags(flags); break; - case NETROM_PACLEN: - if (nr_ctl.arg < 16 || nr_ctl.arg > 65535) - return -EINVAL; - if (nr_ctl.arg > 236) /* we probably want this */ - printk(KERN_WARNING "nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg); - sk->protinfo.nr->paclen = nr_ctl.arg; - break; - default: return -EINVAL; } @@ -446,7 +435,7 @@ case NETROM_T1: if (opt < 1) return -EINVAL; - sk->protinfo.nr->rtt = (opt * NR_SLOWHZ) / 2; + sk->protinfo.nr->t1 = opt * NR_SLOWHZ; return 0; case NETROM_T2: @@ -477,12 +466,6 @@ sk->protinfo.nr->hdrincl = opt ? 1 : 0; return 0; - case NETROM_PACLEN: - if (opt < 1 || opt > 65536) - return -EINVAL; - sk->protinfo.nr->paclen = opt; - return 0; - default: return -ENOPROTOOPT; } @@ -523,10 +506,6 @@ val = sk->protinfo.nr->hdrincl; break; - case NETROM_PACLEN: - val = sk->protinfo.nr->paclen; - break; - default: return -ENOPROTOOPT; } @@ -571,30 +550,25 @@ nr = sk->protinfo.nr; - sock_init_data(sock,sk); - - init_timer(&sk->timer); - - sock->ops = &nr_proto_ops; + sock_init_data(sock, sk); - sk->protocol = protocol; - sk->mtu = NETROM_MTU; /* 236 */ + sock->ops = &nr_proto_ops; + sk->protocol = protocol; + sk->mtu = NETROM_MTU; /* 236 */ skb_queue_head_init(&nr->ack_queue); skb_queue_head_init(&nr->reseq_queue); skb_queue_head_init(&nr->frag_queue); - nr->rtt = sysctl_netrom_transport_timeout / 2; - nr->t1 = sysctl_netrom_transport_timeout; - nr->t2 = sysctl_netrom_transport_acknowledge_delay; - nr->n2 = sysctl_netrom_transport_maximum_tries; - nr->t4 = sysctl_netrom_transport_busy_delay; - nr->idle = sysctl_netrom_transport_no_activity_timeout; - nr->paclen = sysctl_netrom_transport_packet_length; - nr->window = sysctl_netrom_transport_requested_window_size; + nr->t1 = sysctl_netrom_transport_timeout; + nr->t2 = sysctl_netrom_transport_acknowledge_delay; + nr->n2 = sysctl_netrom_transport_maximum_tries; + nr->t4 = sysctl_netrom_transport_busy_delay; + nr->idle = sysctl_netrom_transport_no_activity_timeout; + nr->window = sysctl_netrom_transport_requested_window_size; - nr->bpqext = 1; - nr->state = NR_STATE_0; + nr->bpqext = 1; + nr->state = NR_STATE_0; return 0; } @@ -612,38 +586,34 @@ 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->device = osk->protinfo.nr->device; - nr->bpqext = osk->protinfo.nr->bpqext; - nr->hdrincl = osk->protinfo.nr->hdrincl; + 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; return sk; } @@ -687,7 +657,7 @@ nr_write_internal(sk, NR_DISCACK); sk->protinfo.nr->state = NR_STATE_0; sk->state = TCP_CLOSE; - sk->shutdown = SEND_SHUTDOWN; + sk->shutdown |= SEND_SHUTDOWN; sk->state_change(sk); sk->dead = 1; nr_destroy_socket(sk); @@ -697,7 +667,7 @@ nr_clear_queues(sk); sk->protinfo.nr->n2count = 0; nr_write_internal(sk, NR_DISCREQ); - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk); + sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; sk->protinfo.nr->t2timer = 0; sk->protinfo.nr->t4timer = 0; sk->protinfo.nr->state = NR_STATE_2; @@ -1033,8 +1003,8 @@ /* L4 timeout negotiation */ if (skb->len == 37) { timeout = skb->data[36] * 256 + skb->data[35]; - if (timeout * NR_SLOWHZ < make->protinfo.nr->rtt * 2) - make->protinfo.nr->rtt = (timeout * NR_SLOWHZ) / 2; + if (timeout * NR_SLOWHZ < make->protinfo.nr->t1) + make->protinfo.nr->t1 = timeout * NR_SLOWHZ; make->protinfo.nr->bpqext = 1; } else { make->protinfo.nr->bpqext = 0; @@ -1110,8 +1080,6 @@ if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; - skb->arp = 1; - skb_reserve(skb, size - len); /* @@ -1285,7 +1253,7 @@ cli(); - len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 rtt wnd paclen Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 wnd Snd-Q Rcv-Q\n"); for (s = nr_list; s != NULL; s = s->next) { if ((dev = s->protinfo.nr->device) == NULL) @@ -1297,7 +1265,7 @@ ax2asc(&s->protinfo.nr->user_addr)); len += sprintf(buffer + len, "%-9s ", ax2asc(&s->protinfo.nr->dest_addr)); - len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %3d %6d %5d %5d\n", + len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %5d %5d\n", ax2asc(&s->protinfo.nr->source_addr), devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id, s->protinfo.nr->your_index, s->protinfo.nr->your_id, @@ -1307,9 +1275,9 @@ s->protinfo.nr->t1 / NR_SLOWHZ, s->protinfo.nr->t2timer / NR_SLOWHZ, s->protinfo.nr->t2 / NR_SLOWHZ, - s->protinfo.nr->n2count, s->protinfo.nr->n2, - s->protinfo.nr->rtt / NR_SLOWHZ, - s->protinfo.nr->window, s->protinfo.nr->paclen, + s->protinfo.nr->n2count, + s->protinfo.nr->n2, + s->protinfo.nr->window, s->wmem_alloc, s->rmem_alloc); pos = begin + len; @@ -1399,7 +1367,7 @@ 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"); diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c --- v2.1.24/linux/net/netrom/nr_dev.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/nr_dev.c Sun Feb 2 15:18:52 1997 @@ -228,9 +228,7 @@ int nr_init(struct device *dev) { - int i; - - dev->mtu = 236; /* MTU */ + dev->mtu = NR_MAX_PACKET_SIZE; dev->tbusy = 0; dev->hard_start_xmit = nr_xmit; dev->open = nr_open; @@ -259,9 +257,7 @@ 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; }; diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c --- v2.1.24/linux/net/netrom/nr_in.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/nr_in.c Sun Feb 2 15:18:52 1997 @@ -67,8 +67,6 @@ if ((skbn = alloc_skb(sk->protinfo.nr->fraglen, GFP_ATOMIC)) == NULL) return 1; - skbn->arp = 1; - skb_set_owner_r(skbn, sk); skbn->h.raw = skbn->data; skbo = skb_dequeue(&sk->protinfo.nr->frag_queue); @@ -97,7 +95,6 @@ switch (frametype) { case NR_CONNACK: - nr_calculate_rtt(sk); sk->protinfo.nr->your_index = skb->data[17]; sk->protinfo.nr->your_id = skb->data[18]; sk->protinfo.nr->t1timer = 0; @@ -311,7 +308,7 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb) { int queued = 0, frametype; - + if (sk->protinfo.nr->state == NR_STATE_0) return 0; @@ -319,8 +316,7 @@ 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; diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c --- v2.1.24/linux/net/netrom/nr_out.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/nr_out.c Sun Feb 2 15:18:52 1997 @@ -50,11 +50,9 @@ { struct sk_buff *skbn; unsigned char transport[NR_TRANSPORT_LEN]; - int err, frontlen, len, mtu; + int err, frontlen, len; - mtu = sk->protinfo.nr->paclen; - - if (skb->len - NR_TRANSPORT_LEN > mtu) { + if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) { /* Save a copy of the Transport Header */ memcpy(transport, skb->data, NR_TRANSPORT_LEN); skb_pull(skb, NR_TRANSPORT_LEN); @@ -62,15 +60,12 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + mtu, 0, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, 0, &err)) == NULL) return; - skbn->sk = sk; - skbn->arp = 1; - skb_reserve(skbn, frontlen); - len = (mtu > skb->len) ? skb->len : mtu; + len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE; /* Copy the user data */ memcpy(skb_put(skbn, len), skb->data, len); @@ -187,9 +182,8 @@ sk->protinfo.nr->vl = sk->protinfo.nr->vr; sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; - if (sk->protinfo.nr->t1timer == 0) { - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk); - } + if (sk->protinfo.nr->t1timer == 0) + sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; } nr_set_timer(sk); @@ -218,8 +212,6 @@ *dptr++ = sysctl_netrom_network_ttl_initialiser; - skb->arp = 1; - if (!nr_route_frame(skb, NULL)) { kfree_skb(skb, FREE_WRITE); @@ -245,7 +237,7 @@ nr_write_internal(sk, NR_CONNREQ); sk->protinfo.nr->t2timer = 0; - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk); + sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; } /* @@ -258,9 +250,8 @@ if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY) { frametype |= NR_CHOKE_FLAG; } else { - if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL) { + if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL) frametype |= NR_NAK_FLAG; - } } nr_write_internal(sk, frametype); @@ -273,13 +264,12 @@ { 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; } } } diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v2.1.24/linux/net/netrom/nr_route.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/nr_route.c Sun Feb 2 15:18:52 1997 @@ -101,6 +101,7 @@ nr_neigh->locked = 0; nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; + nr_neigh->failed = 0; if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { @@ -330,7 +331,7 @@ if (nr_neigh->count == 0 && !nr_neigh->locked) nr_remove_neigh(nr_neigh); - + nr_node->count--; if (nr_node->count == 0) { @@ -697,7 +698,7 @@ if (ax25 != NULL) nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, - ax25->device, 0, sysctl_netrom_network_ttl_initialiser); + ax25->device, 0, sysctl_netrom_obsolescence_count_initialiser); if ((dev = nr_dev_get(nr_dest)) != NULL) /* Its for me */ return nr_rx_frame(skb, dev); @@ -729,7 +730,7 @@ 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, diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c --- v2.1.24/linux/net/netrom/nr_subr.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/nr_subr.c Sun Feb 2 15:18:52 1997 @@ -175,7 +175,7 @@ switch (frametype & 0x0F) { case NR_CONNREQ: - timeout = (sk->protinfo.nr->rtt / NR_SLOWHZ) * 2; + timeout = sk->protinfo.nr->t1 / NR_SLOWHZ; *dptr++ = sk->protinfo.nr->my_index; *dptr++ = sk->protinfo.nr->my_id; *dptr++ = 0; @@ -267,40 +267,8 @@ *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 diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c --- v2.1.24/linux/net/netrom/nr_timer.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/nr_timer.c Sun Feb 2 15:18:52 1997 @@ -43,37 +43,20 @@ static void nr_timer(unsigned long); /* - * Linux set/reset timer routines + * Linux set timer */ void nr_set_timer(struct sock *sk) { unsigned long flags; - save_flags(flags); - cli(); - del_timer(&sk->timer); - restore_flags(flags); - - sk->timer.next = sk->timer.prev = NULL; - sk->timer.data = (unsigned long)sk; - sk->timer.function = &nr_timer; - - sk->timer.expires = jiffies+10; - add_timer(&sk->timer); -} - -static void nr_reset_timer(struct sock *sk) -{ - unsigned long flags; - - save_flags(flags); - cli(); + save_flags(flags); cli(); del_timer(&sk->timer); restore_flags(flags); sk->timer.data = (unsigned long)sk; sk->timer.function = &nr_timer; sk->timer.expires = jiffies+10; + add_timer(&sk->timer); } @@ -133,7 +116,7 @@ } if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) { - nr_reset_timer(sk); + nr_set_timer(sk); return; } @@ -187,7 +170,7 @@ 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); } diff -u --recursive --new-file v2.1.24/linux/net/netrom/sysctl_net_netrom.c linux/net/netrom/sysctl_net_netrom.c --- v2.1.24/linux/net/netrom/sysctl_net_netrom.c Thu Jan 23 21:06:58 1997 +++ linux/net/netrom/sysctl_net_netrom.c Sun Feb 2 15:18:52 1997 @@ -26,7 +26,6 @@ static int min_window[] = {1}, max_window[] = {127}; static int min_idle[] = {0 * NR_SLOWHZ}; static int max_idle[] = {65535 * NR_SLOWHZ}; -static int min_n1[] = {1}, max_n1[] = {236}; static int min_route[] = {0}, max_route[] = {1}; static int min_fails[] = {1}, max_fails[] = {10}; @@ -60,9 +59,6 @@ {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}, diff -u --recursive --new-file v2.1.24/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.24/linux/net/netsyms.c Tue Jan 28 18:50:59 1997 +++ linux/net/netsyms.c Sun Feb 2 15:18:52 1997 @@ -93,6 +93,7 @@ EXPORT_SYMBOL(sk_free); EXPORT_SYMBOL(sock_wake_async); EXPORT_SYMBOL(sock_alloc_send_skb); +EXPORT_SYMBOL(sock_init_data); EXPORT_SYMBOL(sock_no_fcntl); EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_wfree); @@ -102,7 +103,6 @@ EXPORT_SYMBOL(skb_copy_datagram_iovec); EXPORT_SYMBOL(skb_realloc_headroom); EXPORT_SYMBOL(datagram_poll); -EXPORT_SYMBOL(sock_init_data); EXPORT_SYMBOL(put_cmsg); EXPORT_SYMBOL(neigh_table_init); diff -u --recursive --new-file v2.1.24/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.24/linux/net/rose/af_rose.c Sun Feb 2 15:46:23 1997 +++ linux/net/rose/af_rose.c Sun Feb 2 15:18:52 1997 @@ -59,7 +59,8 @@ int sysctl_rose_clear_request_timeout = ROSE_DEFAULT_T3; int sysctl_rose_no_activity_timeout = ROSE_DEFAULT_IDLE; int sysctl_rose_ack_hold_back_timeout = ROSE_DEFAULT_HB; -int sysctl_rose_routing_control = 1; +int sysctl_rose_routing_control = ROSE_DEFAULT_ROUTING; +int sysctl_rose_link_fail_timeout = ROSE_DEFAULT_FAIL_TIMEOUT; static unsigned int lci = 1; @@ -157,7 +158,7 @@ memset(rose, 0x00, sizeof(*rose)); sk->protinfo.rose = rose; - rose->sk = sk; + rose->sk = sk; return sk; } @@ -221,7 +222,7 @@ if (event != NETDEV_DOWN) return NOTIFY_DONE; - + rose_kill_by_device(dev); rose_rt_device_down(dev); rose_link_device_down(dev); @@ -356,7 +357,7 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */ + if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) { /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = rose_destroy_timer; @@ -412,16 +413,6 @@ rose_set_timer(sk); break; - case ROSE_T0: - if (rose_ctl.arg < 1) - return -EINVAL; - if (sk->protinfo.rose->neighbour != NULL) { - save_flags(flags); cli(); - sk->protinfo.rose->neighbour->t0 = rose_ctl.arg * ROSE_SLOWHZ; - restore_flags(flags); - } - break; - case ROSE_T1: if (rose_ctl.arg < 1) return -EINVAL; @@ -487,13 +478,6 @@ get_user(opt, (int *)optval); switch (optname) { - case ROSE_T0: - if (opt < 1) - return -EINVAL; - if (sk->protinfo.rose->neighbour != NULL) - sk->protinfo.rose->neighbour->t0 = opt * ROSE_SLOWHZ; - return 0; - case ROSE_T1: if (opt < 1) return -EINVAL; @@ -544,13 +528,6 @@ return -EOPNOTSUPP; switch (optname) { - case ROSE_T0: - if (sk->protinfo.rose->neighbour != NULL) - val = sk->protinfo.rose->neighbour->t0 / ROSE_SLOWHZ; - else - val = sysctl_rose_restart_request_timeout / ROSE_SLOWHZ; - break; - case ROSE_T1: val = sk->protinfo.rose->t1 / ROSE_SLOWHZ; break; @@ -609,28 +586,6 @@ return -EOPNOTSUPP; } -static void def_callback1(struct sock *sk) -{ - if (!sk->dead) - wake_up_interruptible(sk->sleep); -} - -static void def_callback2(struct sock *sk, int len) -{ - if (!sk->dead) { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 1); - } -} - -static void def_callback3(struct sock *sk) -{ - if (!sk->dead) { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 2); - } -} - static int rose_create(struct socket *sock, int protocol) { struct sock *sk; @@ -644,19 +599,19 @@ rose = sk->protinfo.rose; - sock_init_data(sock,sk); + sock_init_data(sock, sk); - sock->ops = &rose_proto_ops; - sk->protocol = protocol; - sk->mtu = ROSE_MTU; /* 128 */ + sock->ops = &rose_proto_ops; + sk->protocol = protocol; + sk->mtu = ROSE_MTU; /* 128 */ skb_queue_head_init(&rose->frag_queue); - rose->t1 = sysctl_rose_call_request_timeout; - rose->t2 = sysctl_rose_reset_request_timeout; - rose->t3 = sysctl_rose_clear_request_timeout; - rose->hb = sysctl_rose_ack_hold_back_timeout; - rose->idle = sysctl_rose_no_activity_timeout; + rose->t1 = sysctl_rose_call_request_timeout; + rose->t2 = sysctl_rose_reset_request_timeout; + rose->t3 = sysctl_rose_clear_request_timeout; + rose->hb = sysctl_rose_ack_hold_back_timeout; + rose->idle = sysctl_rose_no_activity_timeout; rose->state = ROSE_STATE_0; @@ -676,28 +631,19 @@ rose = sk->protinfo.rose; - skb_queue_head_init(&sk->receive_queue); - skb_queue_head_init(&sk->write_queue); - skb_queue_head_init(&sk->back_log); - - init_timer(&sk->timer); - - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->mtu = osk->mtu; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; - - sk->state_change = def_callback1; - sk->data_ready = def_callback2; - sk->write_space = def_callback3; - sk->error_report = def_callback1; + sock_init_data(NULL, sk); + + sk->type = osk->type; + sk->socket = osk->socket; + sk->priority = osk->priority; + sk->protocol = osk->protocol; + sk->rcvbuf = osk->rcvbuf; + sk->sndbuf = osk->sndbuf; + sk->debug = osk->debug; + sk->state = TCP_ESTABLISHED; + sk->mtu = osk->mtu; + sk->sleep = osk->sleep; + sk->zapped = osk->zapped; skb_queue_head_init(&rose->frag_queue); @@ -845,7 +791,7 @@ if (sk->state == TCP_ESTABLISHED) return -EISCONN; /* No reconnect on a seqpacket socket */ - sk->state = TCP_CLOSE; + sk->state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct sockaddr_rose)) @@ -894,7 +840,7 @@ /* Now the loop */ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; - + cli(); /* To avoid races on the sleep */ /* @@ -920,7 +866,7 @@ return 0; } - + static int rose_socketpair(struct socket *sock1, struct socket *sock2) { return -EOPNOTSUPP; @@ -1139,8 +1085,6 @@ if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; - skb->arp = 1; - skb_reserve(skb, size - len); /* @@ -1470,7 +1414,7 @@ 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 diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c --- v2.1.24/linux/net/rose/rose_dev.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/rose_dev.c Sun Feb 2 15:18:52 1997 @@ -200,9 +200,7 @@ int rose_init(struct device *dev) { - int i; - - dev->mtu = ROSE_PACLEN - 2; + dev->mtu = ROSE_MAX_PACKET_SIZE - 2; dev->tbusy = 0; dev->hard_start_xmit = rose_xmit; dev->open = rose_open; @@ -231,9 +229,7 @@ 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; }; diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_in.c linux/net/rose/rose_in.c --- v2.1.24/linux/net/rose/rose_in.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/rose_in.c Sun Feb 2 15:18:52 1997 @@ -1,8 +1,8 @@ /* * Rose release 001 * - * This is ALPHA test software. This code may break your machine, randomly fail to work with new - * releases, misbehave and/or generally screw up. It might even work. + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -64,8 +64,6 @@ if ((skbn = alloc_skb(sk->protinfo.rose->fraglen, GFP_ATOMIC)) == NULL) return 1; - skbn->arp = 1; - skb_set_owner_r(skbn, sk); skbn->h.raw = skbn->data; skbo = skb_dequeue(&sk->protinfo.rose->frag_queue); @@ -189,11 +187,10 @@ case ROSE_RR: case ROSE_RNR: - if (frametype == ROSE_RNR) { + if (frametype == ROSE_RNR) sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY; - } else { + else sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY; - } if (!rose_validate_nr(sk, nr)) { rose_clear_queues(sk); rose_write_internal(sk, ROSE_RESET_REQUEST); @@ -246,7 +243,7 @@ * 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); diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_link.c linux/net/rose/rose_link.c --- v2.1.24/linux/net/rose/rose_link.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/rose_link.c Sun Feb 2 15:18:52 1997 @@ -44,37 +44,20 @@ static void rose_link_timer(unsigned long); /* - * Linux set/reset timer routines + * Linux set timer */ -static void rose_link_set_timer(struct rose_neigh *neigh) +void rose_link_set_timer(struct rose_neigh *neigh) { unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); del_timer(&neigh->timer); restore_flags(flags); - neigh->timer.next = neigh->timer.prev = NULL; neigh->timer.data = (unsigned long)neigh; neigh->timer.function = &rose_link_timer; - neigh->timer.expires = jiffies + 10; - add_timer(&neigh->timer); -} - -static void rose_link_reset_timer(struct rose_neigh *neigh) -{ - unsigned long flags; - save_flags(flags); - cli(); - del_timer(&neigh->timer); - restore_flags(flags); - - neigh->timer.data = (unsigned long)neigh; - neigh->timer.function = &rose_link_timer; - neigh->timer.expires = jiffies + 10; add_timer(&neigh->timer); } @@ -88,19 +71,22 @@ { struct rose_neigh *neigh = (struct rose_neigh *)param; - if (neigh->t0timer == 0 || --neigh->t0timer > 0) { - rose_link_reset_timer(neigh); - return; - } + if (neigh->ftimer > 0) + neigh->ftimer--; - /* - * T0 for a link has expired. - */ - rose_transmit_restart_request(neigh); + if (neigh->t0timer > 0) { + neigh->t0timer--; - neigh->t0timer = neigh->t0; + if (neigh->t0timer == 0) { + rose_transmit_restart_request(neigh); + neigh->t0timer = sysctl_rose_restart_request_timeout; + } + } - rose_link_set_timer(neigh); + if (neigh->ftimer > 0 || neigh->t0timer > 0) + rose_link_set_timer(neigh); + else + del_timer(&neigh->timer); } /* @@ -117,7 +103,7 @@ else rose_call = &rose_callsign; - return ax25_send_frame(skb, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); + return ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); } /* @@ -199,8 +185,6 @@ *dptr++ = 0x00; *dptr++ = 0; - skb->sk = NULL; - if (!rose_send_frame(skb, neigh)) kfree_skb(skb, FREE_WRITE); } @@ -228,8 +212,6 @@ *dptr++ = 0x00; *dptr++ = ROSE_RESTART_CONFIRMATION; - skb->sk = NULL; - if (!rose_send_frame(skb, neigh)) kfree_skb(skb, FREE_WRITE); } @@ -258,8 +240,6 @@ *dptr++ = ROSE_DIAGNOSTIC; *dptr++ = diag; - skb->sk = NULL; - if (!rose_send_frame(skb, neigh)) kfree_skb(skb, FREE_WRITE); } @@ -290,8 +270,6 @@ *dptr++ = cause; *dptr++ = 0x00; - skb->sk = NULL; - if (!rose_send_frame(skb, neigh)) kfree_skb(skb, FREE_WRITE); } @@ -311,8 +289,6 @@ dptr = skb_push(skb, 1); *dptr++ = AX25_P_ROSE; - skb->arp = 1; - if (neigh->restarted) { if (!rose_send_frame(skb, neigh)) kfree_skb(skb, FREE_WRITE); @@ -321,7 +297,7 @@ 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); } } diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_out.c linux/net/rose/rose_out.c --- v2.1.24/linux/net/rose/rose_out.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/rose_out.c Sun Feb 2 15:18:52 1997 @@ -49,7 +49,7 @@ unsigned char header[ROSE_MIN_LEN]; int err, frontlen, len; - if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) { + if (skb->len - ROSE_MIN_LEN > ROSE_MAX_PACKET_SIZE) { /* Save a copy of the Header */ memcpy(header, skb->data, ROSE_MIN_LEN); skb_pull(skb, ROSE_MIN_LEN); @@ -57,15 +57,12 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_MAX_PACKET_SIZE, 0, 0, &err)) == NULL) return; - skbn->sk = sk; - skbn->arp = 1; - skb_reserve(skbn, frontlen); - len = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN; + len = (ROSE_MAX_PACKET_SIZE > skb->len) ? skb->len : ROSE_MAX_PACKET_SIZE; /* Copy the user data */ memcpy(skb_put(skbn, len), skb->data, len); @@ -112,7 +109,7 @@ del_timer(&sk->timer); - end = (sk->protinfo.rose->va + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS; + end = (sk->protinfo.rose->va + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS; if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) && sk->protinfo.rose->vs != end && @@ -149,11 +146,10 @@ void rose_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; diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_route.c linux/net/rose/rose_route.c --- v2.1.24/linux/net/rose/rose_route.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/rose_route.c Sun Feb 2 15:18:52 1997 @@ -86,8 +86,8 @@ rose_neigh->number = rose_neigh_no++; rose_neigh->restarted = 0; skb_queue_head_init(&rose_neigh->queue); - rose_neigh->t0 = sysctl_rose_restart_request_timeout; rose_neigh->t0timer = 0; + rose_neigh->ftimer = 0; init_timer(&rose_neigh->timer); if (rose_route->ndigis != 0) { @@ -114,10 +114,10 @@ * best match. */ if (rose_node == NULL) { - rose_tmpn = rose_node_list; rose_tmpp = NULL; - while(rose_tmpn != NULL) { + + while (rose_tmpn != NULL) { if (rose_tmpn->mask > rose_route->mask) { rose_tmpp = rose_tmpn; rose_tmpn = rose_tmpn->next; @@ -132,7 +132,6 @@ rose_node->address = rose_route->address; rose_node->mask = rose_route->mask; - rose_node->which = 0; rose_node->count = 1; rose_node->neighbour[0] = rose_neigh; @@ -163,13 +162,9 @@ return 0; } - /* We have space at the bottom, slot it in */ + /* We have space, slot it in */ if (rose_node->count < 3) { - rose_node->neighbour[2] = rose_node->neighbour[1]; - rose_node->neighbour[1] = rose_node->neighbour[0]; - - rose_node->neighbour[0] = rose_neigh; - + rose_node->neighbour[rose_node->count] = rose_neigh; rose_node->count++; rose_neigh->count++; } @@ -302,7 +297,7 @@ if (rose_neigh->count == 0) rose_remove_neigh(rose_neigh); - + rose_node->count--; if (rose_node->count == 0) { @@ -436,6 +431,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr) { struct rose_node *node; + int i; for (node = rose_node_list; node != NULL; node = node->next) if (rosecmpm(addr, &node->address, node->mask) == 0) @@ -443,9 +439,11 @@ if (node == NULL) return NULL; - if (node->which >= node->count) return NULL; + for (i = 0; i < node->count; i++) + if (node->neighbour[i]->ftimer == 0) + return node->neighbour[i]; - return node->neighbour[node->which]; + return NULL; } /* @@ -494,25 +492,22 @@ void rose_link_failed(ax25_address *callsign, struct device *dev) { struct rose_neigh *rose_neigh; - struct rose_node *rose_node; struct sk_buff *skb; for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev) break; - + if (rose_neigh == NULL) return; rose_neigh->restarted = 0; rose_neigh->t0timer = 0; - del_timer(&rose_neigh->timer); + rose_neigh->ftimer = sysctl_rose_link_fail_timeout; + + rose_link_set_timer(rose_neigh); while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) kfree_skb(skb, FREE_WRITE); - - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh) - rose_node->which++; } /* @@ -521,35 +516,29 @@ void rose_link_device_down(struct device *dev) { struct rose_neigh *rose_neigh; - struct rose_node *rose_node; struct sk_buff *skb; for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) { if (rose_neigh->dev == dev) { rose_neigh->restarted = 0; rose_neigh->t0timer = 0; + rose_neigh->ftimer = 0; del_timer(&rose_neigh->timer); while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) kfree_skb(skb, FREE_WRITE); - - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh) - rose_node->which++; } } } /* - * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb - * indicates an internally generated frame. + * Route a frame to an appropriate AX.25 connection. */ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) { struct rose_neigh *rose_neigh, *new_neigh; - struct rose_node *rose_node; struct rose_route *rose_route; - rose_address *dest_addr; + rose_address *src_addr, *dest_addr; struct sock *sk; unsigned short frametype; unsigned int lci; @@ -563,6 +552,8 @@ 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) @@ -572,6 +563,11 @@ return 0; /* + * Obviously the link is working, halt the ftimer. + */ + rose_neigh->ftimer = 0; + + /* * LCI of zero is always for us, and its always a restart * frame. */ @@ -591,12 +587,9 @@ /* * Is is a Call Request and is it for us ? */ - if (frametype == ROSE_CALL_REQUEST) { - dest_addr = (rose_address *)(skb->data + 4); - + if (frametype == ROSE_CALL_REQUEST) if ((dev = rose_dev_get(dest_addr)) != NULL) return rose_rx_call_request(skb, dev, rose_neigh, lci); - } if (!sysctl_rose_routing_control) { rose_transmit_clear_request(rose_neigh, lci, 0x0D); @@ -640,18 +633,7 @@ if (frametype != ROSE_CALL_REQUEST) /* XXX */ return 0; - dest_addr = (rose_address *)(skb->data + 4); - - /* - * Create a new route entry, if we can. - */ - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if (rosecmpm(dest_addr, &rose_node->address, rose_node->mask) == 0) - break; - /* - * Its an unknown node, or is unreachable. - */ - if (rose_node == NULL || rose_node->which >= rose_node->count) { + if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) { rose_transmit_clear_request(rose_neigh, lci, 0x0D); return 0; } @@ -661,8 +643,6 @@ return 0; } - new_neigh = rose_node->neighbour[rose_node->which]; - rose_route->lci1 = lci; rose_route->neigh1 = rose_neigh; rose_route->lci2 = rose_new_lci(new_neigh->dev); @@ -693,13 +673,12 @@ 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++) @@ -739,17 +718,17 @@ 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; diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c --- v2.1.24/linux/net/rose/rose_timer.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/rose_timer.c Sun Feb 2 15:18:52 1997 @@ -43,37 +43,20 @@ static void rose_timer(unsigned long); /* - * Linux set/reset timer routines + * Linux set timer */ void rose_set_timer(struct sock *sk) { unsigned long flags; - save_flags(flags); - cli(); - del_timer(&sk->timer); - restore_flags(flags); - - sk->timer.next = sk->timer.prev = NULL; - sk->timer.data = (unsigned long)sk; - sk->timer.function = &rose_timer; - - sk->timer.expires = jiffies + 10; - add_timer(&sk->timer); -} - -static void rose_reset_timer(struct sock *sk) -{ - unsigned long flags; - - save_flags(flags); - cli(); + save_flags(flags); cli(); del_timer(&sk->timer); restore_flags(flags); sk->timer.data = (unsigned long)sk; sk->timer.function = &rose_timer; sk->timer.expires = jiffies + 10; + add_timer(&sk->timer); } @@ -121,7 +104,7 @@ } if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) { - rose_reset_timer(sk); + rose_set_timer(sk); return; } diff -u --recursive --new-file v2.1.24/linux/net/rose/sysctl_net_rose.c linux/net/rose/sysctl_net_rose.c --- v2.1.24/linux/net/rose/sysctl_net_rose.c Thu Jan 23 21:06:59 1997 +++ linux/net/rose/sysctl_net_rose.c Sun Feb 2 15:18:52 1997 @@ -10,12 +10,13 @@ #include #include -static int min_timer[] = {1 * ROSE_SLOWHZ}; -static int max_timer[] = {300 * ROSE_SLOWHZ}; -static int min_idle[] = {0 * ROSE_SLOWHZ}; -static int max_idle[] = {65535 * ROSE_SLOWHZ}; -static int min_route[] = {0}; -static int max_route[] = {1}; +static int min_timer[] = {1 * ROSE_SLOWHZ}; +static int max_timer[] = {300 * ROSE_SLOWHZ}; +static int min_idle[] = {0 * ROSE_SLOWHZ}; +static int max_idle[] = {65535 * ROSE_SLOWHZ}; +static int min_route[] = {0}, max_route[] = {1}; +static int min_ftimer[] = {60 * ROSE_SLOWHZ}; +static int max_ftimer[] = {600 * ROSE_SLOWHZ}; static struct ctl_table_header *rose_table_header; @@ -41,6 +42,9 @@ {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} }; diff -u --recursive --new-file v2.1.24/linux/net/socket.c linux/net/socket.c --- v2.1.24/linux/net/socket.c Tue Jan 28 18:50:59 1997 +++ linux/net/socket.c Sun Feb 2 15:18:52 1997 @@ -35,6 +35,9 @@ * Alan Cox : sendmsg/recvmsg basics. * Tom Dyas : Export net symbols. * Marcin Dalecki : Fixed problems with CONFIG_NET="n". + * Alan Cox : Added thread locking to sys_* calls + * for sockets. May have errors at the + * moment. * * * This program is free software; you can redistribute it and/or @@ -46,14 +49,6 @@ * 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 @@ -68,11 +63,13 @@ #include #include #include +#include #include #include #include #include #include +#include #if defined(CONFIG_KERNELD) && defined(CONFIG_NET) #include @@ -232,7 +229,7 @@ struct file *file; struct inode *inode; - if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (!(file = fget(fd))) { *err = -EBADF; return NULL; @@ -242,12 +239,18 @@ if (!inode || !inode->i_sock || !socki_lookup(inode)) { *err = -ENOTSOCK; + fput(file,inode); return NULL; } return socki_lookup(inode); } +extern __inline__ void sockfd_put(struct socket *sock) +{ + fput(sock->file,sock->inode); +} + /* * Allocate a socket. */ @@ -713,22 +716,16 @@ asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen) { struct socket *sock; - int i; char address[MAX_SOCK_ADDR]; int err; lock_kernel(); - if (!(sock = sockfd_lookup(fd,&err))) - goto out; - - if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0) - goto out; - - if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0) - err = i; - else - err = 0; -out: + if((sock = sockfd_lookup(fd,&err))!=NULL) + { + if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) + err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen); + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -743,15 +740,14 @@ asmlinkage int sys_listen(int fd, int backlog) { struct socket *sock; - int err=-EOPNOTSUPP; + int err; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - if (sock->ops && sock->ops->listen) + if((sock = sockfd_lookup(fd, &err))!=NULL) + { err=sock->ops->listen(sock, backlog); -out: + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -778,54 +774,50 @@ int len; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - err = -EOPNOTSUPP; - if (!sock->ops->accept) - goto out; - - err = -ENOSR; - if (!(newsock = sock_alloc())) - { - printk(KERN_WARNING "accept: no more sockets\n"); - goto out; /* Was: EAGAIN, but we are out of system - resources! */ - } + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + if (!(newsock = sock_alloc())) + { + printk(KERN_WARNING "accept: no more sockets\n"); + err=-EMFILE; + goto out; + } - inode = newsock->inode; - newsock->type = sock->type; + inode = newsock->inode; + newsock->type = sock->type; - if ((err = sock->ops->dup(newsock, sock)) < 0) - { - sock_release(newsock); - goto out; - } + if ((err = sock->ops->dup(newsock, sock)) < 0) + { + sock_release(newsock); + goto out; + } - err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags); + err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags); - if (err < 0) - { - sock_release(newsock); - goto out; - } - newsock = socki_lookup(inode); + if (err < 0) + { + sock_release(newsock); + goto out; + } + newsock = socki_lookup(inode); - if ((fd = get_fd(inode)) < 0) - { - sock_release(newsock); - err = -EINVAL; - goto out; - } + if ((err = get_fd(inode)) < 0) + { + sock_release(newsock); + err=-EINVAL; + goto out; + } - newsock->file = current->files->fd[fd]; + newsock->file = current->files->fd[err]; - if (upeer_sockaddr) - { - newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1); - move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen); - } - err = fd; + if (upeer_sockaddr) + { + newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1); + move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen); + } out: + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -850,17 +842,13 @@ int err; lock_kernel(); - if (!(sock = sockfd_lookup(fd,&err))) - goto out; - - if((err=move_addr_to_kernel(uservaddr,addrlen,address))<0) - goto out; - - err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, + if ((sock = sockfd_lookup(fd,&err))!=NULL) + { + if((err=move_addr_to_kernel(uservaddr,addrlen,address))>=0) + err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, current->files->fd[fd]->f_flags); - if (err >= 0) - err = 0; -out: + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -878,16 +866,12 @@ int err; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0); - if(err) - goto out; - if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0) - goto out; - err = 0; -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0))==0) + err=move_addr_to_user(address,len, usockaddr, usockaddr_len); + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -905,16 +889,12 @@ int err; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); - if(err) - goto out; - if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0) - goto out; - err = 0; -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1))==0) + err=move_addr_to_user(address,len, usockaddr, usockaddr_len); + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -932,30 +912,27 @@ struct iovec iov; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - err = -EINVAL; - if(len<0) - goto out; - err=verify_area(VERIFY_READ, buff, len); - if(err) - goto out; - - iov.iov_base=buff; - iov.iov_len=len; - msg.msg_name=NULL; - msg.msg_namelen=0; - msg.msg_iov=&iov; - msg.msg_iovlen=1; - msg.msg_control=NULL; - msg.msg_controllen=0; - if (current->files->fd[fd]->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - msg.msg_flags=flags; - - err = sock_sendmsg(sock, &msg, len); -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + if(len>=0) + { + iov.iov_base=buff; + iov.iov_len=len; + msg.msg_name=NULL; + msg.msg_namelen=0; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=NULL; + msg.msg_controllen=0; + if (current->files->fd[fd]->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + msg.msg_flags=flags; + err=sock_sendmsg(sock, &msg, len); + } + else + err=-EINVAL; + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -976,35 +953,30 @@ struct iovec iov; lock_kernel(); - if (!(sock = sockfd_lookup(fd,&err))) - goto out; - - err=verify_area(VERIFY_READ,buff,len); - if(err) - goto out; - - iov.iov_base=buff; - iov.iov_len=len; - msg.msg_name=NULL; - msg.msg_iov=&iov; - msg.msg_iovlen=1; - msg.msg_control=NULL; - msg.msg_controllen=0; - msg.msg_namelen=addr_len; - if(addr) + if ((sock = sockfd_lookup(fd,&err))!=NULL) { - err=move_addr_to_kernel(addr,addr_len,address); - if (err < 0) - goto out; - msg.msg_name=address; + iov.iov_base=buff; + iov.iov_len=len; + msg.msg_name=NULL; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=NULL; + msg.msg_controllen=0; + msg.msg_namelen=addr_len; + if(addr) + { + err=move_addr_to_kernel(addr,addr_len,address); + if (err < 0) + goto bad; + msg.msg_name=address; + } + if (current->files->fd[fd]->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + msg.msg_flags=flags; + err=sock_sendmsg(sock, &msg, len); +bad: + sockfd_put(sock); } - - if (current->files->fd[fd]->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - msg.msg_flags=flags; - - err = sock_sendmsg(sock, &msg, len); -out: unlock_kernel(); return err; } @@ -1022,28 +994,20 @@ int err; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - err = 0; - if(size==0) - goto out; - err=verify_area(VERIFY_WRITE, ubuf, size); - if(err) - goto out; - - msg.msg_name=NULL; - msg.msg_iov=&iov; - msg.msg_iovlen=1; - msg.msg_control=NULL; - msg.msg_controllen=0; - iov.iov_base=ubuf; - iov.iov_len=size; - - err = sock_recvmsg(sock, &msg, size, - (current->files->fd[fd]->f_flags & O_NONBLOCK) - ? flags | MSG_DONTWAIT : flags); -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + msg.msg_name=NULL; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=NULL; + msg.msg_controllen=0; + iov.iov_base=ubuf; + iov.iov_len=size; + + err=sock_recvmsg(sock, &msg, size, + (current->files->fd[fd]->f_flags & O_NONBLOCK) ? flags | MSG_DONTWAIT : flags); + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -1061,39 +1025,29 @@ struct iovec iov; struct msghdr msg; char address[MAX_SOCK_ADDR]; - int err; + int err,err2; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - err = 0; - if (size==0) - goto out; - - err=verify_area(VERIFY_WRITE,ubuf,size); - if(err) - goto out; - - msg.msg_control=NULL; - msg.msg_controllen=0; - msg.msg_iovlen=1; - msg.msg_iov=&iov; - iov.iov_len=size; - iov.iov_base=ubuf; - msg.msg_name=address; - msg.msg_namelen=MAX_SOCK_ADDR; - err = sock_recvmsg(sock, &msg, size, - (current->files->fd[fd]->f_flags & O_NONBLOCK) - ? (flags | MSG_DONTWAIT) : flags); - - if(err<0) - goto out; - size=err; - if(addr!=NULL && - (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0) - goto out; - err = size; -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + msg.msg_control=NULL; + msg.msg_controllen=0; + msg.msg_iovlen=1; + msg.msg_iov=&iov; + iov.iov_len=size; + iov.iov_base=ubuf; + msg.msg_name=address; + msg.msg_namelen=MAX_SOCK_ADDR; + err=sock_recvmsg(sock, &msg, size, + (current->files->fd[fd]->f_flags & O_NONBLOCK) ? (flags | MSG_DONTWAIT) : flags); + if(err>=0 && addr!=NULL) + { + err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len); + if(err2<0) + err=err2; + } + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -1109,16 +1063,14 @@ struct socket *sock; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - if (level == SOL_SOCKET) - err = sock_setsockopt(sock,level,optname,optval,optlen); - else if (sock->ops->setsockopt) - err = sock->ops->setsockopt(sock, level, optname, optval, optlen); - else - err = -EOPNOTSUPP; -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + if (level == SOL_SOCKET) + err=sock_setsockopt(sock,level,optname,optval,optlen); + else + err=sock->ops->setsockopt(sock, level, optname, optval, optlen); + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -1134,16 +1086,14 @@ struct socket *sock; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - if (level == SOL_SOCKET) - err = sock_getsockopt(sock,level,optname,optval,optlen); - else if (sock->ops->getsockopt) - err = sock->ops->getsockopt(sock, level, optname, optval, optlen); - else - err = -EOPNOTSUPP; -out: + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + if (level == SOL_SOCKET) + err=sock_getsockopt(sock,level,optname,optval,optlen); + else + err=sock->ops->getsockopt(sock, level, optname, optval, optlen); + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -1159,12 +1109,11 @@ struct socket *sock; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - err = sock->ops->shutdown(sock, how); -out: - unlock_kernel(); + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + err=sock->ops->shutdown(sock, how); + sockfd_put(sock); + } return err; } @@ -1179,36 +1128,32 @@ struct iovec iov[UIO_FASTIOV]; unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ struct msghdr msg_sys; - int err; + int err= -EINVAL; int total_len; lock_kernel(); - if (!(sock = sockfd_lookup(fd,&err))) - goto out; - - err = -EOPNOTSUPP; - if (sock->ops->sendmsg==NULL) - goto out; - err = -EFAULT; if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) - goto out; - + { + err=-EFAULT; + goto out; + } /* do not move before msg_sys is valid */ - err = -EINVAL; if (msg_sys.msg_iovlen>UIO_MAXIOV) goto out; - /* This will also move the address data into kernel space */ err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); if (err < 0) goto out; total_len=err; - if (msg_sys.msg_controllen) { - if (msg_sys.msg_controllen > sizeof(ctl)) { + if (msg_sys.msg_controllen) + { + if (msg_sys.msg_controllen > sizeof(ctl)) + { char *tmp = kmalloc(msg_sys.msg_controllen, GFP_KERNEL); - if (tmp == NULL) { + if (tmp == NULL) + { err = -ENOBUFS; goto failed2; } @@ -1221,12 +1166,15 @@ if (err) goto failed; } - msg_sys.msg_flags = flags; if (current->files->fd[fd]->f_flags & O_NONBLOCK) msg_sys.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &msg_sys, total_len); + if ((sock = sockfd_lookup(fd,&err))!=NULL) + { + err = sock_sendmsg(sock, &msg_sys, total_len); + sockfd_put(sock); + } failed: if (msg_sys.msg_controllen && msg_sys.msg_control != ctl) @@ -1262,17 +1210,17 @@ int *uaddr_len; lock_kernel(); - if (!(sock = sockfd_lookup(fd, &err))) - goto out; - - err = -EFAULT; if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) - goto out; - - err = -EINVAL; + { + err=-EFAULT; + goto out; + } if (msg_sys.msg_iovlen>UIO_MAXIOV) + { + err=-EFAULT; goto out; - + } + /* * Save the user-mode address (verify_iovec will change the * kernel msghdr to use the kernel address space) @@ -1291,34 +1239,35 @@ if (current->files->fd[fd]->f_flags&O_NONBLOCK) flags |= MSG_DONTWAIT; - len=sock_recvmsg(sock, &msg_sys, total_len, flags); + + + if ((sock = sockfd_lookup(fd, &err))!=NULL) + { + err=sock_recvmsg(sock, &msg_sys, total_len, flags); + if(err>=0) + len=err; + sockfd_put(sock); + } if (msg_sys.msg_iov != iov) kfree(msg_sys.msg_iov); - if (len<0) { - err = len; - goto out; - } - if (uaddr != NULL) - { + if (uaddr != NULL && err>=0) err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); - if (err) - goto out; - } - err = -EFAULT; - if (put_user(msg_sys.msg_flags, &msg->msg_flags)) - goto out; - if (put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen)) - goto out; - err = len; + if (err>=0 && (put_user(msg_sys.msg_flags, &msg->msg_flags) || + put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen))) + err = -EFAULT; out: unlock_kernel(); - return err; + if(err<0) + return err; + return len; } /* * Perform a file control on a socket file descriptor. + * + * FIXME: does this need an fd lock ? */ int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -1356,6 +1305,12 @@ if(call<1||call>SYS_RECVMSG) goto out; err = -EFAULT; + + /* + * Ideally we want to precompute the maths, but unsigned long + * isnt a fixed size.... + */ + if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long)))) goto out; @@ -1478,7 +1433,8 @@ * 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. @@ -1492,6 +1448,14 @@ #ifdef CONFIG_NETLINK init_netlink(); +#endif + + /* + * Wan router layer. + */ + +#ifdef CONFIG_WAN_ROUTER + wanrouter_init(); #endif /* diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/Makefile linux/net/wanrouter/Makefile --- v2.1.24/linux/net/wanrouter/Makefile Thu Jan 1 02:00:00 1970 +++ linux/net/wanrouter/Makefile Sun Feb 2 15:18:52 1997 @@ -0,0 +1,17 @@ +# +# Makefile for the Linux WAN router layer. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := wanrouter.o +O_OBJS := wanmain.o wanproc.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make + +tar: + tar -cvf /dev/f1 . diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/patchlevel linux/net/wanrouter/patchlevel --- v2.1.24/linux/net/wanrouter/patchlevel Thu Jan 1 02:00:00 1970 +++ linux/net/wanrouter/patchlevel Sun Feb 2 15:18:52 1997 @@ -0,0 +1 @@ +1.0.0 diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c --- v2.1.24/linux/net/wanrouter/wanmain.c Thu Jan 1 02:00:00 1970 +++ linux/net/wanrouter/wanmain.c Sun Feb 2 15:18:52 1997 @@ -0,0 +1,676 @@ +/***************************************************************************** +* wanmain.c WAN Multiprotocol Router Module. Main code. +* +* This module is completely hardware-independent and provides +* the following common services for the WAN Link Drivers: +* o WAN device managenment (registering, unregistering) +* o Network interface management +* o Physical connection management (dial-up, incomming calls) +* o Logical connection management (switched virtual circuits) +* o Protocol encapsulation/decapsulation +* +* Author: Gene Kozin +* +* 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 /* offsetof(), etc. */ +#include /* return codes */ +#include /* OS configuration options */ +#include +#include /* support for loadable modules */ +#include /* kmalloc(), kfree() */ +#include /* verify_area(), etc. */ +#include /* inline mem*, str* functions */ +#include /* kernel <-> user copy */ +#include /* htons(), etc. */ +#include /* copy_to/from_user */ +#include /* WAN router API definitions */ + +/****** Defines and Macros **************************************************/ + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +/****** Function Prototypes *************************************************/ + +/* + * Kernel loadable module interface. + */ + +#ifdef MODULE +int init_module (void); +void cleanup_module (void); +#endif + +/* + * WAN device IOCTL handlers + */ + +static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf); +static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat); +static int device_shutdown (wan_device_t* wandev); +static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf); +static int device_del_if (wan_device_t* wandev, char* u_name); + +/* + * Miscellaneous + */ + +static wan_device_t* find_device (char* name); +static int delete_interface (wan_device_t* wandev, char* name, int forse); + +/* + * Global Data + */ + +static char fullname[] = "WAN Router"; +static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char modname[] = ROUTER_NAME; /* short module name */ +static wan_device_t* devlist = NULL; /* list of registered devices */ +static int devcnt = 0; + +/* + * Organizationally Unique Identifiers for encapsulation/decapsulation + */ + +static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 }; +static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 }; + +#ifdef MODULE + +/* + * Kernel Loadable Module Entry Points + */ + +/* + * Module 'insert' entry point. + * o print announcement + * o initialize static data + * o create /proc/net/router directory and static entries + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ + +int init_module (void) +{ + int err; + + printk(KERN_INFO "%s v%u.%u %s\n", + fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); + err = wanrouter_proc_init(); + if (err) printk(KERN_ERR + "%s: can't create entry in proc filesystem!\n", modname); + return err; +} + +/* + * Module 'remove' entry point. + * o delete /proc/net/router directory and static entries. + */ + +void cleanup_module (void) +{ + wanrouter_proc_cleanup(); +} + +#else + +void wanrouter_init(void) +{ + int err = wanrouter_proc_init(); + if (err) printk(KERN_ERR + "%s: can't create entry in proc filesystem!\n", modname); +} +#endif + +/* + * Kernel APIs + */ + +/* + * Register WAN device. + * o verify device credentials + * o create an entry for the device in the /proc/net/router directory + * o initialize internally maintained fields of the wan_device structure + * o link device data space to a singly-linked list + * o if it's the first device, then start kernel 'thread' + * o increment module use count + * + * Return: + * 0 Ok + * < 0 error. + * + * Context: process + */ + +int register_wan_device(wan_device_t* wandev) +{ + int err, namelen; + + if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || + (wandev->name == NULL)) + return -EINVAL; + + namelen = strlen(wandev->name); + if (!namelen || (namelen > WAN_DRVNAME_SZ)) + return -EINVAL; + + if (find_device(wandev->name) != NULL) + return -EEXIST; + +#ifdef WANDEBUG + printk(KERN_INFO "%s: registering WAN device %s\n", + modname, wandev->name); +#endif + + /* + * Register /proc directory entry + */ + err = wanrouter_proc_add(wandev); + if (err) + { + printk(KERN_ERR + "%s: can't create /proc/net/router/%s entry!\n", + modname, wandev->name) + ; + return err; + } + + /* + * Initialize fields of the wan_device structure maintained by the + * router and update local data. + */ + + wandev->ndev = 0; + wandev->dev = NULL; + wandev->next = devlist; + devlist = wandev; + ++devcnt; + MOD_INC_USE_COUNT; /* prevent module from unloading */ + return 0; +} + +/* + * Unregister WAN device. + * o shut down device + * o unlink device data space from the linked list + * o delete device entry in the /proc/net/router directory + * o decrement module use count + * + * Return: 0 Ok + * <0 error. + * Context: process + */ + +int unregister_wan_device(char* name) +{ + wan_device_t *wandev, *prev; + + if (name == NULL) + return -EINVAL; + + for (wandev = devlist, prev = NULL; + wandev && strcmp(wandev->name, name); + prev = wandev, wandev = wandev->next) + ; + if (wandev == NULL) + return -ENODEV; + +#ifdef WANDEBUG + printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name); +#endif + + if (wandev->state != WAN_UNCONFIGURED) + { + while(wandev->dev) + delete_interface(wandev, wandev->dev->name, 1); + if (wandev->shutdown) + wandev->shutdown(wandev); + } + if (prev) + prev->next = wandev->next; + else + devlist = wandev->next; + --devcnt; + wanrouter_proc_delete(wandev); + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Encapsulate packet. + * + * Return: encapsulation header size + * < 0 - unsupported Ethertype + * + * Notes: + * 1. This function may be called on interrupt context. + */ + +int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev) +{ + int hdr_len = 0; + + switch (skb->protocol) + { + case ETH_P_IP: /* IP datagram encapsulation */ + hdr_len += 1; + skb_push(skb, 1); + skb->data[0] = NLPID_IP; + break; + + case ETH_P_IPX: /* SNAP encapsulation */ + case ETH_P_ARP: + hdr_len += 6; + skb_push(skb, 6); + skb->data[0] = NLPID_SNAP; + memcpy(&skb->data[1], oui_ether, sizeof(oui_ether)); + *((unsigned short*)&skb->data[4]) = htons(skb->protocol); + break; + + default: /* Unknown packet type */ + printk(KERN_INFO + "%s: unsupported Ethertype 0x%04X on interface %s!\n", + modname, skb->protocol, dev->name); + hdr_len = -EINVAL; + } + return hdr_len; +} + +/* + * Decapsulate packet. + * + * Return: Ethertype (in network order) + * 0 unknown encapsulation + * + * Notes: + * 1. This function may be called on interrupt context. + */ + +unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev) +{ + int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ + unsigned short ethertype; + + switch (skb->data[cnt]) + { + case NLPID_IP: /* IP datagramm */ + ethertype = htons(ETH_P_IP); + cnt += 1; + break; + + case NLPID_SNAP: /* SNAP encapsulation */ + if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))) + { + printk(KERN_INFO + "%s: unsupported SNAP OUI %02X-%02X-%02X " + "on interface %s!\n", modname, + skb->data[cnt+1], skb->data[cnt+2], + skb->data[cnt+3], dev->name); + ; + return 0; + } + ethertype = *((unsigned short*)&skb->data[cnt+4]); + cnt += 6; + break; + + /* add other protocols, e.g. CLNP, ESIS, ISIS, if needed */ + + default: + printk(KERN_INFO + "%s: unsupported NLPID 0x%02X on interface %s!\n", + modname, skb->data[cnt], dev->name) + ; + return 0; + } + skb->protocol = ethertype; + skb->pkt_type = PACKET_HOST; /* Physically point to point */ + skb->mac.raw = skb->data; + skb_pull(skb, cnt); + return ethertype; +} + +/* + * WAN device IOCTL. + * o find WAN device associated with this node + * o execute requested action or pass command to the device driver + */ + +int wanrouter_ioctl(struct inode* inode, struct file* file, + unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct proc_dir_entry* dent; + wan_device_t* wandev; + + if (!suser()) + return -EPERM; + + if ((cmd >> 8) != ROUTER_IOCTL) + return -EINVAL; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->data == NULL)) + return -EINVAL; + + wandev = dent->data; + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + switch (cmd) + { + case ROUTER_SETUP: + err = device_setup(wandev, (void*)arg); + break; + + case ROUTER_DOWN: + err = device_shutdown(wandev); + break; + + case ROUTER_STAT: + err = device_stat(wandev, (void*)arg); + break; + + case ROUTER_IFNEW: + err = device_new_if(wandev, (void*)arg); + break; + + case ROUTER_IFDEL: + err = device_del_if(wandev, (void*)arg); + break; + + case ROUTER_IFSTAT: + break; + + default: + if ((cmd >= ROUTER_USER) && + (cmd <= ROUTER_USER_MAX) && + wandev->ioctl) + err = wandev->ioctl(wandev, cmd, arg) + ; + else err = -EINVAL; + } + return err; +} + +/* + * WAN Driver IOCTL Handlers + */ + +/* + * Setup WAN link device. + * o verify user address space + * o allocate kernel memory and copy configuration data to kernel space + * o if configuration data includes extension, copy it to kernel space too + * o call driver's setup() entry point + */ + +static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf) +{ + void* data; + wandev_conf_t* conf; + int err= -EINVAL; + + if (wandev->setup == NULL) /* Nothing to do ? */ + return 0; + + conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); + if (conf == NULL) + return -ENOBUFS; + + if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) + { + kfree(conf); + return -EFAULT; + } + + if (conf->magic != ROUTER_MAGIC) + goto bail; + + if (conf->data_size && conf->data) + { + if(conf->data_size > 1024 || conf->data_size < 0) + goto bail; + data = kmalloc(conf->data_size, GFP_KERNEL); + if (data) + { + if(!copy_from_user(data, conf->data, conf->data_size)) + { + conf->data=data; + wandev->setup(wandev,conf); + } + else + err = -ENOBUFS; + } + if (data) + kfree(data); + } +bail: + kfree(conf); + return err; +} + +/* + * Shutdown WAN device. + * o delete all not opened logical channels for this device + * o call driver's shutdown() entry point + */ + +static int device_shutdown (wan_device_t* wandev) +{ + struct device* dev; + + if (wandev->state == WAN_UNCONFIGURED) + return 0; + + for (dev = wandev->dev; dev;) + { + if (delete_interface(wandev, dev->name, 0)) + dev = dev->slave; + } + if (wandev->ndev) + return -EBUSY; /* there are opened interfaces */ + + if (wandev->shutdown) + return wandev->shutdown(wandev); + return 0; +} + +/* + * Get WAN device status & statistics. + */ + +static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat) +{ + wandev_stat_t stat; + + memset(&stat, 0, sizeof(stat)); + + /* Ask device driver to update device statistics */ + if ((wandev->state != WAN_UNCONFIGURED) && wandev->update) + wandev->update(wandev); + + /* Fill out structure */ + stat.ndev = wandev->ndev; + stat.state = wandev->state; + + if(copy_to_user(u_stat, &stat, sizeof(stat))) + return -EFAULT; + return 0; +} + +/* + * Create new WAN interface. + * o verify user address space + * o copy configuration data to kernel address space + * o allocate network interface data space + * o call driver's new_if() entry point + * o make sure there is no interface name conflict + * o register network interface + */ + +static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf) +{ + wanif_conf_t conf; + struct device* dev; + int err; + + if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) + return -ENODEV; + + if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t))) + return -EFAULT; + + if (conf.magic != ROUTER_MAGIC) + return -EINVAL; + + dev = kmalloc(sizeof(struct device), GFP_KERNEL); + if (dev == NULL) + return -ENOBUFS; + + memset(dev, 0, sizeof(struct device)); + err = wandev->new_if(wandev, dev, &conf); + if (!err) + { + /* Register network interface. This will invoke init() + * function supplied by the driver. If device registered + * successfully, add it to the interface list. + */ + if (dev->name == NULL) + err = -EINVAL; + + else if (dev_get(dev->name)) + err = -EEXIST; /* name already exists */ + else + { +#ifdef WANDEBUG + printk(KERN_INFO "%s: registering interface %s...\n", + modname, dev->name); +#endif + err = register_netdev(dev); + if (!err) + { + cli(); /***** critical section start *****/ + dev->slave = wandev->dev; + wandev->dev = dev; + ++wandev->ndev; + sti(); /****** critical section end ******/ + return 0; /* done !!! */ + } + } + if (wandev->del_if) + wandev->del_if(wandev, dev); + } + kfree(dev); + return err; +} + +/* + * Delete WAN logical channel. + * o verify user address space + * o copy configuration data to kernel address space + */ + +static int device_del_if (wan_device_t* wandev, char* u_name) +{ + char name[WAN_IFNAME_SZ + 1]; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + memset(name, 0, sizeof(name)); + if(copy_from_user(name, u_name, WAN_IFNAME_SZ)) + return -EFAULT; + return delete_interface(wandev, name, 0); +} + +/* + * Miscellaneous Functions + */ + +/* + * Find WAN device by name. + * Return pointer to the WAN device data space or NULL if device not found. + */ + +static wan_device_t* find_device (char* name) +{ + wan_device_t* wandev; + + for (wandev = devlist;wandev && strcmp(wandev->name, name); + wandev = wandev->next); + return wandev; +} + +/* + * Delete WAN logical channel identified by its name. + * o find logical channel by its name + * o call driver's del_if() entry point + * o unregister network interface + * o unlink channel data space from linked list of channels + * o release channel data space + * + * Return: 0 success + * -ENODEV channel not found. + * -EBUSY interface is open + * + * Note: If (force != 0), then device will be destroyed even if interface + * associated with it is open. It's caller's responsibility to make + * sure that opened interfaces are not removed! + */ + +static int delete_interface (wan_device_t* wandev, char* name, int force) +{ + struct device *dev, *prev; + + for (dev = wandev->dev, prev = NULL; + dev && strcmp(name, dev->name); + prev = dev, dev = dev->slave); + + if (dev == NULL) + return -ENODEV; /* interface not found */ + + if (dev->start) + { + if (force) + { + printk(KERN_WARNING + "%s: deleting opened interface %s!\n",modname, name); + } + else + return -EBUSY; /* interface in use */ + } + if (wandev->del_if) + wandev->del_if(wandev, dev); + + cli(); /***** critical section start *****/ + if (prev) + prev->slave = dev->slave; + else + wandev->dev = dev->slave; + --wandev->ndev; + sti(); /****** critical section end ******/ + + unregister_netdev(dev); + kfree(dev); + return 0; +} + +/* + * End + */ diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c --- v2.1.24/linux/net/wanrouter/wanproc.c Thu Jan 1 02:00:00 1970 +++ linux/net/wanrouter/wanproc.c Sun Feb 2 16:44:21 1997 @@ -0,0 +1,460 @@ +/***************************************************************************** +* wanproc.c WAN Multiprotocol Router Module. proc filesystem interface. +* +* This module is completely hardware-independent and provides +* access to the router using Linux /proc filesystem. +* +* Author: Gene Kozin +* +* 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 /* offsetof(), etc. */ +#include /* return codes */ +#include +#include /* kmalloc(), kfree() */ +#include /* verify_area(), etc. */ +#include /* inline mem*, str* functions */ +#include /* kernel <-> user copy */ +#include /* htons(), etc. */ +#include /* copy_to_user */ +#include /* 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 + * entry for each WAN device + */ + +/* + * Generic /proc/net/router/ 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/ 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 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 + */ + diff -u --recursive --new-file v2.1.24/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.24/linux/net/x25/af_x25.c Sun Feb 2 15:46:23 1997 +++ linux/net/x25/af_x25.c Sun Feb 2 15:18:53 1997 @@ -421,28 +421,6 @@ return -EOPNOTSUPP; } -static void def_callback1(struct sock *sk) -{ - if (!sk->dead) - wake_up_interruptible(sk->sleep); -} - -static void def_callback2(struct sock *sk, int len) -{ - if (!sk->dead) { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 1); - } -} - -static void def_callback3(struct sock *sk) -{ - if (!sk->dead) { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 2); - } -} - static struct sock *x25_alloc_socket(void) { struct sock *sk; @@ -463,16 +441,7 @@ MOD_INC_USE_COUNT; - skb_queue_head_init(&sk->receive_queue); - skb_queue_head_init(&sk->write_queue); - skb_queue_head_init(&sk->back_log); - - init_timer(&sk->timer); - - sk->state_change = def_callback1; - sk->data_ready = def_callback2; - sk->write_space = def_callback3; - sk->error_report = def_callback1; + sock_init_data(NULL, sk); skb_queue_head_init(&x25->fragment_queue); skb_queue_head_init(&x25->interrupt_in_queue); @@ -494,30 +463,17 @@ 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; - } - - 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_init_data(sock, sk); - x25->state = X25_STATE_0; + sock->ops = &x25_proto_ops; + sk->protocol = protocol; + sk->mtu = X25_DEFAULT_PACKET_SIZE; /* X25_PS128 */ + + 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; diff -u --recursive --new-file v2.1.24/linux/net/x25/x25_link.c linux/net/x25/x25_link.c --- v2.1.24/linux/net/x25/x25_link.c Thu Jan 23 21:06:59 1997 +++ linux/net/x25/x25_link.c Sun Feb 2 15:18:53 1997 @@ -52,31 +52,14 @@ { unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); del_timer(&neigh->timer); restore_flags(flags); - neigh->timer.next = neigh->timer.prev = NULL; neigh->timer.data = (unsigned long)neigh; neigh->timer.function = &x25_link_timer; - neigh->timer.expires = jiffies + 100; - add_timer(&neigh->timer); -} -static void x25_link_reset_timer(struct x25_neigh *neigh) -{ - unsigned long flags; - - save_flags(flags); - cli(); - del_timer(&neigh->timer); - restore_flags(flags); - - neigh->timer.data = (unsigned long)neigh; - neigh->timer.function = &x25_link_timer; - neigh->timer.expires = jiffies + 100; add_timer(&neigh->timer); } @@ -91,7 +74,7 @@ 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; } diff -u --recursive --new-file v2.1.24/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c --- v2.1.24/linux/net/x25/x25_timer.c Thu Jan 23 21:06:59 1997 +++ linux/net/x25/x25_timer.c Sun Feb 2 15:18:53 1997 @@ -42,36 +42,14 @@ static void x25_timer(unsigned long); /* - * Linux set/reset timer routines + * Linux set timer */ void x25_set_timer(struct sock *sk) { unsigned long flags; - save_flags(flags); - cli(); - + save_flags(flags); cli(); del_timer(&sk->timer); - - restore_flags(flags); - - sk->timer.next = sk->timer.prev = NULL; - sk->timer.data = (unsigned long)sk; - sk->timer.function = &x25_timer; - sk->timer.expires = jiffies + 100; - - add_timer(&sk->timer); -} - -static void x25_reset_timer(struct sock *sk) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - del_timer(&sk->timer); - restore_flags(flags); sk->timer.data = (unsigned long)sk; @@ -125,7 +103,7 @@ } if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) { - x25_reset_timer(sk); + x25_set_timer(sk); return; }