]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.50pre1 2.3.50pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:32:25 +0000 (15:32 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:32:25 +0000 (15:32 -0500)
93 files changed:
Documentation/Configure.help
Documentation/networking/cs89x0.txt
Makefile
arch/i386/kernel/irq.c
arch/i386/mm/init.c
arch/ppc/configs/common_defconfig
arch/ppc/defconfig
arch/ppc/kernel/Makefile
arch/ppc/kernel/feature.c
arch/ppc/kernel/head.S
arch/ppc/kernel/irq.c
arch/ppc/kernel/pci.c
arch/ppc/kernel/pmac_pic.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/ppc_htab.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/setup.c
arch/ppc/mm/init.c
arch/ppc/xmon/start.c
arch/ppc/xmon/xmon.c
arch/sparc64/kernel/setup.c
arch/sparc64/lib/blockops.S
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
drivers/block/Config.in
drivers/block/ali14xx.c
drivers/block/cpqarray.h
drivers/block/ide-cd.c
drivers/block/ide-pmac.c
drivers/block/ide-proc.c
drivers/block/nbd.c
drivers/cdrom/cdrom.c
drivers/char/epca.c
drivers/char/istallion.c
drivers/char/stradis.c
drivers/char/videodev.c
drivers/isdn/avmb1/b1dma.c
drivers/isdn/avmb1/c4.c
drivers/net/3c505.c
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/acenic.c
drivers/net/acenic.h
drivers/net/appletalk/Config.in [new file with mode: 0644]
drivers/net/appletalk/Makefile [new file with mode: 0644]
drivers/net/appletalk/cops.c [new file with mode: 0644]
drivers/net/appletalk/cops.h [new file with mode: 0644]
drivers/net/appletalk/cops_ffdrv.h [new file with mode: 0644]
drivers/net/appletalk/cops_ltdrv.h [new file with mode: 0644]
drivers/net/appletalk/ipddp.c [new file with mode: 0644]
drivers/net/appletalk/ipddp.h [new file with mode: 0644]
drivers/net/appletalk/ltpc.c [new file with mode: 0644]
drivers/net/appletalk/ltpc.h [new file with mode: 0644]
drivers/net/cops.c [deleted file]
drivers/net/cops.h [deleted file]
drivers/net/cops_ffdrv.h [deleted file]
drivers/net/cops_ltdrv.h [deleted file]
drivers/net/cs89x0.c
drivers/net/cs89x0.h
drivers/net/ipddp.c [deleted file]
drivers/net/ipddp.h [deleted file]
drivers/net/ltpc.c [deleted file]
drivers/net/ltpc.h [deleted file]
drivers/net/ncr885e.c
drivers/net/net_init.c
drivers/net/tokenring/Config.in
drivers/net/tokenring/Makefile
drivers/net/via-rhine.c
drivers/net/yellowfin.c
drivers/parport/Config.in
drivers/parport/parport_pc.c
drivers/pcmcia/yenta.c
drivers/scsi/sr.c
drivers/sound/ac97_codec.c
drivers/sound/trident.c
drivers/sound/trident.h
drivers/usb/Config.in
drivers/usb/usb-ohci.c
drivers/usb/usb-serial.c
drivers/video/riva/fbdev.c
fs/block_dev.c
fs/proc/proc_misc.c
fs/proc/root.c
fs/udf/udfdecl.h
include/asm-ppc/types.h
include/linux/ac97_codec.h
include/linux/cdrom.h
include/linux/ide.h
ipc/shm.c
net/Config.in
net/netsyms.c

index 87688bfcb76ea15f81134fe66d2ce980db5bb6dc..908f120edc9db9da3ef1eda9c7c7ba756a8649e7 100644 (file)
@@ -2268,10 +2268,11 @@ CONFIG_M386
      UMC U5D or U5S.
    - "586" for generic Pentium CPUs, possibly lacking the TSC 
      (time stamp counter) register.
-   - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and 
-     K6-3D.
+   - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5.
    - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
      Intel Pentium II/Pentium Pro.
+   - "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D).
+   - "Athlon" for the AMD Athlon (aka K7)
 
   If you don't know what to do, choose "386".
 
@@ -5990,7 +5991,8 @@ CONFIG_AIRONET4500
        adhoc=1         there are no Access Points around
        master=1        Adhoc master (the one who creates network sync)
        slave=1         Adhoc slave(btw, it is still forming own net 
-                       sometimes)
+                       sometimes, and has problems with firmware...
+                       change IbssJoinNetTimeout from /proc...)
        channel=1..?    meaningful in adhoc mode
   all other parameters can be set via /proc interface
   These parameters belong to .._card module, but alas, they are here
@@ -8411,7 +8413,7 @@ CONFIG_USB_UHCI
   
 USB-UHCI High Bandwidth support
 CONFIG_USB_UHCI_HIGH_BANDWIDTH
-  This option enables the so called reclamation loop in usb-uhci, thus
+  This option enables the so-called reclamation loop in usb-uhci, thus
   allowing much higher transfer bandwidth for USB-bulk and control
   messages; isochronous transfers (audio, video etc.) are not affected.
   Due to a very simple design of the UHCI controller, this may cause
@@ -8651,13 +8653,14 @@ CONFIG_USB_OV511
   The module will be called ov511.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-USB ADMtek's Pegasus based ethernet devices support
+USB ADMtek Pegasus-based ethernet device support
 CONFIG_USB_PEGASUS
-  Say Y if you want to use your usb ethernet device. Note that
-  the code is still experimental. If you have devices with other
-  vendor IDs than ADMtek's you should change/add them in the
+  Say Y if you want to use your USB ethernet device. Note that
+  the code is still experimental. If you have devices with vendor
+  IDs other than ADMtek's, you should change/add them in the
   driver code and send a message to me (petkan@spct.net) for 
   update.
+
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called ov511.o. If you want to compile it as a
@@ -8742,9 +8745,9 @@ CONFIG_USB_DABUSB
  
 PLUSB driver
 CONFIG_USB_PLUSB
-  A driver for the Prolific PL-2302 USB to USB network device. This 'USB
-  cable' connects two hosts via a point to point network with bandwidth of
-  5Mbit/s.  Configure this driver after connecting the USB cable via
+  A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB
+  cable' connects two hosts via a point-to-point network with bandwidth of
+  5 Mbit/s.  Configure this driver after connecting the USB cable via
   ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 
   (and vice versa on the other host).
 
index f26fad4981f48ee7ff9a1501e6d3aa229fa4f9be..24f15cb7114647778acc314146a4c35f1f717462 100644 (file)
-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
-
-
-
-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 modification 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 exist. 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 example 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 additional 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 net_device *dev);
-
-
-Example:
-
- extern int ultra_probe(struct net_device *dev);
- extern int wd_probe(struct net_device *dev);
- extern int el2_probe(struct net_device *dev);
-
- extern int cs89x0_probe(struct net_device *dev);
-
- extern int ne_probe(struct net_device *dev);
- extern int hp_probe(struct net_device *dev);
- extern int hp_plus_probe(struct net_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 
-known 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 ensures 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 ensures 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 ensures there are no conflicts with the assigned IRQ
-     signal.
-
-   * EEPROM Test
-     The EEPROM test ensures the EEPROM can be read.
-
-   * Chip RAM Test
-     The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is
-     working properly.
-
-   * Internal Loop-back Test
-     The Internal Loop Back test ensures 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 ensures 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 Adapter
-A000-C7FF      VGA Graphics Adapter
-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
-E-mail    :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
-latest drivers and technical publications.
-
-
-6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
-
-Access to the BBS is available 24 hours a day, seven days a week. Baud 
-rates from 300K to 14.4K are supported as well as most common file transfer 
-protocols.  
-
-To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, 
-and no parity.  Dial (512) 441-3265 and press <ENTER> after connection is made.
-Login using your account name and password.  (If you do not have an account, 
-you may login as "GUEST".  No password is required for the Guest account.)
-
-From the main system menu, select the "Enter Public File Area" menu option.  
-From the Public File Area menu, select the "LAN (Local Area Network)" file
-area.  A list of the latest drivers and support utilities available for the
-CS89XX ISA Ethernet adapter will be presented along with the option to download
-the file(s) of your choice.
-
-
+\r
+NOTE\r
+----\r
+\r
+This document was contributed by Cirrus Logic for kernel 2.2.5.  This version\r
+has been updated for 2.3.48 by Andrew Morton <andrewm@uow.edu.au>\r
+\r
+Cirrus make a copy of this driver available at their website, as\r
+described below.  In general, you should use the driver version which\r
+comes with your Linux distribution.\r
+\r
+\r
+\r
+CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS\r
+Linux Network Interface Driver ver. 2.00 <kernel 2.3.48>\r
+===============================================================================\r
\r
+\r
+TABLE OF CONTENTS\r
+\r
+1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS\r
+    1.1 Product Overview \r
+    1.2 Driver Description\r
+       1.2.1 Driver Name\r
+       1.2.2 File in the Driver Package\r
+    1.3 System Requirements\r
+    1.4 Licensing Information\r
+\r
+2.0 ADAPTER INSTALLATION and CONFIGURATION\r
+    2.1 CS8900-based Adapter Configuration\r
+    2.2 CS8920-based Adapter Configuration \r
+\r
+3.0 LOADING THE DRIVER AS A MODULE\r
+\r
+4.0 COMPILING THE DRIVER\r
+    4.1 Compiling the Driver as a Loadable Module\r
+    4.2 Compiling the driver to support memory mode\r
+    4.3 Compiling the driver to support Rx DMA \r
+    4.4 Compiling the Driver into the Kernel\r
+\r
+5.0 TESTING AND TROUBLESHOOTING\r
+    5.1 Known Defects and Limitations\r
+    5.2 Testing the Adapter\r
+        5.2.1 Diagnostic Self-Test\r
+        5.2.2 Diagnostic Network Test\r
+    5.3 Using the Adapter's LEDs\r
+    5.4 Resolving I/O Conflicts\r
+\r
+6.0 TECHNICAL SUPPORT\r
+    6.1 Contacting Cirrus Logic's Technical Support\r
+    6.2 Information Required Before Contacting Technical Support\r
+    6.3 Obtaining the Latest Driver Version\r
+    6.4 Current maintainer\r
+\r
+\r
+\r
+1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS\r
+===============================================================================\r
+\r
+\r
+1.1 PRODUCT OVERVIEW\r
+\r
+The CS8900-based ISA Ethernet Adapters from Cirrus Logic follow \r
+IEEE 802.3 standards and support half or full-duplex operation in ISA bus \r
+computers on 10 Mbps Ethernet networks.  The adapters are designed for operation \r
+in 16-bit ISA or EISA bus expansion slots and are available in \r
+10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 \r
+or fiber networks).  \r
+\r
+CS8920-based adapters are similar to the CS8900-based adapter with additional \r
+features for Plug and Play (PnP) support and Wakeup Frame recognition.  As \r
+such, the configuration procedures differ somewhat between the two types of \r
+adapters.  Refer to the "Adapter Configuration" section for details on \r
+configuring both types of adapters.\r
+\r
+\r
+1.2 DRIVER DESCRIPTION\r
+\r
+The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux\r
+v2.3.48 or greater kernel.  It can be compiled directly into the kernel\r
+or loaded at run-time as a device driver module.\r
+\r
+1.2.1 Driver Name: cs89x0\r
+\r
+1.2.2 Files in the Driver Archive:\r
+\r
+The files in the driver at Cirrus' website include:\r
+\r
+  readme.txt         - this file\r
+  build              - batch file to compile cs89x0.c.\r
+  cs89x0.c           - driver C code\r
+  cs89x0.h           - driver header file\r
+  cs89x0.o           - pre-compiled module (for v2.2.5 kernel)\r
+  config/Config.in   - sample file to include cs89x0 driver in the kernel.\r
+  config/Makefile    - sample file to include cs89x0 driver in the kernel.\r
+  config/Space.c     - sample file to include cs89x0 driver in the kernel.\r
+\r
+\r
+\r
+1.3 SYSTEM REQUIREMENTS\r
+\r
+The following hardware is required:\r
+\r
+   * Cirrus Logic LAN (CS8900/20-based) Ethernet ISA Adapter   \r
+\r
+   * IBM or IBM-compatible PC with:\r
+     * An 80386 or higher processor\r
+     * 16 bytes of contiguous IO space available between 210h - 370h\r
+     * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920).\r
+\r
+   * Appropriate cable (and connector for AUI, 10BASE-2) for your network\r
+     topology.\r
+\r
+The following software is required:\r
+\r
+* LINUX kernel version 2.3.48 or higher\r
+\r
+   * CS8900/20 Setup Utility (DOS-based)\r
+\r
+   * LINUX kernel sources for your kernel (if compiling into kernel)\r
+\r
+   * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel \r
+     or a module)   \r
+\r
+\r
+\r
+1.4 LICENSING INFORMATION\r
+\r
+This program is free software; you can redistribute it and/or modify it under\r
+the terms of the GNU General Public License as published by the Free Software\r
+Foundation, version 1.\r
+\r
+This program is distributed in the hope that it will be useful, but WITHOUT\r
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for \r
+more details.\r
+\r
+For a full copy of the GNU General Public License, write to the Free Software\r
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+\r
+\r
+2.0 ADAPTER INSTALLATION and CONFIGURATION\r
+===============================================================================\r
+\r
+Both the CS8900 and CS8920-based adapters can be configured using parameters \r
+stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup \r
+Utility if you want to change the adapter's configuration in EEPROM.  \r
+\r
+When loading the driver as a module, you can specify many of the adapter's \r
+configuration parameters on the command-line to override the EEPROM's settings \r
+or for interface configuration when an EEPROM is not used. (CS8920-based \r
+adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE.\r
+\r
+Since the CS8900/20 Setup Utility is a DOS-based application, you must install \r
+and configure the adapter in a DOS-based system using the CS8900/20 Setup \r
+Utility before installation in the target LINUX system.  (Not required if \r
+installing a CS8900-based adapter and the default configuration is acceptable.)\r
+     \r
+\r
+2.1 CS8900-BASED ADAPTER CONFIGURATION\r
+\r
+CS8900-based adapters shipped from Cirrus Logic have been configured \r
+with the following "default" settings:\r
+\r
+  Operation Mode:      Memory Mode\r
+  IRQ:                 10\r
+  Base I/O Address:    300\r
+  Memory Base Address: D0000\r
+  Optimization:               DOS Client\r
+  Transmission Mode:   Half-duplex\r
+  BootProm:            None\r
+  Media Type:         Autodetect (3-media cards) or \r
+                       10BASE-T (10BASE-T only adapter)\r
+\r
+You should only change the default configuration settings if conflicts with \r
+another adapter exists. To change the adapter's configuration, run the \r
+CS8900/20 Setup Utility. \r
+\r
+\r
+2.2 CS8920-BASED ADAPTER CONFIGURATION\r
+\r
+CS8920-based adapters are shipped from Cirrus Logic configured as Plug\r
+and Play (PnP) enabled.  However, since the cs89x0 driver does NOT\r
+support PnP, you must install the CS8920 adapter in a DOS-based PC and\r
+run the CS8900/20 Setup Utility to disable PnP and configure the\r
+adapter before installation in the target Linux system.  Failure to do\r
+this will leave the adapter inactive and the driver will be unable to\r
+communicate with the adapter.  \r
+\r
+\r
+        **************************************************************** \r
+        *                    CS8920-BASED ADAPTERS:                    *\r
+        *                                                              * \r
+        * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT.  * \r
+        * THE CS89X0 DRIVER DOES NOT SUPPORT PnP. THEREFORE, YOU MUST  *\r
+        * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND   *\r
+        * TO ACTIVATE THE ADAPTER.                                     *\r
+        ****************************************************************\r
+\r
+\r
+\r
+\r
+3.0 LOADING THE DRIVER AS A MODULE\r
+===============================================================================\r
+\r
+If the driver is compiled as a loadable module, you can load the driver module\r
+with the 'modprobe' command.  Many of the adapter's configuration parameters can \r
+be specified as command-line arguments to the load command.  This facility \r
+provides a means to override the EEPROM's settings or for interface \r
+configuration when an EEPROM is not used.\r
+\r
+Example:\r
+\r
+    insmod cs89x0.o io=0x200 irq=0xA media=aui\r
+\r
+This exmaple loads the module and configures the adapter to use an IO port base\r
+address of 200h, interrupt 10, and use the AUI media connection.  The following\r
+configuration options are available on the command line:\r
+\r
+* io=###               - specify IO address (200h-360h)\r
+* irq=##               - specify interrupt level\r
+* use_dma=1            - Enable DMA\r
+* dma=#                - specify dma channel (Driver is compiled to support\r
+                         Rx DMA only)\r
+* dmasize=# (16 or 64) - DMA size 16K or 64K.  Default value is set to 16.\r
+* media=rj45           - specify media type\r
+   or media=bnc\r
+   or media=aui\r
+   or medai=auto\r
+* duplex=full          - specify forced half/full/autonegotiate duplex\r
+   or duplex=half\r
+   or duplex=auto\r
+* debug=#              - debug level (only available if the driver was compiled\r
+                         for debugging)\r
+\r
+NOTES:\r
+\r
+a) If an EEPROM is present, any specified command-line parameter\r
+   will override the corresponding configuration value stored in\r
+   EEPROM.\r
+\r
+b) The "io" parameter must be specified on the command-line.  \r
+\r
+c) In case you can not re-load the driver because Linux system\r
+   returns the "device or resource busy" message, try to re-load it by\r
+   increment the IO port address by one.  The driver will write\r
+   commands to the IO base addresses to reset the data port pointer. \r
+   You can specify an I/O address with an address value one greater\r
+   than the configured address.  Example, to scan for an adapter\r
+   located at IO base 0x300, specify an IO address of 0x301.  \r
+\r
+d) The "duplex=auto" parameter is only supported for the CS8920.\r
+\r
+e) The minimum command-line configuration required if an EEPROM is\r
+   not present is:\r
+\r
+   io \r
+   irq \r
+   media type (no autodetect)\r
+\r
+f) The following addtional parameters are CS89XX defaults (values\r
+   used with no EEPROM or command-line argument).\r
+\r
+   * DMA Burst = enabled\r
+   * IOCHRDY Enabled = enabled\r
+   * UseSA = enabled\r
+   * CS8900 defaults to half-duplex if not specified on command-line\r
+   * CS8920 defaults to autoneg if not specified on command-line\r
+   * Use reset defaults for other config parameters\r
+   * dma_mode = 0\r
+\r
+g) You can use ifconfig to set the adapter's Ethernet address.\r
+\r
+h) Many Linux distributions use the 'modprobe' command to load\r
+   modules.  This program uses the '/etc/conf.modules' file to\r
+   determine configuration information which is passed to a driver\r
+   module when it is loaded.  All the configuration options which are\r
+   described above may be placed within /etc/conf.modules.\r
+\r
+   For example:\r
+\r
+   > cat /etc/conf.modules\r
+   ...\r
+   alias eth0 cs89x0\r
+   options cs89x0 io=0x0200 dma=5 use_dma=1\r
+   ...\r
+\r
+   In this example we are telling the module system that the\r
+   ethernet driver for this machine should use the cs89x0 driver.  We\r
+   are asking 'modprobe' to pass the 'io', 'dma' and 'use_dma'\r
+   arguments to the driver when it is loaded.\r
+\r
+i) Cirrus recommend that the cs89x0 use the ISA DMA channels 5, 6 or\r
+   7.  You will probably find that other DMA channels will not work.\r
+\r
+j) The cs89x0 supports DMA for receiving only.  DMA mode is\r
+   significantly more efficient.  Flooding a 400 MHz Celeron machine\r
+   with large ping packets consumes 82% of its CPU capacity in non-DMA\r
+   mode.  With DMA this is reduced to 45%.\r
+\r
+k) If your Linux kernel was compiled with inbuilt plug-and-play\r
+   support you will be able to find information about the cs89x0 card\r
+   with the command\r
+\r
+   cat /proc/isapnp\r
+\r
+l) If during DMA operation you find erratic behavior or network data\r
+   corruption you should use your PC's BIOS to slow the EISA bus clock.\r
+\r
+\r
+4.0 COMPILING THE DRIVER\r
+===============================================================================\r
+\r
+The cs89x0 driver can be compiled directly into the kernel or compiled into\r
+a loadable device driver module.\r
+\r
+\r
+4.1 COMPILING THE DRIVER AS A LOADABLE MODULE\r
+\r
+To compile the driver into a loadable module, use the following command \r
+(single command line, without quotes):\r
+\r
+"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall \r
+-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS \r
+-c cs89x0.c"\r
+\r
+4.2 COMPILING THE DRIVER TO SUPPORT MEMORY MODE\r
+\r
+Support for memory mode was not carried over into the 2.3 series kernels.\r
+\r
+4.3 COMPILING THE DRIVER TO SUPPORT Rx DMA\r
+\r
+The compile-time optionality for DMA was removed in the 2.3 kernel\r
+series.  DMA support is now unconditionally part of the driver.  It is\r
+enabled by the 'use_dma=1' module option.\r
+\r
+4.4 COMPILING THE DRIVER INTO THE KERNEL\r
+\r
+If your Linux distribution already has support for the cs89x0 driver\r
+then simply copy the source file to the /usr/src/linux/drivers/net\r
+directory to replace the original ones and run the make utility to\r
+rebuild the kernel.  See Step 3 for rebuilding the kernel.\r
+\r
+If your Linux does not include the cs89x0 driver, you need to edit three \r
+configuration files, copy the source file to the /usr/src/linux/drivers/net\r
+directory, and then run the make utility to rebuild the kernel.\r
+\r
+1. Edit the following configuration files by adding the statements as\r
+indicated.  (When possible, try to locate the added text to the section of the\r
+file containing similar statements).\r
+\r
+\r
+a.) In /usr/src/linux/drivers/net/Config.in, add:\r
+\r
+tristate 'CS89x0 support' CONFIG_CS89x0\r
+\r
+Example:\r
+\r
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then\r
+       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I\r
+     fi\r
+\r
+     tristate 'CS89x0 support' CONFIG_CS89x0\r
+\r
+     tristate 'NE2000/NE1000 support' CONFIG_NE2000\r
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then\r
+       tristate 'NI5210 support' CONFIG_NI52\r
+\r
+\r
+b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: \r
+\r
+ifeq ($(CONFIG_CS89x0),y)\r
+L_OBJS += cs89x0.o\r
+else\r
+  ifeq ($(CONFIG_CS89x0),m)\r
+  M_OBJS += cs89x0.o\r
+  endif\r
+endif\r
+\r
+\r
+c.) In /linux/drivers/net/Space.c file, add the line:\r
+\r
+extern int cs89x0_probe(struct device *dev);\r
+\r
+\r
+Example:\r
+\r
+ extern int ultra_probe(struct device *dev);\r
+ extern int wd_probe(struct device *dev);\r
+ extern int el2_probe(struct device *dev);\r
+\r
+ extern int cs89x0_probe(struct device *dev);\r
+\r
+ extern int ne_probe(struct device *dev);\r
+ extern int hp_probe(struct device *dev);\r
+ extern int hp_plus_probe(struct device *dev);\r
+\r
+\r
+Also add:\r
+\r
+ #ifdef CONFIG_CS89x0\r
+       { cs89x0_probe,0 },\r
+ #endif\r
+\r
+\r
+2.) Copy the driver source files (cs89x0.c and cs89x0.h) \r
+into the /usr/src/linux/drivers/net directory.\r
+\r
+\r
+3.) Go to /usr/src/linux directory and run 'make config' followed by 'make dep' \r
+and finally 'make' (or make bzImage) to rebuild the kernel. \r
+\r
+4.) Use the DOS 'setup' utility to disable plug and play on the NIC.\r
+\r
+\r
+5.0 TESTING AND TROUBLESHOOTING\r
+===============================================================================\r
+\r
+5.1 KNOWN DEFECTS and LIMITATIONS\r
+\r
+Refer to the RELEASE.TXT file distributed as part of this archive for a list of \r
+known defects, driver limitations, and work arounds.\r
+\r
+\r
+5.2 TESTING THE ADAPTER\r
+\r
+Once the adapter has been installed and configured, the diagnostic option of \r
+the CS8900/20 Setup Utility can be used to test the functionality of the \r
+adapter and its network connection.  Use the diagnostics 'Self Test' option to\r
+test the functionality of the adapter with the hardware configuration you have\r
+assigned. You can use the diagnostics 'Network Test' to test the ability of the\r
+adapter to communicate across the Ethernet with another PC equipped with a \r
+CS8900/20-based adapter card (it must also be running the CS8900/20 Setup \r
+Utility).\r
+\r
+         NOTE: The Setup Utility's diagnostics are designed to run in a\r
+         DOS-only operating system environment.  DO NOT run the diagnostics \r
+         from a DOS or command prompt session under Windows 95, Windows NT, \r
+         OS/2, or other operating system.\r
+\r
+To run the diagnostics tests on the CS8900/20 adapter:\r
+\r
+   1.) Boot DOS on the PC and start the CS8900/20 Setup Utility.\r
+\r
+   2.) The adapter's current configuration is displayed.  Hit the ENTER key to\r
+       get to the main menu.\r
+\r
+   4.) Select 'Diagnostics' (ALT-G) from the main menu.  \r
+       * Select 'Self-Test' to test the adapter's basic functionality.\r
+       * Select 'Network Test' to test the network connection and cabling.\r
+\r
+\r
+5.2.1 DIAGNOSTIC SELF-TEST\r
+\r
+The diagnostic self-test checks the adapter's basic functionality as well as \r
+its ability to communicate across the ISA bus based on the system resources \r
+assigned during hardware configuration.  The following tests are performed:\r
+\r
+   * IO Register Read/Write Test\r
+     The IO Register Read/Write test insures that the CS8900/20 can be \r
+     accessed in IO mode, and that the IO base address is correct.\r
+\r
+   * Shared Memory Test\r
+     The Shared Memory test insures the CS8900/20 can be accessed in memory \r
+     mode and that the range of memory addresses assigned does not conflict \r
+     with other devices in the system.\r
+\r
+   * Interrupt Test\r
+     The Interrupt test insures there are no conflicts with the assigned IRQ\r
+     signal.\r
+\r
+   * EEPROM Test\r
+     The EEPROM test insures the EEPROM can be read.\r
+\r
+   * Chip RAM Test\r
+     The Chip RAM test insures the 4K of memory internal to the CS8900/20 is\r
+     working properly.\r
+\r
+   * Internal Loop-back Test\r
+     The Internal Loop Back test insures the adapter's transmitter and \r
+     receiver are operating properly.  If this test fails, make sure the \r
+     adapter's cable is connected to the network (check for LED activity for \r
+     example).\r
+\r
+   * Boot PROM Test\r
+     The Boot PROM  test insures the Boot PROM is present, and can be read.\r
+     Failure indicates the Boot PROM  was not successfully read due to a\r
+     hardware problem or due to a conflicts on the Boot PROM address\r
+     assignment. (Test only applies if the adapter is configured to use the\r
+     Boot PROM option.)\r
+\r
+Failure of a test item indicates a possible system resource conflict with \r
+another device on the ISA bus.  In this case, you should use the Manual Setup \r
+option to reconfigure the adapter by selecting a different value for the system\r
+resource that failed.\r
+\r
+\r
+5.2.2 DIAGNOSTIC NETWORK TEST\r
+\r
+The Diagnostic Network Test verifies a working network connection by \r
+transferring data between two CS8900/20 adapters installed in different PCs \r
+on the same network. (Note: the diagnostic network test should not be run \r
+between two nodes across a router.) \r
+\r
+This test requires that each of the two PCs have a CS8900/20-based adapter\r
+installed and have the CS8900/20 Setup Utility running.  The first PC is \r
+configured as a Responder and the other PC is configured as an Initiator.  \r
+Once the Initiator is started, it sends data frames to the Responder which \r
+returns the frames to the Initiator.\r
+\r
+The total number of frames received and transmitted are displayed on the \r
+Initiator's display, along with a count of the number of frames received and \r
+transmitted OK or in error.  The test can be terminated anytime by the user at \r
+either PC.\r
+\r
+To setup the Diagnostic Network Test:\r
+\r
+    1.) Select a PC with a CS8900/20-based adapter and a known working network\r
+        connection to act as the Responder.  Run the CS8900/20 Setup Utility \r
+        and select 'Diagnostics -> Network Test -> Responder' from the main \r
+        menu.  Hit ENTER to start the Responder.\r
+\r
+    2.) Return to the PC with the CS8900/20-based adapter you want to test and\r
+        start the CS8900/20 Setup Utility. \r
+\r
+    3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'.\r
+        Hit ENTER to start the test.\r
\r
+You may stop the test on the Initiator at any time while allowing the Responder\r
+to continue running.  In this manner, you can move to additional PCs and test \r
+them by starting the Initiator on another PC without having to stop/start the \r
+Responder.\r
\r
+\r
+\r
+5.3 USING THE ADAPTER'S LEDs\r
+\r
+The 2 and 3-media adapters have two LEDs visible on the back end of the board \r
+located near the 10Base-T connector.  \r
+\r
+Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T \r
+connection.  (Only applies to 10Base-T.  The green LED has no significance for\r
+a 10Base-2 or AUI connection.)\r
+\r
+TX/RX LED: The yellow LED lights briefly each time the adapter transmits or \r
+receives data. (The yellow LED will appear to "flicker" on a typical network.)\r
+\r
+\r
+5.4 RESOLVING I/O CONFLICTS\r
+\r
+An IO conflict occurs when two or more adapter use the same ISA resource (IO \r
+address, memory address or IRQ).  You can usually detect an IO conflict in one \r
+of four ways after installing and or configuring the CS8900/20-based adapter:\r
+\r
+    1.) The system does not boot properly (or at all).\r
+\r
+    2.) The driver can not communicate with the adapter, reporting an "Adapter\r
+        not found" error message.\r
+\r
+    3.) You cannot connect to the network or the driver will not load.\r
+\r
+    4.) If you have configured the adapter to run in memory mode but the driver\r
+        reports it is using IO mode when loading, this is an indication of a\r
+        memory address conflict.\r
+\r
+If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a \r
+diagnostic self-test.  Normally, the ISA resource in conflict will fail the \r
+self-test.  If so, reconfigure the adapter selecting another choice for the \r
+resource in conflict.  Run the diagnostics again to check for further IO \r
+conflicts.\r
+\r
+In some cases, such as when the PC will not boot, it may be necessary to remove\r
+the adapter and reconfigure it by installing it in another PC to run the \r
+CS8900/20 Setup Utility.  Once reinstalled in the target system, run the \r
+diagnostics self-test to ensure the new configuration is free of conflicts \r
+before loading the driver again.\r
+\r
+When manually configuring the adapter, keep in mind the typical ISA system \r
+resource usage as indicated in the tables below.\r
+\r
+I/O Address            Device                        IRQ      Device\r
+-----------            --------                      ---      --------\r
+ 200-20F               Game I/O adapter               3       COM2, Bus Mouse\r
+ 230-23F               Bus Mouse                      4       COM1\r
+ 270-27F               LPT3: third parallel port      5       LPT2\r
+ 2F0-2FF               COM2: second serial port       6       Floppy Disk controller\r
+ 320-32F               Fixed disk controller          7       LPT1\r
+                                              8       Real-time Clock\r
+                                                 9       EGA/VGA display adapter    \r
+                                                12       Mouse (PS/2)                              \r
+Memory Address  Device                          13       Math Coprocessor\r
+--------------  ---------------------           14       Hard Disk controller\r
+A000-BFFF      EGA Graphics Adpater\r
+A000-C7FF      VGA Graphics Adpater\r
+B000-BFFF      Mono Graphics Adapter\r
+B800-BFFF      Color Graphics Adapter\r
+E000-FFFF      AT BIOS\r
+\r
+\r
+\r
+\r
+6.0 TECHNICAL SUPPORT\r
+===============================================================================\r
+\r
+6.1 CONTACTING CIRRUS LOGIC'S TECHNICAL SUPPORT\r
+\r
+Cirrus Logic's CS89XX Technical Application Support can be reached at:\r
+\r
+Telephone  :(800) 888-5016 (from inside U.S. and Canada)\r
+           :(512) 442-7555 (from outside the U.S. and Canada)\r
+Fax        :(512) 912-3871\r
+Email      :ethernet@crystal.cirrus.com\r
+WWW        :http://www.cirrus.com\r
+\r
+\r
+6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT\r
+\r
+Before contacting Cirrus Logic for technical support, be prepared to provide as \r
+Much of the following information as possible. \r
+\r
+1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.)\r
+\r
+2.) Adapter configuration\r
+\r
+    * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel\r
+    * Plug and Play enabled/disabled (CS8920-based adapters only)\r
+    * Configured for media auto-detect or specific media type (which type).    \r
+\r
+3.) PC System's Configuration\r
+\r
+    * Plug and Play system (yes/no)\r
+    * BIOS (make and version)\r
+    * System make and model\r
+    * CPU (type and speed)\r
+    * System RAM\r
+    * SCSI Adapter\r
+\r
+4.) Software\r
+\r
+    * CS89XX driver and version\r
+    * Your network operating system and version\r
+    * Your system's OS version \r
+    * Version of all protocol support files\r
+\r
+5.) Any Error Message displayed.\r
+\r
+\r
+\r
+6.3 OBTAINING THE LATEST DRIVER VERSION\r
+\r
+You can obtain the latest CS89XX drivers and support software from Cirrus Logic's \r
+Web site.  You can also contact Cirrus Logic's Technical Support (email:\r
+ethernet@crystal.cirrus.com) and request that you be registered for automatic \r
+software-update notification.\r
+\r
+Cirrus Logic maintains a web page at http://www.cirrus.com with the\r
+the latest drivers and technical publications.\r
+\r
+\r
+6.4 Current maintainer\r
+\r
+In February 2000 the maintenance of this driver was assumed by Andrew\r
+Morton <andrewm@uow.edu.au>\r
+\r
+\r
index 21436a4cb2e4eff8c6cd589fd75ee9c00f76324c..155997f18c50ec3611b90685b6f30af147ae89a0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 49
+SUBLEVEL = 50
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
index 4163626f4208aac119458a66e4b8380263e6fda5..120c861e7997579c579aac2f58951639f54b9454 100644 (file)
@@ -199,13 +199,13 @@ static void show(char * str)
                printk(" %d",local_bh_count(i));
 
        printk(" ]\nStack dumps:");
-       for(i=0;i< smp_num_cpus;i++) {
+       for(i = 0; i < smp_num_cpus; i++) {
                unsigned long esp;
-               if(i==cpu)
+               if (i == cpu)
                        continue;
                printk("\nCPU %d:",i);
                esp = init_tss[i].esp0;
-               if(esp==NULL) {
+               if (!esp) {
                        /* tss->esp0 is set to NULL in cpu_init(),
                         * it's initialized when the cpu returns to user
                         * space. -- manfreds
index b9e535a7197935045d4765bb4dbfc33c30bea64b..c801285eb18020125fd3f44b065713724a928215 100644 (file)
@@ -320,7 +320,7 @@ static void __init pagetable_init(void)
                if (vaddr >= end)
                        break;
 #if CONFIG_X86_PAE
-               pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
+               pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
                set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
 #else
                pmd = (pmd_t *)pgd;
index 4ba96bde9851542686d7377ed2fb1d41d9b2e44c..c849bac82993815eb510e39c197fe0a93ffe8abe 100644 (file)
@@ -92,7 +92,14 @@ CONFIG_BLK_DEV_IDESCSI=y
 #
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -194,6 +201,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # SCSI low-level drivers
 #
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
@@ -249,7 +257,6 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
 CONFIG_SCSI_MAC53C94=y
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -266,6 +273,7 @@ CONFIG_NETDEVICES=y
 #
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
@@ -389,7 +397,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
-CONFIG_FB_ATY128=y
+# CONFIG_FB_ATY128 is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -448,6 +456,7 @@ CONFIG_PSMOUSE=y
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -496,6 +505,8 @@ CONFIG_USB_OHCI=y
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_DABUSB is not set
 # CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
 
 #
 # USB HID
@@ -503,7 +514,7 @@ CONFIG_USB_OHCI=y
 # CONFIG_USB_HID is not set
 CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
-# CONFIG_USB_GRAPHIRE is not set
+# CONFIG_USB_WACOM is not set
 # CONFIG_USB_WMFORCE is not set
 CONFIG_INPUT_KEYBDEV=y
 CONFIG_INPUT_MOUSEDEV=y
index 4ba96bde9851542686d7377ed2fb1d41d9b2e44c..c849bac82993815eb510e39c197fe0a93ffe8abe 100644 (file)
@@ -92,7 +92,14 @@ CONFIG_BLK_DEV_IDESCSI=y
 #
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -194,6 +201,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # SCSI low-level drivers
 #
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
@@ -249,7 +257,6 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
 CONFIG_SCSI_MAC53C94=y
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -266,6 +273,7 @@ CONFIG_NETDEVICES=y
 #
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
@@ -389,7 +397,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
-CONFIG_FB_ATY128=y
+# CONFIG_FB_ATY128 is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -448,6 +456,7 @@ CONFIG_PSMOUSE=y
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -496,6 +505,8 @@ CONFIG_USB_OHCI=y
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_DABUSB is not set
 # CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
 
 #
 # USB HID
@@ -503,7 +514,7 @@ CONFIG_USB_OHCI=y
 # CONFIG_USB_HID is not set
 CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
-# CONFIG_USB_GRAPHIRE is not set
+# CONFIG_USB_WACOM is not set
 # CONFIG_USB_WMFORCE is not set
 CONFIG_INPUT_KEYBDEV=y
 CONFIG_INPUT_MOUSEDEV=y
index 0f71676225f3fde2aa8445000c9085f73b19ccc0..73db2269e9d732b93ab462f5e288ebd7aeefd3fb 100644 (file)
@@ -98,7 +98,7 @@ ifeq ($(CONFIG_ALL_PPC),y)
   OX_OBJS += prep_setup.o
 endif
 ifeq ($(CONFIG_GEMINI),y)
-  O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o
+  O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o open_pic.o
 endif
 
 all: $(KHEAD) kernel.o
@@ -114,6 +114,8 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
                $(TOPDIR)/include/asm/ptrace.h
        $(CC) $(CFLAGS) -S mk_defs.c
        cp ppc_defs.head ppc_defs.h
+# for bk, this way we can write to the file even if it's not checked out
+       chmod u+w ppc_defs.h
        grep '^#define' mk_defs.s >> ppc_defs.h
        rm mk_defs.s
 
index 156eb187e32cae71c7b68afa96b32ef3a84adea7..d14c7380acc1c7dddaca1f388a44a408004ca76a 100644 (file)
@@ -154,6 +154,9 @@ feature_init(void)
 {
        struct device_node *np;
 
+       if (_machine != _MACH_Pmac)
+               return;
+
        np = find_devices("mac-io");
        while (np != NULL) {
                /* KeyLargo contains several (5 ?) FCR registers in mac-io,
index b6d44ecb300c69e7da4e00d14b140d372e017a77..dab413c15c5e888a20baad6e86c67eda42aaa283 100644 (file)
@@ -222,7 +222,7 @@ __after_prom_start:
        mtspr   IBAT0L,r8
        mtspr   IBAT0U,r11
 #if 0 /* Useful debug code, please leave in for now so I don't have to
-       * look at docs when I need to setup a BAT ;
+       * look at docs when I need to setup a BAT ...
        */
        bl      setup_screen_bat
 #endif
@@ -256,6 +256,8 @@ __after_prom_start:
  * prep needs the mmu to be turned on here, but pmac already has it on.
  * this shouldn't bother the pmac since it just gets turned on again
  * as we jump to our code at KERNELBASE. -- Cort
+ * Actually no, pmac doesn't have it on any more. BootX enters with MMU
+ * off, and in other cases, we now turn it off before changing BATs above.
  */
 turn_on_mmu:
        mfmsr   r0
@@ -1423,6 +1425,7 @@ start_here:
        li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
        mtspr   SRR0,r4
        mtspr   SRR1,r3
+       SYNC
        rfi
 /* Load up the kernel context */
 2:
@@ -1433,6 +1436,7 @@ start_here:
        tlbsync                 /* ... on all CPUs */
        sync
 #endif
+       
        bl      load_up_mmu
 
 /* Set up for using our exception vectors */
@@ -1448,6 +1452,7 @@ start_here:
        ori     r3,r3,start_kernel@l
        mtspr   SRR0,r3
        mtspr   SRR1,r4
+       SYNC
        rfi                     /* enable MMU and jump to start_kernel */
 
 /*
@@ -1530,11 +1535,11 @@ setup_screen_bat:
        li      r3,0
        mtspr   DBAT1U,r3
        mtspr   IBAT1U,r3
-       lis     r3, 0x9100
+       lis     r3, 0x8200
        ori     r4,r3,0x2a
        mtspr   DBAT1L,r4
        mtspr   IBAT1L,r4
-       ori     r3,r3,(BL_8M<<2)|0x2    /* set up BAT registers for 604 */
+       ori     r3,r3,(BL_16M<<2)|0x2   /* set up BAT registers for 604 */
        mtspr   DBAT1U,r3
        mtspr   IBAT1U,r3
        blr
index ffac1871a18d4048dfac77e6bf17ac11d8b2f80e..f8e11ecc033bfa89ead781b2e23f4f24eb26f233 100644 (file)
@@ -45,7 +45,9 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
+#include <linux/proc_fs.h>
 
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/hydra.h>
 #include <asm/system.h>
@@ -611,3 +613,160 @@ void __global_restore_flags(unsigned long flags)
 }
 #endif /* __SMP__ */
 
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff};
+
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+       if (count < HEX_DIGITS+1)
+               return -EINVAL;
+       return sprintf (page, "%08x\n", irq_affinity[(int)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+               unsigned long count, unsigned long *ret)
+{
+       unsigned char hexnum [HEX_DIGITS];
+       unsigned long value;
+       int i;
+
+       if (!count)
+               return -EINVAL;
+       if (count > HEX_DIGITS)
+               count = HEX_DIGITS;
+       if (copy_from_user(hexnum, buffer, count))
+               return -EFAULT;
+
+       /*
+        * Parse the first 8 characters as a hex string, any non-hex char
+        * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+        */
+       value = 0;
+
+       for (i = 0; i < count; i++) {
+               unsigned int c = hexnum[i];
+
+               switch (c) {
+                       case '0' ... '9': c -= '0'; break;
+                       case 'a' ... 'f': c -= 'a'-10; break;
+                       case 'A' ... 'F': c -= 'A'-10; break;
+               default:
+                       goto out;
+               }
+               value = (value << 4) | c;
+       }
+out:
+       *ret = value;
+       return 0;
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+                                       unsigned long count, void *data)
+{
+       int irq = (int) data, full_count = count, err;
+       unsigned long new_value;
+
+       if (!irq_desc[irq].handler->set_affinity)
+               return -EIO;
+
+       err = parse_hex_value(buffer, count, &new_value);
+
+#if CONFIG_SMP
+       /*
+        * Do not allow disabling IRQs completely - it's a too easy
+        * way to make the system unusable accidentally :-) At least
+        * one online CPU still has to be targeted.
+        */
+       if (!(new_value & cpu_online_map))
+               return -EINVAL;
+#endif
+
+       irq_affinity[irq] = new_value;
+       irq_desc[irq].handler->set_affinity(irq, new_value);
+
+       return full_count;
+}
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+       unsigned long *mask = (unsigned long *) data;
+       if (count < HEX_DIGITS+1)
+               return -EINVAL;
+       return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+                                       unsigned long count, void *data)
+{
+       unsigned long *mask = (unsigned long *) data, full_count = count, err;
+       unsigned long new_value;
+
+       err = parse_hex_value(buffer, count, &new_value);
+       if (err)
+               return err;
+
+       *mask = new_value;
+       return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+       struct proc_dir_entry *entry;
+       char name [MAX_NAMELEN];
+
+       if (!root_irq_dir || (irq_desc[irq].handler == NULL))
+               return;
+
+       memset(name, 0, MAX_NAMELEN);
+       sprintf(name, "%d", irq);
+
+       /* create /proc/irq/1234 */
+       irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+       /* create /proc/irq/1234/smp_affinity */
+       entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+
+       entry->nlink = 1;
+       entry->data = (void *)irq;
+       entry->read_proc = irq_affinity_read_proc;
+       entry->write_proc = irq_affinity_write_proc;
+
+       smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+       struct proc_dir_entry *entry;
+       int i;
+
+       /* create /proc/irq */
+       root_irq_dir = proc_mkdir("irq", 0);
+
+       /* create /proc/irq/prof_cpu_mask */
+       entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+
+       entry->nlink = 1;
+       entry->data = (void *)&prof_cpu_mask;
+       entry->read_proc = prof_cpu_mask_read_proc;
+       entry->write_proc = prof_cpu_mask_write_proc;
+
+       /*
+        * Create entries for all existing IRQs.
+        */
+       for (i = 0; i < NR_IRQS; i++) {
+               if (irq_desc[i].handler == NULL)
+                       continue;
+               register_irq_proc(i);
+       }
+}
index 8326bc369cfbc6bd49fa97023d1f30459ed6e3d0..773c99b5ccc84fddef4cb2e5a620b5ec173bacc7 100644 (file)
@@ -131,11 +131,6 @@ char __init *pcibios_setup(char *str)
        return str;
 }
 
-int pcibios_assign_resource(struct pci_dev *pdev, int resource)
-{
-       return 0;
-}
-
 /* the next two are stolen from the alpha port... */
 void __init
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
@@ -189,48 +184,3 @@ int pcibios_enable_device(struct pci_dev *dev)
        }
        return 0;
 }
-
-/*
- * Assign new address to PCI resource.  We hope our resource information
- * is complete.  We don't re-assign resources unless we are
- * forced to do so.
- *
- * Expects start=0, end=size-1, flags=resource type.
- */
-
-int pci_assign_resource(struct pci_dev *dev, int i)
-{
-       struct resource *r = &dev->resource[i];
-       struct resource *pr = pci_find_parent_resource(dev, r);
-       unsigned long size = r->end + 1;
-       u32 new, check;
-
-       if (!pr) {
-               printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
-               return -EINVAL;
-       }
-       if (r->flags & IORESOURCE_IO) {
-               if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) {
-                       printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
-                       return -EBUSY;
-               }
-       } else {
-               if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) {
-                       printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
-                       return -EBUSY;
-               }
-       }
-       if (i < 6) {
-               int reg = PCI_BASE_ADDRESS_0 + 4*i;
-               new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
-               pci_write_config_dword(dev, reg, new);
-               pci_read_config_dword(dev, reg, &check);
-               if (new != check)
-                       printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
-       } else if (i == PCI_ROM_RESOURCE) {
-               r->flags |= PCI_ROM_ADDRESS_ENABLE;
-               pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
-       }
-       printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
-       return 0;
-}
index b0276ca2c20dff79c2ba6c61f189558b43ea450b..f2794ae5a4eb98644eeefededdb99d20385e4bf8 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/prom.h>
+#include <asm/pci-bridge.h>
 #include "pmac_pic.h"
 
 /* pmac */struct pmac_irq_hw {
index 5fef07e89e8f0d50e0dc32a25ecb8a8d6352c714..c2c4cbbf496f4bc0e333e5c1ae9877eeb28cfd83 100644 (file)
@@ -283,8 +283,6 @@ pmac_setup_arch(void)
                        ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
                                ? "enabled" : "disabled");
 
-       feature_init();
-
 #ifdef CONFIG_KGDB
        zs_kgdb_hook(0);
 #endif
@@ -325,14 +323,15 @@ static void __init init_p2pbridge(void)
            || p2pbridge->parent == NULL
            || strcmp(p2pbridge->parent->name, "pci") != 0)
                return;
-
        if (pci_device_loc(p2pbridge, &bus, &devfn) < 0)
                return;
-
-       pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
+       if (ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) {
+               printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+               return;
+       }
        val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
-       pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val);
-       pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
+       ppc_md.pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val);
+       ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
 }
 
 static void __init ohare_init(void)
@@ -703,8 +702,8 @@ pmac_progress(char *s, unsigned short hex)
 {
        if (disp_bi == 0)
                return;
-       drawstring(s);
-       drawchar('\n');
+       prom_drawstring(s);
+       prom_drawchar('\n');
 }
 #endif CONFIG_BOOTX_TEXT
 
index da46f3c1ce6419340314cc32986f8534ce251a78..441310e687c7700e8387f3ff0d0aae14292eb0cf 100644 (file)
@@ -44,12 +44,6 @@ extern unsigned long htab_evicts;
 extern unsigned long pte_misses;
 extern unsigned long pte_errors;
 
-struct file_operations ppc_htab_operations = {
-       llseek:         ppc_htab_lseek,
-       read:           ppc_htab_read,
-       write:          ppc_htab_write,
-};
-
 /* these will go into processor.h when I'm done debugging -- Cort */
 #define MMCR0 952
 #define MMCR0_PMC1_CYCLES (0x1<<7)
@@ -63,6 +57,12 @@ struct file_operations ppc_htab_operations = {
 #define PMC1 953
 #define PMC2 954
 
+struct file_operations ppc_htab_operations = {
+        llseek:         ppc_htab_lseek,
+        read:           ppc_htab_read,
+        write:          ppc_htab_write,
+};
+
 char *pmc1_lookup(unsigned long mmcr0)
 {
        switch ( mmcr0 & (0x7f<<7) )
index 4ee638f62827113aa8d5d1364e11e6fbfc867dde..310e301e64a0d1b4d8d4e3658e757406bd3713ed 100644 (file)
@@ -114,9 +114,9 @@ static struct device_node *allnodes = 0;
 static void clearscreen(void);
 static void flushscreen(void);
 
-void drawchar(char c);
-void drawstring(const char *c);
-static void drawhex(unsigned long v);
+void prom_drawchar(char c);
+void prom_drawstring(const char *c);
+void prom_drawhex(unsigned long v);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
@@ -134,6 +134,8 @@ static long                         g_max_loc_Y = 0;
 
 static unsigned char vga_font[cmapsz];
 
+int bootx_text_mapped = 1;
+
 #endif /* CONFIG_BOOTX_TEXT */
 
 
@@ -257,7 +259,7 @@ prom_print(const char *msg)
        {
 #ifdef CONFIG_BOOTX_TEXT
                if (RELOC(disp_bi) != 0)
-                       drawstring(msg);
+                       prom_drawstring(msg);
 #endif
                return;
        }               
@@ -385,6 +387,7 @@ prom_init(int r3, int r4, prom_entry pp)
 #ifdef CONFIG_BOOTX_TEXT
                prom_print(RELOC("booting...\n"));
                flushscreen();
+               RELOC(bootx_text_mapped) = 0;
 #endif
                return phys;
        }
@@ -633,6 +636,7 @@ prom_init(int r3, int r4, prom_entry pp)
                prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
                prom_print(RELOC("booting...\n"));
        }
+       RELOC(bootx_text_mapped) = 0;
 #endif
 
        return phys;
@@ -648,28 +652,30 @@ prom_welcome(boot_infos_t* bi, unsigned long phys)
        
        prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
        prom_print(RELOC("\nstarted at       : 0x"));
-       drawhex(phys);
+       prom_drawhex(phys);
        prom_print(RELOC("\nlinked at        : 0x"));
-       drawhex(KERNELBASE);
+       prom_drawhex(KERNELBASE);
        prom_print(RELOC("\nframe buffer at  : 0x"));
-       drawhex((unsigned long)bi->dispDeviceBase);
+       prom_drawhex((unsigned long)bi->dispDeviceBase);
        prom_print(RELOC(" (phys), 0x"));
-       drawhex((unsigned long)bi->logicalDisplayBase);
+       prom_drawhex((unsigned long)bi->logicalDisplayBase);
        prom_print(RELOC(" (log)"));
+       prom_print(RELOC("\nklimit           : 0x"));
+       prom_drawhex(RELOC(klimit));
        prom_print(RELOC("\nMSR              : 0x"));
        __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
-       drawhex(flags);
+       prom_drawhex(flags);
        __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
        pvr >>= 16;
        if (pvr > 1) {
            prom_print(RELOC("\nHID0             : 0x"));
            __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
-           drawhex(flags);
+           prom_drawhex(flags);
        }
        if (pvr == 8 || pvr == 12) {
            prom_print(RELOC("\nICTC             : 0x"));
            __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
-           drawhex(flags);
+           prom_drawhex(flags);
        }
        prom_print(RELOC("\n\n"));
 }
@@ -807,13 +813,18 @@ setup_disp_fake_bi(ihandle dp)
        
        prom_print(RELOC("Initializing fake screen\n"));
 
-       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width));
-       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height));
-       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"),
+                 &width, sizeof(width));
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"),
+                 &height, sizeof(height));
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"),
+                 &depth, sizeof(depth));
        pitch = width * ((depth + 7) / 8);
-       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"),
+                 &pitch, sizeof(pitch));
        address = 0;
-       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"),
+                 &address, sizeof(address));
        if (address == 0) {
                prom_print(RELOC("Failed to get address\n"));
                return;
@@ -837,7 +848,6 @@ setup_disp_fake_bi(ihandle dp)
        bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
        bi->dispDeviceRect[2] = width;
        bi->dispDeviceRect[3] = height;
-       RELOC(disp_bi) = 0;
 }
 #endif
 
@@ -1844,6 +1854,7 @@ map_bootx_text(void)
        disp_bi->logicalDisplayBase =
                ioremap((unsigned long) disp_bi->dispDeviceBase,
                        disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
+       bootx_text_mapped = 1;
 }
 
 /* Calc the base address of a given point (x,y) */
@@ -1940,11 +1951,14 @@ scrollscreen(void)
 
 __pmac
 void
-drawchar(char c)
+prom_drawchar(char c)
 {
        unsigned long offset = reloc_offset();
        int cline = 0, x;
 
+       if (!RELOC(bootx_text_mapped))
+               return;
+
        switch (c) {
        case '\b':
                if (RELOC(g_loc_X) > 0)
@@ -1988,27 +2002,33 @@ drawchar(char c)
 
 __pmac
 void
-drawstring(const char *c)
+prom_drawstring(const char *c)
 {
+       unsigned long offset    = reloc_offset();
+
+       if (!RELOC(bootx_text_mapped))
+               return;
        while (*c)
-               drawchar(*c++);
+               prom_drawchar(*c++);
 }
 
 __pmac
-static void
-drawhex(unsigned long v)
+void
+prom_drawhex(unsigned long v)
 {
        static char hex_table[] = "0123456789abcdef";
        unsigned long offset    = reloc_offset();
        
-       drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
-       drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
+       if (!RELOC(bootx_text_mapped))
+               return;
+       prom_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
+       prom_drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
 }
 
 
index 5a57ba8a24dd61ab0fb9ebd956c67ee43cc36e30..73a6c2bf7ae03ae2889aa411209ef9e56d972677 100644 (file)
@@ -29,6 +29,7 @@
 #endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
+#include <asm/feature.h>
 #ifdef CONFIG_OAK
 #include "oak_setup.h"
 #endif /* CONFIG_OAK */
@@ -417,7 +418,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                 unsigned long r6, unsigned long r7)
 {
        parse_bootinfo();
-
+       
        if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
        
 #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
@@ -687,6 +688,7 @@ void __init setup_arch(char **cmdline_p)
 
        ppc_md.setup_arch();
        if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
+       paging_init();
 }
 
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
@@ -733,12 +735,12 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
        id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
        id->eide_pio       = __le16_to_cpu(id->eide_pio);
        id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-       for (i=0; i<2 i++)
+       for (i=0; i<2; i++)
                id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i=0; i<4 i++)
+        for (i=0; i<4; i++)
                 id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
        id->queue_depth    = __le16_to_cpu(id->queue_depth);
-       for (i=0; i<4 i++)
+       for (i=0; i<4; i++)
                id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
        id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
        id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
index 2faccd0420ab543db666aecddb71f7f1e0a857ab..eaa5924a20478bf5233bfbe5f63f35ab2726409d 100644 (file)
@@ -961,8 +961,9 @@ void __init MMU_init(void)
                }
 #endif
 #if 0
-               setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE);
-               disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase;
+// This is bogus, BAT must be aligned.
+//             setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE);
+//             disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase;
 #endif         
                ioremap_base = 0xf0000000;
                break;
index 8e924699fa830a53d46fc5f81a5bd4c746da953e..95b19ba475fb2b44c8be027390e6413df3f80b8c 100644 (file)
 static volatile unsigned char *sccc, *sccd;
 unsigned long TXRDY, RXRDY;
 extern void xmon_printf(const char *fmt, ...);
-extern void drawchar(char);
-extern void drawstring(const char *str);
+extern void prom_drawchar(char);
+extern void prom_drawstring(const char *str);
 static int xmon_expect(const char *str, unsigned int timeout);
 
 static int console = 0;
-static int use_screen = 0;
+static int use_screen = 1; /* default */
 static int via_modem = 0;
 static int xmon_use_sccb = 0;
 static struct device_node *macio_node;
@@ -48,6 +48,8 @@ xmon_map_scc(void)
 {
        volatile unsigned char *base;
 
+       use_screen = 0;
+       
        if ( _machine == _MACH_Pmac )
        {
                struct device_node *np;
@@ -58,7 +60,7 @@ xmon_map_scc(void)
                /* needs to be hacked if xmon_printk is to be used
                   from within find_via_pmu() */
                if (!via_modem && disp_bi && find_via_pmu()) {
-                       drawstring("xmon uses screen and keyboard\n");
+                       prom_drawstring("xmon uses screen and keyboard\n");
                        use_screen = 1;
                        return;
                }
@@ -122,7 +124,7 @@ xmon_write(void *handle, void *ptr, int nb)
        if (use_screen) {
                /* write it on the screen */
                for (i = 0; i < nb; ++i)
-                       drawchar(*p++);
+                       prom_drawchar(*p++);
                return nb;
        }
 #endif
@@ -142,6 +144,7 @@ xmon_write(void *handle, void *ptr, int nb)
                        ct = 1;
                        --i;
                } else {
+                       prom_drawchar(c);
                        if (console)
                                printk("%c", c);
                        ct = 0;
@@ -187,15 +190,15 @@ xmon_get_pmu_key(void)
                do {
                        if (--t < 0) {
                                on = 1 - on;
-                               drawchar(on? 0xdb: 0x20);
-                               drawchar('\b');
+                               prom_drawchar(on? 0xdb: 0x20);
+                               prom_drawchar('\b');
                                t = 200000;
                        }
                        pmu_poll();
                } while (xmon_pmu_keycode == -1);
                k = xmon_pmu_keycode;
                if (on)
-                       drawstring(" \b");
+                       prom_drawstring(" \b");
 
                /* test for shift keys */
                if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
@@ -284,6 +287,8 @@ xmon_init_scc()
        {
                int i, x;
 
+               if (macio_node != 0)
+                       feature_set(macio_node, FEATURE_Serial_enable);
                if (via_modem && macio_node != 0) {
                        unsigned int t0;
 
@@ -399,15 +404,12 @@ int xmon_expect(const char *str, unsigned int timeout)
                for (;;) {
                        c = xmon_read_poll();
                        if (c == -1) {
-                               if (readtb() - t0 > timeout) {
-                                       printk("timeout\n");
+                               if (readtb() - t0 > timeout)
                                        return 0;
-                               }
                                continue;
                        }
                        if (c == '\n')
                                break;
-                       printk("%c", c);
                        if (c != '\r' && lineptr < &line[sizeof(line) - 1])
                                *lineptr++ = c;
                }
index d18d74dfda9c54da6f55c7bfc66b878f148c28fb..620df9aea28acdc9d03a6814440074c476bfe4d3 100644 (file)
@@ -119,7 +119,8 @@ void
 xmon(struct pt_regs *excp)
 {
        struct pt_regs regs;
-       int msr, cmd;
+       int msr, cmd, i;
+       unsigned *sp;
 
        if (excp == NULL) {
                asm volatile ("stw      0,0(%0)\n\
@@ -135,6 +136,29 @@ xmon(struct pt_regs *excp)
                excp = &regs;
        }
 
+       prom_drawstring("xmon pc="); prom_drawhex(excp->nip);
+       prom_drawstring(" lr="); prom_drawhex(excp->link);
+       prom_drawstring(" msr="); prom_drawhex(excp->msr);
+       prom_drawstring(" trap="); prom_drawhex(excp->trap);
+       prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]);
+       sp = &excp->gpr[0];
+       for (i = 0; i < 32; ++i) {
+               if ((i & 7) == 0)
+                       prom_drawstring("\n");
+               prom_drawstring(" ");
+               prom_drawhex(sp[i]);
+       }
+       sp = (unsigned *) excp->gpr[1];
+       for (i = 0; i < 64; ++i) {
+               if ((i & 7) == 0) {
+                       prom_drawstring("\n");
+                       prom_drawhex(sp);
+                       prom_drawstring(" ");
+               }
+               prom_drawstring(" ");
+               prom_drawhex(sp[i]);
+       }
+       prom_drawstring("\n");
        msr = get_msr();
        set_msr(msr & ~0x8000); /* disable interrupts */
        remove_bpts();
@@ -521,7 +545,7 @@ void
 excprint(struct pt_regs *fp)
 {
        printf("vector: %x at pc = %x %s",
-              fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/"");
+              fp->trap, fp->nip, pretty_lookup_name(fp->nip));
        printf(", msr = %x, sp = %x [%x]\n",
               fp->msr, fp->gpr[1], fp);
        if (fp->trap == 0x300 || fp->trap == 0x600)
@@ -1390,6 +1414,10 @@ static char *lookup_name(unsigned long addr)
        if ( !sysmap || !sysmap_size )
                return NULL;
        
+       /* adjust if addr is relative to kernelbase */
+       if ( addr < PAGE_OFFSET )
+               addr += PAGE_OFFSET;
+
        cmp = simple_strtoul(c, &c, 8);
        strcpy( last, strsep( &c, "\n"));
        while ( c < (sysmap+sysmap_size) )
index ed2e8bd812f76a3a26ffe191eb0e1676caa708b1..0d1b968fa3a468183a843fb07702a9e0c2ef5969 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $
+/*  $Id: setup.c,v 1.52 2000/03/03 23:48:41 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -164,9 +164,17 @@ int prom_callback(long *args)
                }
 
                if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+                       /* Spitfire Errata #32 workaround */
+                       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                            "flush     %%g6"
+                                            : /* No outputs */
+                                            : "r" (0),
+                                            "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
                        /*
                         * Locked down tlb entry 63.
                         */
+
                        tte = spitfire_get_dtlb_data(63);
                        res = PROM_TRUE;
                        goto done;
index 1aa48643ce480ab13ebf31bfc8f3c6b5a17a2a2a..1cdbf09da44e1d7d10f9b227163e4c26c08f9dcb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.19 1999/11/19 05:52:45 davem Exp $
+/* $Id: blockops.S,v 1.20 2000/03/03 23:48:38 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -46,13 +46,37 @@ copy_page: /* %o0=dest, %o1=src */
        sethi           %hi(TLBTEMP_ENT1), %o3
        rdpr            %pstate, %g3
        wrpr            %g3, PSTATE_IE, %pstate
+
+       /* Spitfire Errata #32 workaround */
+       mov             0x8, %o4
+       stxa            %g0, [%o4] ASI_DMMU
+       flush           %g6
+
        ldxa            [%o3] ASI_DTLB_TAG_READ, %o4
+
+       /* Spitfire Errata #32 workaround */
+       mov             0x8, %o5
+       stxa            %g0, [%o5] ASI_DMMU
+       flush           %g6
+
        ldxa            [%o3] ASI_DTLB_DATA_ACCESS, %o5
        stxa            %o0, [%o2] ASI_DMMU
        stxa            %g1, [%o3] ASI_DTLB_DATA_ACCESS
        membar          #Sync
        add             %o3, (TLBTEMP_ENTSZ), %o3
+
+       /* Spitfire Errata #32 workaround */
+       mov             0x8, %g5
+       stxa            %g0, [%g5] ASI_DMMU
+       flush           %g6
+
        ldxa            [%o3] ASI_DTLB_TAG_READ, %g5
+
+       /* Spitfire Errata #32 workaround */
+       mov             0x8, %g7
+       stxa            %g0, [%g7] ASI_DMMU
+       flush           %g6
+
        ldxa            [%o3] ASI_DTLB_DATA_ACCESS, %g7
        stxa            %o1, [%o2] ASI_DMMU
        stxa            %g2, [%o3] ASI_DTLB_DATA_ACCESS
@@ -120,7 +144,19 @@ clear_page:                /* %o0=dest */
        sethi           %hi(TLBTEMP_ENT2), %o3
        rdpr            %pstate, %g3
        wrpr            %g3, PSTATE_IE, %pstate
+
+       /* Spitfire Errata #32 workaround */
+       mov             0x8, %g5
+       stxa            %g0, [%g5] ASI_DMMU
+       flush           %g6
+
        ldxa            [%o3] ASI_DTLB_TAG_READ, %g5
+
+       /* Spitfire Errata #32 workaround */
+       mov             0x8, %g7
+       stxa            %g0, [%g7] ASI_DMMU
+       flush           %g6
+
        ldxa            [%o3] ASI_DTLB_DATA_ACCESS, %g7
        stxa            %o0, [%o2] ASI_DMMU
        stxa            %g1, [%o3] ASI_DTLB_DATA_ACCESS
index 58dc224f9245ff90d9841da18a114d2675a04346..68147d4d4107ee74240602e459397a483cc2930f 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.146 2000/02/09 21:11:09 davem Exp $
+/*  $Id: init.c,v 1.147 2000/03/03 23:48:44 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -230,6 +230,14 @@ static void inherit_prom_mappings(void)
 
        /* Now fixup OBP's idea about where we really are mapped. */
        prom_printf("Remapping the kernel... ");
+
+       /* Spitfire Errata #32 workaround */
+       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                            "flush     %%g6"
+                            : /* No outputs */
+                            : "r" (0),
+                            "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
        phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
        phys_page += ((unsigned long)&prom_boot_page -
                      (unsigned long)&empty_zero_page);
@@ -252,11 +260,27 @@ static void inherit_prom_mappings(void)
                : "memory");
 
        tte_vaddr = (unsigned long) &empty_zero_page;
+
+       /* Spitfire Errata #32 workaround */
+       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                            "flush     %%g6"
+                            : /* No outputs */
+                            : "r" (0),
+                            "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
        kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
 
        remap_func = (void *)  ((unsigned long) &prom_remap -
                                (unsigned long) &prom_boot_page);
 
+
+       /* Spitfire Errata #32 workaround */
+       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                            "flush     %%g6"
+                            : /* No outputs */
+                            : "r" (0),
+                            "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
        remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
                   (unsigned long) &empty_zero_page,
                   prom_get_mmu_ihandle());
@@ -319,8 +343,16 @@ static void __flush_nucleus_vptes(void)
 
        /* Only DTLB must be checked for VPTE entries. */
        for(i = 0; i < 63; i++) {
-               unsigned long tag = spitfire_get_dtlb_tag(i);
+               unsigned long tag;
 
+               /* Spitfire Errata #32 workaround */
+               __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                    "flush     %%g6"
+                                    : /* No outputs */
+                                    : "r" (0),
+                                    "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+               tag = spitfire_get_dtlb_tag(i);
                if(((tag & ~(PAGE_MASK)) == 0) &&
                   ((tag &  (PAGE_MASK)) >= prom_reserved_base)) {
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -436,10 +468,26 @@ void inherit_locked_prom_mappings(int save_p)
        for(i = 0; i < 63; i++) {
                unsigned long data;
 
+
+               /* Spitfire Errata #32 workaround */
+               __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                    "flush     %%g6"
+                                    : /* No outputs */
+                                    : "r" (0),
+                                    "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
                data = spitfire_get_dtlb_data(i);
                if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-                       unsigned long tag = spitfire_get_dtlb_tag(i);
+                       unsigned long tag;
+
+                       /* Spitfire Errata #32 workaround */
+                       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                            "flush     %%g6"
+                                            : /* No outputs */
+                                            : "r" (0),
+                                            "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
+                       tag = spitfire_get_dtlb_tag(i);
                        if(save_p) {
                                prom_dtlb[dtlb_seen].tlb_ent = i;
                                prom_dtlb[dtlb_seen].tlb_tag = tag;
@@ -459,10 +507,25 @@ void inherit_locked_prom_mappings(int save_p)
        for(i = 0; i < 63; i++) {
                unsigned long data;
 
+               /* Spitfire Errata #32 workaround */
+               __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                    "flush     %%g6"
+                                    : /* No outputs */
+                                    : "r" (0),
+                                    "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
                data = spitfire_get_itlb_data(i);
                if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-                       unsigned long tag = spitfire_get_itlb_tag(i);
+                       unsigned long tag;
+
+                       /* Spitfire Errata #32 workaround */
+                       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                            "flush     %%g6"
+                                            : /* No outputs */
+                                            : "r" (0),
+                                            "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
+                       tag = spitfire_get_itlb_tag(i);
                        if(save_p) {
                                prom_itlb[itlb_seen].tlb_ent = i;
                                prom_itlb[itlb_seen].tlb_tag = tag;
@@ -544,6 +607,13 @@ void __flush_tlb_all(void)
                             : "=r" (pstate)
                             : "i" (PSTATE_IE));
        for(i = 0; i < 64; i++) {
+               /* Spitfire Errata #32 workaround */
+               __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                    "flush     %%g6"
+                                    : /* No outputs */
+                                    : "r" (0),
+                                    "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
                if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : /* no outputs */
@@ -552,6 +622,14 @@ void __flush_tlb_all(void)
                        spitfire_put_dtlb_data(i, 0x0UL);
                        membar("#Sync");
                }
+
+               /* Spitfire Errata #32 workaround */
+               __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
+                                    "flush     %%g6"
+                                    : /* No outputs */
+                                    : "r" (0),
+                                    "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
                if(!(spitfire_get_itlb_data(i) & _PAGE_L)) {
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : /* no outputs */
index 0825b058585dae3247302fa302e983bddcd3c5a3..210db79e69d7652002b37b2433f6f230c0ba79e4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.37 2000/02/14 02:52:04 davem Exp $
+/* $Id: ultra.S,v 1.38 2000/03/03 23:48:44 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -35,7 +35,7 @@ __flush_tlb_mm: /* %o0=(ctx & 0x3ff), %o1=SECONDARY_CONTEXT */
 __flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
                    * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
                    */
-#define TLB_MAGIC      206 /* Students, do you know how I calculated this?  -DaveM */
+#define TLB_MAGIC      207 /* Students, do you know how I calculated this?  -DaveM */
 /*IC3*/        cmp             %o5, %o4
        be,pt           %xcc, __flush_tlb_page
         srlx           %o5, 13, %g5
@@ -58,6 +58,12 @@ __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
        wrpr            %g1, PSTATE_IE, %pstate
        mov             TLB_TAG_ACCESS, %g3
        mov             (62 << 3), %g2
+
+       /* Spitfire Errata #32 workaround. */
+       mov             0x8, %o4
+       stxa            %g0, [%o4] ASI_DMMU
+       flush           %g6
+
 1:     ldxa            [%g2] ASI_ITLB_TAG_READ, %o4
        and             %o4, 0x3ff, %o5
        cmp             %o5, %o0
@@ -83,12 +89,27 @@ __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
         wrpr           %g1, 0x0, %pstate
 4:     stxa            %g0, [%g3] ASI_IMMU
        stxa            %g0, [%g2] ASI_ITLB_DATA_ACCESS
+       flush           %g6
+
+       /* Spitfire Errata #32 workaround. */
+       mov             0x8, %o4
+       stxa            %g0, [%o4] ASI_DMMU
+       flush           %g6
+
        ba,pt           %xcc, 2b
-        flush          %g6
+        nop
+
 5:     stxa            %g0, [%g3] ASI_DMMU
 /*IC9*/        stxa            %g0, [%g2] ASI_DTLB_DATA_ACCESS
+       flush           %g6
+
+       /* Spitfire Errata #32 workaround. */
+       mov             0x8, %o4
+       stxa            %g0, [%o4] ASI_DMMU
+       flush           %g6
+
        ba,pt           %xcc, 3b
-        flush          %g6
+        nop
 
        .align          32
 __flush_tlb_mm_slow:
@@ -293,28 +314,51 @@ xcall_receive_signal:
         clr            %l6
 99:    retry
 
+       .data
+
+errata32_hwbug:
+       .xword  0
+
+       .text
+
        /* These two are not performance critical... */
        .globl          xcall_flush_tlb_all
 xcall_flush_tlb_all:
+
+       /* Spitfire Errata #32 workaround. */
+       sethi           %hi(errata32_hwbug), %g4
+       stx             %g0, [%g4 + %lo(errata32_hwbug)]
+
        clr             %g2
        clr             %g3
 1:     ldxa            [%g3] ASI_DTLB_DATA_ACCESS, %g4
        and             %g4, _PAGE_L, %g5
        brnz,pn         %g5, 2f
         mov            TLB_TAG_ACCESS, %g7
+
        stxa            %g0, [%g7] ASI_DMMU
        membar          #Sync
-
        stxa            %g0, [%g3] ASI_DTLB_DATA_ACCESS
        membar          #Sync
+
+       /* Spitfire Errata #32 workaround. */
+       sethi           %hi(errata32_hwbug), %g4
+       stx             %g0, [%g4 + %lo(errata32_hwbug)]
+
 2:     ldxa            [%g3] ASI_ITLB_DATA_ACCESS, %g4
        and             %g4, _PAGE_L, %g5
        brnz,pn         %g5, 2f
         mov            TLB_TAG_ACCESS, %g7
+
        stxa            %g0, [%g7] ASI_IMMU
        membar          #Sync
-
        stxa            %g0, [%g3] ASI_ITLB_DATA_ACCESS
+       membar          #Sync
+
+       /* Spitfire Errata #32 workaround. */
+       sethi           %hi(errata32_hwbug), %g4
+       stx             %g0, [%g4 + %lo(errata32_hwbug)]
+
 2:     add             %g2, 1, %g2
        cmp             %g2, 63
        ble,pt          %icc, 1b
index 64432480bc779aa32c01badf82d2cb4ce4b33416..0e29e3a2e15bcd603aa46ab81137527ee1e0eecf 100644 (file)
@@ -213,9 +213,9 @@ if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
 #   tristate '  RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
 #   tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5
 fi
-if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
-fi
+#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
+#   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
+#fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
    bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
index e7fd203b44dfe39bc73b3cfd768b22d5dedcb418..b3ffaa529ea6c852e81bfd23fcb1b4d36b7d7d2d 100644 (file)
 
 /* port addresses for auto-detection */
 #define ALI_NUM_PORTS 4
-static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
 
 /* register initialization data */
 typedef struct { byte reg, data; } RegInitializer;
 
-static RegInitializer __init initData[] = {
+static RegInitializer initData[] __initdata = {
        {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
        {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
        {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
index fedbb46acef04a81cbcf22ebfb564fec37639112..31e9786f3fa22d11e69f2e2fd4b213eba3e3b7ad 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/locks.h>
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
-#include <linux/raid/md.h>
 #include <linux/timer.h>
 #endif
 
index 0f032ac8c072ccfd62a97af46b57876d4b7cf19d..641783e9c5262884c737aafb15d5a06ef5405fb8 100644 (file)
@@ -1883,7 +1883,7 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
        char buffer[16];
        int stat;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer));
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
 
        /* These will be moved into the Uniform layer shortly... */
        switch (cmd) {
@@ -2075,7 +2075,7 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
        if ((stat = cdrom_select_speed (drive, speed)) < 0)
                return stat;
 
-       init_cdrom_command(&cgc, &buf, sizeof(buf));
+       init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
 
 #ifndef __ACER50__
        /* Now with that done, update the speed fields */
@@ -2303,7 +2303,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
                return nslots;
        }
 
-       init_cdrom_command(&cgc, &buf, sizeof(buf));
+       init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
        /* we have to cheat a little here. the packet will eventually
         * be queued with ide_cdrom_packet(), which extracts the
         * drive from cdi->handle. Since this device hasn't been
index 28eb789c2aebdd2e3cdfc5b47eeba32abdfdd180..e0803e6fa29a2f5b15b6ff2838f81023c2acb876 100644 (file)
@@ -420,7 +420,7 @@ pmac_ide_probe(void)
                hwif = &ide_hwifs[i];
                pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
                memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-               hwif->chipset = ide_generic;
+               hwif->chipset = ide_pmac;
                hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
index 90977c959742a61e33f764c249584bca42e121fd..debba3207c19da1c64dbd656b8edaf0718a7c897 100644 (file)
@@ -405,6 +405,7 @@ static int proc_ide_read_imodel
                case ide_cmd646:        name = "cmd646";        break;
                case ide_cy82c693:      name = "cy82c693";      break;
                case ide_4drives:       name = "4drives";       break;
+               case ide_pmac:          name = "mac-io";        break;
                default:                name = "(unknown)";     break;
        }
        len = sprintf(page, "%s\n", name);
index abecb27c409fc4c2b10ada48c3665a7d47527318..65e7bfdc48e2c0351d7980e5a28928c1976ce0d3 100644 (file)
@@ -77,6 +77,7 @@ static int nbd_open(struct inode *inode, struct file *file)
        nbd_dev[dev].refcnt++;
        if (!(nbdev->flags & NBD_INITIALISED)) {
                init_MUTEX(&nbdev->queue_lock);
+               INIT_LIST_HEAD(&nbdev->queue_head);
                nbdev->flags |= NBD_INITIALISED;
        }
        MOD_INC_USE_COUNT;
index c20ce1b9398247b0cd062d36dd031290d63aa23a..c66efc8c7f96a093f3eeee0995ea5036e1a91e4b 100644 (file)
   -- Fixed CDDA ripping with cdda2wav - accept much larger requests of
   number of frames and split the reads in blocks of 8.
 
-  3.05 Dec 13, 1999 - Jens Axboe <axboe@image.dk>
+  3.06 Dec 13, 1999 - Jens Axboe <axboe@image.dk>
   -- Added support for changing the region of DVD drives.
   -- Added sense data to generic command.
+
+  3.07 Feb 2, 2000 - Jens Axboe <axboe@suse.de>
+  -- Do same "read header length" trick in cdrom_get_disc_info() as
+  we do in cdrom_get_track_info() -- some drive don't obbey specs and
+  fail if they can't supply the full Mt Fuji size table.
+  -- Deleted stuff related to setting up write modes. It has a different
+  home now.
+  -- Clear header length in mode_select unconditionally.
+  -- Removed the register_disk() that was added, not needed here.
   
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 3.06"
-#define VERSION "Id: cdrom.c 3.06 1999/12/13"
+#define REVISION "Revision: 3.07"
+#define VERSION "Id: cdrom.c 3.07 2000/02/02"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -415,7 +424,6 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
        return 0;
 }
 
-static
 struct cdrom_device_info *cdrom_find_device(kdev_t dev)
 {
        struct cdrom_device_info *cdi;
@@ -682,7 +690,7 @@ static int cdrom_read_mech_status(struct cdrom_device_info *cdi,
        length = sizeof(struct cdrom_mechstat_header) +
                 cdi->capacity * sizeof(struct cdrom_slot);
 
-       init_cdrom_command(&cgc, buf, length);
+       init_cdrom_command(&cgc, buf, length, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_MECHANISM_STATUS;
        cgc.cmd[8] = (length >> 8) & 0xff;
        cgc.cmd[9] = length & 0xff;
@@ -737,7 +745,7 @@ static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot)
        if (cdi->sanyo_slot && slot < 0)
                return 0;
 
-       init_cdrom_command(&cgc, NULL, 0);
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
        cgc.cmd[0] = GPCMD_LOAD_UNLOAD;
        cgc.cmd[4] = 2 + (slot >= 0);
        cgc.cmd[8] = slot;
@@ -921,12 +929,15 @@ void sanitize_format(union cdrom_addr *addr,
        *curr = requested;
 }
 
-void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len)
+void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len,
+                       int type)
 {
        memset(cgc, 0, sizeof(struct cdrom_generic_command));
-       memset(buf, 0, len);
+       if (buf)
+               memset(buf, 0, len);
        cgc->buffer = (char *) buf;
        cgc->buflen = len;
+       cgc->data_direction = type;
 }
 
 /* DVD handling */
@@ -953,6 +964,7 @@ static void setup_report_key(struct cdrom_generic_command *cgc, unsigned agid, u
                }
        }
        cgc->cmd[9] = cgc->buflen;
+       cgc->data_direction = CGC_DATA_WRITE;
 }
 
 static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
@@ -974,6 +986,7 @@ static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, uns
                }
        }
        cgc->cmd[9] = cgc->buflen;
+       cgc->data_direction = CGC_DATA_READ;
 }
 
 static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
@@ -983,7 +996,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        struct cdrom_generic_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, 0);
+       init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ);
 
        switch (ai->type) {
        /* LU data send */
@@ -1124,7 +1137,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        struct cdrom_generic_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf));
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[6] = s->physical.layer_num;
        cgc.cmd[7] = s->type;
@@ -1165,7 +1178,7 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
        struct cdrom_generic_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf));
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[6] = s->copyright.layer_num;
        cgc.cmd[7] = s->type;
@@ -1193,7 +1206,7 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
        if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
                return -ENOMEM;
 
-       init_cdrom_command(&cgc, buf, size);
+       init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[7] = s->type;
        cgc.cmd[8] = size >> 8;
@@ -1214,7 +1227,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
        struct cdrom_generic_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf));
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[7] = s->type;
        cgc.cmd[9] = cgc.buflen = 0xff;
@@ -1244,7 +1257,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
        if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
                return -ENOMEM;
 
-       init_cdrom_command(&cgc, buf, size);
+       init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[7] = s->type;
        cgc.cmd[8] = size >> 8;
@@ -1305,6 +1318,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi,
        cgc->cmd[2] = page_code | (page_control << 6);
        cgc->cmd[7] = cgc->buflen >> 8;
        cgc->cmd[8] = cgc->buflen & 0xff;
+       cgc->data_direction = CGC_DATA_READ;
        return cdo->generic_packet(cdi, cgc);
 }
 
@@ -1314,11 +1328,12 @@ int cdrom_mode_select(struct cdrom_device_info *cdi,
        struct cdrom_device_ops *cdo = cdi->ops;
 
        memset(cgc->cmd, 0, sizeof(cgc->cmd));
-       
+       memset(cgc->buffer, 0, 2);
        cgc->cmd[0] = GPCMD_MODE_SELECT_10;
        cgc->cmd[1] = 0x10;             /* PF */
        cgc->cmd[7] = cgc->buflen >> 8;
        cgc->cmd[8] = cgc->buflen & 0xff;
+       cgc->data_direction = CGC_DATA_WRITE;
        return cdo->generic_packet(cdi, cgc);
 }
 
@@ -1330,7 +1345,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
        char buffer[32];
        int ret;
 
-       init_cdrom_command(&cgc, buffer, 16);
+       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
        cgc.cmd[1] = 2;     /* MSF addressing */
        cgc.cmd[2] = 0x40;  /* request subQ data */
@@ -1812,6 +1827,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);
                if (cgc.buffer == NULL)
                        return -ENOMEM;
+               cgc.data_direction = CGC_DATA_READ;
                ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
                if (!ret)
                        if (copy_to_user((char *)arg, cgc.buffer, blocksize))
@@ -1849,7 +1865,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                        kfree(cgc.buffer);
                        return -EFAULT;
                }
-
+               cgc.data_direction = CGC_DATA_READ;
                while (ra.nframes > 0) {
                        ret = cdrom_read_block(cdi, &cgc, lba, frames, 1,
                                               CD_FRAMESIZE_RAW);
@@ -1913,6 +1929,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                cgc.cmd[7] = entry.cdte_addr.msf.second;
                cgc.cmd[8] = entry.cdte_addr.msf.frame;
                cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+               cgc.data_direction = CGC_DATA_NONE;
                return cdo->generic_packet(cdi, &cgc);
                }
        case CDROMPLAYMSF: {
@@ -1926,6 +1943,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                cgc.cmd[6] = msf.cdmsf_min1;
                cgc.cmd[7] = msf.cdmsf_sec1;
                cgc.cmd[8] = msf.cdmsf_frame1;
+               cgc.data_direction = CGC_DATA_NONE;
                return cdo->generic_packet(cdi, &cgc);
                }
        case CDROMPLAYBLK: {
@@ -1939,6 +1957,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                cgc.cmd[5] = blk.from & 0xff;
                cgc.cmd[7] = (blk.len >> 8) & 0xff;
                cgc.cmd[8] = blk.len & 0xff;
+               cgc.data_direction = CGC_DATA_NONE;
                return cdo->generic_packet(cdi, &cgc);
                }
        case CDROMVOLCTRL:
@@ -1989,9 +2008,6 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                buffer[offset+13] = volctrl.channel2 & mask[offset+13];
                buffer[offset+15] = volctrl.channel3 & mask[offset+15];
 
-               /* clear the first three */
-               memset(buffer, 0, 3);
-
                /* set volume */
                cgc.buffer = buffer;
                return cdrom_mode_select(cdi, &cgc);
@@ -2003,6 +2019,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                cgc.cmd[0] = GPCMD_START_STOP_UNIT;
                cgc.cmd[1] = 1;
                cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
+               cgc.data_direction = CGC_DATA_NONE;
                return cdo->generic_packet(cdi, &cgc);
                }
 
@@ -2011,6 +2028,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 
                cgc.cmd[0] = GPCMD_PAUSE_RESUME;
                cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
+               cgc.data_direction = CGC_DATA_NONE;
                return cdo->generic_packet(cdi, &cgc);
                }
 
@@ -2090,7 +2108,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                if (copy && !ret)
                        __copy_to_user(userbuf, cgc.buffer, cgc.buflen);
                /* copy back sense data */
-               if (ret && sense != NULL)
+               if (sense != NULL)
                        if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense)))
                                ret = -EFAULT;
                kfree(cgc.buffer);
@@ -2125,7 +2143,7 @@ int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type,
        struct cdrom_generic_command cgc;
        int ret;
 
-       init_cdrom_command(&cgc, ti, 8);
+       init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
        cgc.cmd[1] = type & 3;
        cgc.cmd[4] = (track & 0xff00) >> 8;
@@ -2145,12 +2163,26 @@ int cdrom_get_disc_info(kdev_t dev, disc_information *di)
        struct cdrom_device_info *cdi = cdrom_find_device(dev);
        struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_generic_command cgc;
+       int ret;
 
        /* set up command and get the disc info */
-       init_cdrom_command(&cgc, di, sizeof(*di));
+       init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DISC_INFO;
-       cgc.cmd[8] = cgc.buflen;
+       cgc.cmd[8] = cgc.buflen = 2;
 
+       if ((ret = cdo->generic_packet(cdi, &cgc)))
+               return ret;
+
+       /* not all drives have the same disc_info length, so requeue
+        * packet with the length the drive tells us it can supply
+        */
+       cgc.buflen = be16_to_cpu(di->disc_information_length) +
+                    sizeof(di->disc_information_length);
+
+       if (cgc.buflen > sizeof(disc_information))
+               cgc.buflen = sizeof(disc_information);
+
+       cgc.cmd[8] = cgc.buflen;
        return cdo->generic_packet(cdi, &cgc);
 }
 
@@ -2265,6 +2297,7 @@ EXPORT_SYMBOL(cdrom_select_disc);
 EXPORT_SYMBOL(cdrom_mode_select);
 EXPORT_SYMBOL(cdrom_mode_sense);
 EXPORT_SYMBOL(init_cdrom_command);
+EXPORT_SYMBOL(cdrom_find_device);
 
 #ifdef CONFIG_SYSCTL
 
index e8de397bfce0a3d7b849bb3c7def865ba5fb408c..31cd5546c258857c5a97bfc43662131f591e6f2f 100644 (file)
@@ -1545,13 +1545,14 @@ int __init init_module()
 } /* End init_module */
 
 #endif
-#ifdef MODULE
-/* -------------------- Begin cleanup_module  ---------------------- */
 
 #ifdef ENABLE_PCI
 static struct pci_driver epca_driver;
 #endif
 
+#ifdef MODULE
+/* -------------------- Begin cleanup_module  ---------------------- */
+
 void cleanup_module()
 { /* Begin cleanup_module */
 
index 0b1ab10e1f980e018327b302661ce8ba97b9770f..ad945239027b3c4cf3aa1ffa016bff40ea16db1d 100644 (file)
@@ -142,6 +142,8 @@ static int  stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
  */
 #define        STLI_EISAPROBE  0
 
+static devfs_handle_t devfs_handle = NULL;
+
 /*****************************************************************************/
 
 /*
@@ -830,8 +832,6 @@ int init_module()
 
 /*****************************************************************************/
 
-static devfs_handle_t devfs_handle = NULL;
-
 void cleanup_module()
 {
        stlibrd_t       *brdp;
index b63f35436409a7c6a70ad1631d5b8610e19cbce0..6d98f932302510f034d1372d120cb584a50a15c9 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/major.h>
 #include <linux/malloc.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
@@ -2236,13 +2237,9 @@ static void release_saa(void)
        }
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-#else
-int init_stradis_cards(struct video_init *unused)
+
+static int __init stradis_init (void)
 {
-#endif
        struct pci_dev *dev = NULL;
        int result = 0, i;
 
@@ -2269,11 +2266,14 @@ int init_stradis_cards(struct video_init *unused)
        return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+
+static void __exit stradis_exit (void)
 {
        release_saa();
        printk(KERN_INFO "stradis: module cleanup complete\n");
 }
 
-#endif
+
+module_init(stradis_init);
+module_exit(stradis_exit);
+
index cfcdbfcdeaa91130abb494cb5b9d82c1c7735dec..f0b1aaf4dd0b43c921eba385ee92ef07e43f5d38 100644 (file)
@@ -60,9 +60,6 @@ static struct video_init video_init_list[]={
        {"i2c-tuner", i2c_tuner_init},
        {"bttv", init_bttv_cards},
 #endif 
-#ifdef CONFIG_VIDEO_STRADIS
-       {"stradis", init_stradis_cards},
-#endif 
 #ifdef CONFIG_VIDEO_BWQCAM
        {"bw-qcam", init_bw_qcams},
 #endif 
index d61b883752a0a312aaa59700ae9065ea46e0b225..1785e174021287322735835495f77c24efdd884f 100644 (file)
@@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.3 $";
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
-int suppress_pollack = 0;
+static int suppress_pollack = 0;
 MODULE_PARM(suppress_pollack, "0-1i");
 
 /* ------------------------------------------------------------- */
index 7483370cf26960394c1a4450ae1620df1f7cc0bd..76f34569dafd565dafa779582683cf98cb7cfd23 100644 (file)
@@ -65,7 +65,7 @@ static char *revision = "$Revision: 1.4 $";
 
 /* ------------------------------------------------------------- */
 
-int suppress_pollack = 0;
+static int suppress_pollack = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
index 5e948c7e7e304b93c49607e4d79de282eb7cc898..b333ad08c6c0e3b173dd5016d9c6019a66d7c2e7 100644 (file)
@@ -1049,7 +1049,6 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
  
 static void elp_timeout(struct net_device *dev)
 {
-       unsigned long flags;
        elp_device *adapter = dev->priv;
        int stat;
 
index 80f56adf76037877f7d9c117468efe1b7740160c..d8a5e12af9e5db07fc4fe0f5c0206213260f1e01 100644 (file)
@@ -46,6 +46,7 @@ static int max_interrupt_work = 20;
 #define RX_RING_SIZE   16
 #define PKT_BUF_SZ             1536    /* Size of each temporary Rx buffer. */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/isapnp.h>
index 9e3f72b3367c1da73b40ced2b9a7a63a5a65caaa..7a14db1ce427aa91ea5745cf042d495495de948b 100644 (file)
    $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
  */
 
-#ifdef MODULE
 #include <linux/module.h>
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -902,7 +899,7 @@ static void elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
 #ifndef NO_NOPCOMMANDS
                if (stat & STAT_CNA) {
                        /* CU went 'not ready' */
-                       if (netif_running(dev->state)) {
+                       if (netif_running(dev)) {
                                printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status);
                        }
                }
index 64edb30c1afab4423e05aaa9b0aad20c57ebc104..b264def307a4cd3e808b80a97bc0a2bab2c11ee8 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 source drivers/net/arcnet/Config.in
+source drivers/net/appletalk/Config.in
 
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'Bonding driver support' CONFIG_BONDING
@@ -131,9 +132,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       fi
 
       tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
-      if [ "$CONFIG_OBSOLETE" = "y" ]; then
-         tristate '    CS89x0 support' CONFIG_CS89x0
-      fi
+      tristate '    CS89x0 support' CONFIG_CS89x0
       tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
       tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
       tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
@@ -209,27 +208,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    fi
 fi
 
-#
-# AppleTalk
-#
-
-if [ "$CONFIG_ATALK" != "n" ]; then
-   mainmenu_option next_comment
-   comment 'Appletalk devices'
-   dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
-   dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
-   if [ "$CONFIG_COPS" != "n" ]; then
-      bool '  Dayna firmware support' CONFIG_COPS_DAYNA
-      bool '  Tangent firmware support' CONFIG_COPS_TANGENT
-   fi
-   dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
-   if [ "$CONFIG_IPDDP" != "n" ]; then
-      bool '  IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
-      bool '  Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
-   fi
-   endmenu
-fi
-
 if [ ! "$CONFIG_PARPORT" = "n" ]; then
    dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 fi
index 6a7b1f06abb9cf7153063362ddaa71bac0a151b0..3231ad4b96f28b1450334be1dc72bdfb75c1ecd8 100644 (file)
@@ -18,7 +18,7 @@ SUB_DIRS     :=
 MOD_SUB_DIRS :=
 MOD_IN_SUB_DIRS :=
 ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \
-               arcnet skfp tulip
+               arcnet skfp tulip appletalk
 
 O_TARGET := net.o
 MOD_LIST_NAME := NET_MODULES
@@ -104,6 +104,15 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ATALK),y)
+SUB_DIRS += appletalk
+MOD_IN_SUB_DIRS += appletalk
+else
+  ifeq ($(CONFIG_ATALK),m)
+  MOD_IN_SUB_DIRS += appletalk
+  endif
+endif
+
 #
 # link order important here
 #
@@ -280,9 +289,6 @@ obj-$(CONFIG_A2065) += a2065.o
 obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_CS89x0) += cs89x0.o
-obj-$(CONFIG_LTPC) += ltpc.o
-obj-$(CONFIG_COPS) += cops.o
-obj-$(CONFIG_IPDDP) += ipddp.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
index 3587dfe16a671d3c7a3f248859051aeb84450166..9969bcbde342bc7ef099e9f91db77f341f6691ce 100644 (file)
  * They used the DEC vendor ID by mistake
  */
 #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
-#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a
+#define PCI_DEVICE_ID_FARALLON_PN9000SX        0x1a
 #endif
 #ifndef PCI_VENDOR_ID_SGI
-#define PCI_VENDOR_ID_SGI             0x10a9
+#define PCI_VENDOR_ID_SGI              0x10a9
 #endif
 #ifndef PCI_DEVICE_ID_SGI_ACENIC
-#define PCI_DEVICE_ID_SGI_ACENIC      0x0009
+#define PCI_DEVICE_ID_SGI_ACENIC       0x0009
 #endif
 
 #ifndef wmb
 #define __exit
 #endif
 
+#ifndef SMP_CACHE_BYTES
+#define SMP_CACHE_BYTES        L1_CACHE_BYTES
+#endif
+
+
 #if (LINUX_VERSION_CODE < 0x02030e)
 #define net_device device
 #endif
@@ -121,7 +126,7 @@ static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
        return virt_ptr;
 }
 #define pci_free_consistent(cookie, size, ptr, dma_ptr)        kfree(ptr)
-#define pci_map_single(cookie, address, size, dir)             virt_to_bus(address)
+#define pci_map_single(cookie, address, size, dir)     virt_to_bus(address)
 #define pci_unmap_single(cookie, address, size, dir)
 #endif
 
@@ -140,18 +145,22 @@ static inline void netif_start_queue(struct net_device *dev)
        dev->start = 1;
 }
 
-#define ace_mark_net_bh(foo)                           mark_bh(foo)
-#define ace_if_busy(dev)       dev->tbusy
-#define ace_if_running(dev)    dev->start
-#define ace_if_down(dev)       {do{dev->start = 0;}while (0);}
+#define ace_mark_net_bh(foo)           mark_bh(foo)
+#define netif_queue_stopped(dev)       dev->tbusy
+#define netif_running(dev)             dev->start
+#define ace_if_down(dev)               {do{dev->start = 0;}while (0);}
 #else
 #define NET_BH                 0
 #define ace_mark_net_bh(foo)   {do{} while(0);}
-#define ace_if_busy(dev)       netif_queue_stopped(dev)
-#define ace_if_running(dev)    netif_running(dev)
 #define ace_if_down(dev)       {do{} while(0);}
 #endif
 
+
+#define ACE_MAX_MOD_PARMS      8
+#define BOARD_IDX_STATIC       0
+#define BOARD_IDX_OVERFLOW     -1
+
+
 #include "acenic.h"
 
 /*
@@ -336,30 +345,41 @@ static inline void netif_start_queue(struct net_device *dev)
 #define ACE_STD_BUFSIZE                (ACE_STD_MTU + ETH_HLEN + 2+4+16)
 #define ACE_JUMBO_BUFSIZE      (ACE_JUMBO_MTU + ETH_HLEN + 2+4+16)
 
-#define DEF_TX_RATIO           24
 /*
  * There seems to be a magic difference in the effect between 995 and 996
  * but little difference between 900 and 995 ... no idea why.
+ *
+ * There is now a default set of tuning parameters which is set, depending
+ * on whether or not the user enables Jumbo frames. It's assumed that if
+ * Jumbo frames are enabled, the user wants optimal tuning for that case.
  */
-#define DEF_TX_COAL            996
+#define DEF_TX_COAL            400 /* 996 */
 #define DEF_TX_MAX_DESC                40
-#define DEF_RX_COAL            1000
+#define DEF_RX_COAL            120 /* 1000 */
 #define DEF_RX_MAX_DESC                25
+#define DEF_TX_RATIO           21 /* 24 */
+
+#define DEF_JUMBO_TX_COAL      20
+#define DEF_JUMBO_TX_MAX_DESC  60
+#define DEF_JUMBO_RX_COAL      30
+#define DEF_JUMBO_RX_MAX_DESC  6
+#define DEF_JUMBO_TX_RATIO     21
+
 #define TX_COAL_INTS_ONLY      0       /* seems not worth it */
 #define DEF_TRACE              0
-#define DEF_STAT               2 * TICKS_PER_SEC
+#define DEF_STAT               (2 * TICKS_PER_SEC)
 
-static int link[8] = {0, };
-static int trace[8] = {0, };
-static int tx_coal_tick[8] = {0, };
-static int rx_coal_tick[8] = {0, };
-static int max_tx_desc[8] = {0, };
-static int max_rx_desc[8] = {0, };
-static int tx_ratio[8] = {0, };
-static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1};
+static int link[ACE_MAX_MOD_PARMS] = {0, };
+static int trace[ACE_MAX_MOD_PARMS] = {0, };
+static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
+static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
+static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, };
+static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, };
+static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, };
+static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static const char __initdata *version = 
-  "acenic.c: v0.41 02/16/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
+  "acenic.c: v0.42 03/02/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev = NULL;
@@ -469,11 +489,6 @@ int __init acenic_probe (struct net_device *dev)
 
                pci_set_master(pdev);
 
-#ifdef __sparc__
-               /* NOTE: Cache line size is in 32-bit word units. */
-               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
                /*
                 * Remap the regs into kernel space - this is abuse of
                 * dev->base_addr since it was means for I/O port
@@ -484,7 +499,6 @@ int __init acenic_probe (struct net_device *dev)
 #else
                dev->base_addr = pdev->resource[0].start;
 #endif
-
                ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
                if (!ap->regs) {
                        printk(KERN_ERR "%s:  Unable to map I/O register, "
@@ -540,8 +554,7 @@ int __init acenic_probe (struct net_device *dev)
                if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
                        printk(KERN_ERR "%s: Driver compiled without Tigon I"
                               " support - NIC disabled\n", dev->name);
-                       iounmap(ap->regs);
-                       unregister_netdev(dev);
+                       ace_init_cleanup(dev);
                        continue;
                }
 #endif
@@ -550,13 +563,17 @@ int __init acenic_probe (struct net_device *dev)
                        continue;
 
 #ifdef MODULE
-               if (ace_init(dev, boards_found))
-                       continue;
+               if (boards_found >= ACE_MAX_MOD_PARMS)
+                       ap->board_idx = BOARD_IDX_OVERFLOW;
+               else
+                       ap->board_idx = boards_found;
 #else
-               if (ace_init(dev, -1))
-                       continue;
+               ap->board_idx = BOARD_IDX_STATIC;
 #endif
 
+               if (ace_init(dev))
+                       continue;
+
                boards_found++;
        }
 
@@ -566,20 +583,16 @@ int __init acenic_probe (struct net_device *dev)
         * or more boards. Otherwise, return failure (-ENODEV).
         */
 
-#ifdef MODULE
-       return boards_found;
-#else
        if (boards_found > 0)
                return 0;
        else
                return -ENODEV;
-#endif
 }
 
 
 #ifdef MODULE
 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
-MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver");
+MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
@@ -597,7 +610,7 @@ void __exit ace_module_cleanup(void)
 
        while (root_dev) {
                next = ((struct ace_private *)root_dev->priv)->next;
-               ap = (struct ace_private *)root_dev->priv;
+               ap = root_dev->priv;
 
                regs = ap->regs;
 
@@ -670,38 +683,26 @@ void __exit ace_module_cleanup(void)
                        }
                }
 
-               ace_free_descriptors(root_dev);
-
-               if (ap->trace_buf)
-                       kfree(ap->trace_buf);
-               if (ap->info)
-                       pci_free_consistent(ap->pdev, sizeof(struct ace_info),
-                                           ap->info, ap->info_dma);
-               if (ap->skb)
-                       kfree(ap->skb);
-               if (root_dev->irq)
-                       free_irq(root_dev->irq, root_dev);
-               unregister_netdev(root_dev);
-               iounmap(regs);
+               ace_init_cleanup(root_dev);
                kfree(root_dev);
-
                root_dev = next;
        }
 }
+#endif
 
 
 int __init ace_module_init(void)
 {
-       int cards;
+       int status;
 
        root_dev = NULL;
 
 #ifdef NEW_NETINIT
-       cards = acenic_probe();
+       status = acenic_probe();
 #else
-       cards = acenic_probe(NULL);
+       status = acenic_probe(NULL);
 #endif
-       return cards ? 0 : -ENODEV;
+       return status;
 }
 
 
@@ -717,7 +718,6 @@ void cleanup_module(void)
        ace_module_cleanup();
 }
 #endif
-#endif
 
 
 #if (LINUX_VERSION_CODE >= 0x02032a)
@@ -817,10 +817,36 @@ static int ace_allocate_descriptors(struct net_device *dev)
 
 fail:
        /* Clean up. */
+       ace_init_cleanup(dev);
+       return 1;
+}
+
+
+/*
+ * Generic cleanup handling data allocated during init. Used when the
+ * module is unloaded or if an error occurs during initialization
+ */
+static void ace_init_cleanup(struct net_device *dev)
+{
+       struct ace_private *ap;
+
+       ap = dev->priv;
+
        ace_free_descriptors(dev);
-       iounmap(ap->regs);
+
+       if (ap->info)
+               pci_free_consistent(ap->pdev, sizeof(struct ace_info),
+                                   ap->info, ap->info_dma);
+       if (ap->skb)
+               kfree(ap->skb);
+       if (ap->trace_buf)
+               kfree(ap->trace_buf);
+
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+
        unregister_netdev(dev);
-       return 1;
+       iounmap(ap->regs);
 }
 
 
@@ -840,19 +866,22 @@ static inline void ace_issue_cmd(struct ace_regs *regs, struct cmd *cmd)
 }
 
 
-static int __init ace_init(struct net_device *dev, int board_idx)
+static int __init ace_init(struct net_device *dev)
 {
        struct ace_private *ap;
        struct ace_regs *regs;
        struct ace_info *info = NULL;
        unsigned long tmp_ptr, myjif;
        u32 tig_ver, mac1, mac2, tmp, pci_state;
-       int ecode = 0;
+       int board_idx, ecode = 0;
        short i;
+       unsigned char cache;
 
        ap = dev->priv;
        regs = ap->regs;
 
+       board_idx = ap->board_idx;
+
        /*
         * aman@sgi.com - its useful to do a NIC reset here to
         * address the `Firmware not running' problem subsequent
@@ -968,6 +997,21 @@ static int __init ace_init(struct net_device *dev, int board_idx)
        dev->dev_addr[4] = (mac2 >> 8) & 0xff;
        dev->dev_addr[5] = mac2 & 0xff;
 
+       /*
+        * Looks like this is necessary to deal with on all architectures,
+        * even this %$#%$# N440BX Intel based thing doesn't get it right.
+        * Ie. having two NICs in the machine, one will have the cache
+        * line set at boot time, the other will not.
+        */
+       pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache);
+       if ((cache << 2) != SMP_CACHE_BYTES) {
+               printk(KERN_INFO "  PCI cache line size set incorrectly "
+                      "(%i bytes) by BIOS/FW, correcting to %i\n",
+                      (cache << 2), SMP_CACHE_BYTES);
+               pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE,
+                                     SMP_CACHE_BYTES >> 2);
+       }
+
        pci_state = readl(&regs->PciState);
        printk(KERN_INFO "  PCI bus width: %i bits, speed: %iMHz, "
               "latency: %i clks\n",
@@ -991,19 +1035,20 @@ static int __init ace_init(struct net_device *dev, int board_idx)
                /*
                 * Tuning parameters only supported for 8 cards
                 */
-               if (board_idx > 7 || dis_pci_mem_inval[board_idx]) {
+               if (board_idx == BOARD_IDX_OVERFLOW ||
+                   dis_pci_mem_inval[board_idx]) {
                        if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
                                ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
                                pci_write_config_word(ap->pdev, PCI_COMMAND,
                                                      ap->pci_command);
-                               printk(KERN_INFO "%s: disabling PCI memory "
-                                      "write and invalidate\n", dev->name);
+                               printk(KERN_INFO "  Disabling PCI memory "
+                                      "write and invalidate\n");
                        }
                } else if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
-                       printk(KERN_INFO "%s: PCI memory write & invalidate "
-                              "enabled by BIOS, enabling counter "
-                              "measures\n", dev->name);
-                       switch(L1_CACHE_BYTES) {
+                       printk(KERN_INFO "  PCI memory write & invalidate "
+                              "enabled by BIOS, enabling counter measures\n");
+                       
+                       switch(SMP_CACHE_BYTES) {
                        case 16:
                                tmp |= DMA_WRITE_MAX_16;
                                break;
@@ -1023,8 +1068,10 @@ static int __init ace_init(struct net_device *dev, int board_idx)
                        }
                }
        }
+
 #ifdef __sparc__
-       /* On this platform, we know what the best dma settings
+       /*
+        * On this platform, we know what the best dma settings
         * are.  We use 64-byte maximum bursts, because if we
         * burst larger than the cache line size (or even cross
         * a 64byte boundry in a single burst) the UltraSparc
@@ -1034,12 +1081,18 @@ static int __init ace_init(struct net_device *dev, int board_idx)
         * set will give the PCI controller proper hints about
         * prefetching.
         */
-       tmp = (tmp & ~(0xfc));
+       tmp = tmp & ~DMA_READ_WRITE_MASK;
        tmp |= DMA_READ_MAX_64;
        tmp |= DMA_WRITE_MAX_64;
 #endif
        writel(tmp, &regs->PciState);
 
+       if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) {
+               printk(KERN_INFO "  Enabling PCI Fast Back to Back\n");
+               ap->pci_command |= PCI_COMMAND_FAST_BACK;
+               pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command);
+       }
+               
        /*
         * Initialize the generic info block and the command+event rings
         * and the control blocks for the transmit and receive rings
@@ -1213,21 +1266,15 @@ static int __init ace_init(struct net_device *dev, int board_idx)
        writel(1, &regs->AssistState);
 
        writel(DEF_STAT, &regs->TuneStatTicks);
-
-       writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
-       writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
-       writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
-       writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
        writel(DEF_TRACE, &regs->TuneTrace);
-       writel(DEF_TX_RATIO, &regs->TxBufRat);
 
-       if (board_idx >= 8) {
-               printk(KERN_WARNING "%s: more then 8 NICs detected, "
-                      "ignoring module parameters!\n", dev->name);
-               board_idx = -1;
-       }
+       ace_set_rxtx_parms(dev, 0);
 
-       if (board_idx >= 0) {
+       if (board_idx == BOARD_IDX_OVERFLOW) {
+               printk(KERN_WARNING "%s: more then %i NICs detected, "
+                      "ignoring module parameters!\n",
+                      dev->name, ACE_MAX_MOD_PARMS);
+       } else if (board_idx >= 0) {
                if (tx_coal_tick[board_idx])
                        writel(tx_coal_tick[board_idx],
                               &regs->TuneTxCoalTicks);
@@ -1352,8 +1399,6 @@ static int __init ace_init(struct net_device *dev, int board_idx)
                        writel(readl(&regs->CpuBCtrl) | CPU_HALT,
                               &regs->CpuBCtrl);
                writel(0, &regs->Mb0Lo);
-               free_irq(dev->irq, dev);
-               dev->irq = 0;
 
                ecode = -EBUSY;
                goto init_error;
@@ -1376,27 +1421,63 @@ static int __init ace_init(struct net_device *dev, int board_idx)
                               "the RX mini ring\n", dev->name);
        }
        return 0;
+
  init_error:
-       iounmap(ap->regs);
-       unregister_netdev(dev);
-       if (ap->skb) {
-               kfree(ap->skb);
-               ap->skb = NULL;
-       }
-       if (ap->info)
-               pci_free_consistent(ap->pdev, sizeof(struct ace_info),
-                                   info, ap->info_dma);
+       ace_init_cleanup(dev);
        return ecode;
 }
 
 
+static void ace_set_rxtx_parms(struct net_device *dev, int jumbo)
+{
+       struct ace_private *ap;
+       struct ace_regs *regs;
+       int board_idx;
+
+       ap = dev->priv;
+       regs = ap->regs;
+
+       board_idx = ap->board_idx;
+
+       if (board_idx >= 0) {
+               if (!jumbo) {
+                       if (!tx_coal_tick[board_idx])
+                               writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
+                       if (!max_tx_desc[board_idx])
+                               writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
+                       if (!rx_coal_tick[board_idx])
+                               writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
+                       if (!max_rx_desc[board_idx])
+                               writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
+                       if (!tx_ratio[board_idx])
+                               writel(DEF_TX_RATIO, &regs->TxBufRat);
+               } else {
+                       if (!tx_coal_tick[board_idx])
+                               writel(DEF_JUMBO_TX_COAL,
+                                      &regs->TuneTxCoalTicks);
+                       if (!max_tx_desc[board_idx])
+                               writel(DEF_JUMBO_TX_MAX_DESC,
+                                      &regs->TuneMaxTxDesc);
+                       if (!rx_coal_tick[board_idx])
+                               writel(DEF_JUMBO_RX_COAL,
+                                      &regs->TuneRxCoalTicks);
+                       if (!max_rx_desc[board_idx])
+                               writel(DEF_JUMBO_RX_MAX_DESC,
+                                      &regs->TuneMaxRxDesc);
+                       if (!tx_ratio[board_idx])
+                               writel(DEF_JUMBO_TX_RATIO, &regs->TxBufRat);
+               }
+       }
+}
+
+
 /*
  * Monitor the card to detect hangs.
  */
 static void ace_timer(unsigned long data)
 {
        struct net_device *dev = (struct net_device *)data;
-       struct ace_private *ap = (struct ace_private *)dev->priv;
+       struct ace_private *ap = dev->priv;
        struct ace_regs *regs = ap->regs;
 
        /*
@@ -1459,7 +1540,7 @@ static void ace_dump_trace(struct ace_private *ap)
 {
 #if 0
        if (!ap->trace_buf)
-               if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)));
+               if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)))
                    return;
 #endif
 }
@@ -1664,7 +1745,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
 {
        struct ace_private *ap;
 
-       ap = (struct ace_private *)dev->priv;
+       ap = dev->priv;
 
        while (evtcsm != evtprd) {
                switch (ap->evt_ring[evtcsm].evt) {
@@ -1742,7 +1823,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
 
 static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 {
-       struct ace_private *ap = (struct ace_private *)dev->priv;
+       struct ace_private *ap = dev->priv;
        u32 idx;
        int mini_count = 0, std_count = 0;
 
@@ -1795,7 +1876,8 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 
                skb = rip->skb;
                rip->skb = NULL;
-               pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE);
+               pci_unmap_single(ap->pdev, rip->mapping, mapsize,
+                                PCI_DMA_FROMDEVICE);
                skb_put(skb, retdesc->size);
 #if 0
                /* unncessary */
@@ -1860,7 +1942,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
        u32 txcsm, rxretcsm, rxretprd;
        u32 evtcsm, evtprd;
 
-       ap = (struct ace_private *)dev->priv;
+       ap = dev->priv;
        regs = ap->regs;
 
        /*
@@ -1902,7 +1984,8 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 
                        ap->stats.tx_packets++;
                        ap->stats.tx_bytes += skb->len;
-                       pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(ap->pdev, mapping, skb->len,
+                                        PCI_DMA_TODEVICE);
                        dev_kfree_skb_irq(skb);
 
                        ap->skb->tx_skbuff[idx].skb = NULL;
@@ -1928,7 +2011,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
                 * Ie. skip the comparison of the tx producer vs. the
                 * consumer.
                 */
-               if (ace_if_busy(dev) && xchg(&ap->tx_full, 0)) {
+               if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) {
                        /*
                         * This does not need to be atomic (and expensive),
                         * I've seen cases where it would fail otherwise ;-(
@@ -1959,7 +2042,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
         * This has to go last in the interrupt handler and run with
         * the spin lock released ... what lock?
         */
-       if (ace_if_running(dev)) {
+       if (netif_running(dev)) {
                int cur_size;
                int run_bh = 0;
 
@@ -2108,7 +2191,7 @@ static int ace_close(struct net_device *dev)
        ace_if_down(dev);
        netif_stop_queue(dev);
 
-       ap = (struct ace_private *)dev->priv;
+       ap = dev->priv;
        regs = ap->regs;
 
        del_timer(&ap->timer);
@@ -2143,7 +2226,8 @@ static int ace_close(struct net_device *dev)
                        writel(0, &ap->tx_ring[i].addr.addrhi);
                        writel(0, &ap->tx_ring[i].addr.addrlo);
                        writel(0, &ap->tx_ring[i].flagsize);
-                       pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(ap->pdev, mapping, skb->len,
+                                        PCI_DMA_TODEVICE);
                        dev_kfree_skb(skb);
                        ap->skb->tx_skbuff[i].skb = NULL;
                }
@@ -2165,7 +2249,7 @@ static int ace_close(struct net_device *dev)
 
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct ace_private *ap = (struct ace_private *)dev->priv;
+       struct ace_private *ap = dev->priv;
        struct ace_regs *regs = ap->regs;
        unsigned long addr;
        u32 idx, flagsize;
@@ -2193,7 +2277,8 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        ap->skb->tx_skbuff[idx].skb = skb;
        ap->skb->tx_skbuff[idx].mapping =
-               pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+               pci_map_single(ap->pdev, skb->data, skb->len,
+                              PCI_DMA_TODEVICE);
        addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
 #if (BITS_PER_LONG == 64)
        writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
@@ -2264,12 +2349,13 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu)
                        ap->jumbo = 1;
                        if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
                                ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
-                       ap->jumbo = 1;
+                       ace_set_rxtx_parms(dev, 1);
                }
        } else {
                netif_stop_queue(dev);
                while (test_and_set_bit(0, &ap->jumbo_refill_busy));
                synchronize_irq();
+               ace_set_rxtx_parms(dev, 0);
                if (ap->jumbo){
                        struct cmd cmd;
 
@@ -2287,7 +2373,7 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu)
 static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 #ifdef ETHTOOL
-       struct ace_private *ap = (struct ace_private *) dev->priv;
+       struct ace_private *ap = dev->priv;
        struct ace_regs *regs = ap->regs;
        struct ethtool_cmd ecmd;
        u32 link, speed;
@@ -2429,7 +2515,7 @@ static int ace_set_mac_addr(struct net_device *dev, void *p)
        u16 *da;
        struct cmd cmd;
 
-       if(ace_if_running(dev))
+       if(netif_running(dev))
                return -EBUSY;
 
        memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
@@ -2587,7 +2673,7 @@ int __init ace_load_firmware(struct net_device *dev)
        struct ace_private *ap;
        struct ace_regs *regs;
 
-       ap = (struct ace_private *)dev->priv;
+       ap = dev->priv;
        regs = ap->regs;
 
        if (!(readl(&regs->CpuCtrl) & CPU_HALTED)) {
index 7719338ab5772d307f3e551ec31bb2301e32a91f..958561a690b64a9c59eb3275b4ac88d9ab411a54 100644 (file)
@@ -233,6 +233,7 @@ typedef struct {
 #define DMA_WRITE_MAX_128      0xa0
 #define DMA_WRITE_MAX_256      0xc0
 #define DMA_WRITE_MAX_1K       0xe0
+#define DMA_READ_WRITE_MASK    0xfc
 #define MEM_READ_MULTIPLE      0x00020000
 #define PCI_66MHZ              0x00080000
 #define PCI_32BIT              0x00100000
@@ -635,6 +636,7 @@ struct ace_private
        unsigned char           *trace_buf;
        struct pci_dev          *pdev;
        struct net_device       *next;
+       int                     board_idx;
        u16                     pci_command;
        u8                      pci_latency;
        char                    name[48];
@@ -698,7 +700,7 @@ static inline void ace_set_txprd(struct ace_regs *regs,
 /*
  * Prototypes
  */
-static int ace_init(struct net_device *dev, int board_idx);
+static int ace_init(struct net_device *dev);
 static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
 static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
 static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
@@ -717,8 +719,10 @@ extern int ace_recycle(struct sk_buff *skb);
 #endif
 static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static int ace_set_mac_addr(struct net_device *dev, void *p);
+static void ace_set_rxtx_parms(struct net_device *dev, int jumbo);
 static int ace_allocate_descriptors(struct net_device *dev);
 static void ace_free_descriptors(struct net_device *dev);
+static void ace_init_cleanup(struct net_device *dev);
 static struct net_device_stats *ace_get_stats(struct net_device *dev);
 static int read_eeprom_byte(struct net_device *dev, unsigned long offset);
 
diff --git a/drivers/net/appletalk/Config.in b/drivers/net/appletalk/Config.in
new file mode 100644 (file)
index 0000000..951cf49
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Appletalk driver configuration
+#
+
+if [ "$CONFIG_ATALK" != "n" ]; then
+  mainmenu_option next_comment
+  comment 'Appletalk devices'
+  dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
+  dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
+  if [ "$CONFIG_COPS" != "n" ]; then
+     bool '  Dayna firmware support' CONFIG_COPS_DAYNA
+     bool '  Tangent firmware support' CONFIG_COPS_TANGENT
+  fi
+  dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
+  if [ "$CONFIG_IPDDP" != "n" ]; then
+     bool '  IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+     bool '  Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
+  fi
+  endmenu
+fi
diff --git a/drivers/net/appletalk/Makefile b/drivers/net/appletalk/Makefile
new file mode 100644 (file)
index 0000000..a59443c
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# Makefile for drivers/net/appletalk
+#
+# 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).
+#
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+obj-y   :=
+obj-n   :=
+obj-m   :=
+obj-    :=
+export-objs :=
+
+obj-$(CONFIG_LTPC) += ltpc.o
+obj-$(CONFIG_COPS) += cops.o
+obj-$(CONFIG_IPDDP) += ipddp.o
+
+L_TARGET := appletalk.a
+L_OBJS   := $(filter-out $(export-objs), $(obj-y))
+LX_OBJS  := $(filter     $(export-objs), $(obj-y))
+M_OBJS   := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS  := $(sort $(filter     $(export-objs), $(obj-m)))
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
new file mode 100644 (file)
index 0000000..466705f
--- /dev/null
@@ -0,0 +1,1066 @@
+/*      cops.c: LocalTalk driver for Linux.
+ *
+ *     Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ *
+ *     With more than a little help from;
+ *     - Alan Cox <Alan.Cox@linux.org> 
+ *
+ *      Derived from:
+ *      - skeleton.c: A network driver outline for linux.
+ *        Written 1993-94 by Donald Becker.
+ *     - ltpc.c: A driver for the LocalTalk PC card.
+ *       Written by Bradford W. Johnson.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU Public License, incorporated herein by reference.
+ *
+ *     Changes:
+ *     19970608        Alan Cox        Allowed dual card type support
+ *                                     Can set board type in insmod
+ *                                     Hooks for cops_setup routine
+ *                                     (not yet implemented).
+ *     19971101        Jay Schulist    Fixes for multiple lt* devices.
+ *     19980607        Steven Hirsch   Fixed the badly broken support
+ *                                     for Tangent type cards. Only
+ *                                      tested on Daystar LT200. Some
+ *                                      cleanup of formatting and program
+ *                                      logic.  Added emacs 'local-vars'
+ *                                      setup for Jay's brace style.
+ *     20000211        Alan Cox        Cleaned up for softnet
+ */
+
+static const char *version =
+"cops.c:v0.04 6/7/98 Jay Schulist <jschlst@turbolinux.com>\n";
+/*
+ *  Sources:
+ *      COPS Localtalk SDK. This provides almost all of the information
+ *      needed.
+ */
+
+/*
+ * insmod/modprobe configurable stuff.
+ *     - IO Port, choose one your card supports or 0 if you dare.
+ *     - IRQ, also choose one your card supports or nothing and let
+ *       the driver figure it out.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>    /* For ltalk_setup() */
+#include <linux/delay.h>       /* For udelay() */
+#include <linux/atalk.h>
+
+#include "cops.h"              /* Our Stuff */
+#include "cops_ltdrv.h"                /* Firmware code for Tangent type cards. */
+#include "cops_ffdrv.h"                /* Firmware code for Dayna type cards. */
+
+/*
+ *      The name of the card. Is used for messages and in the requests for
+ *      io regions, irqs and dma channels
+ */
+
+static const char *cardname = "cops";
+
+#ifdef CONFIG_COPS_DAYNA
+static int board_type = DAYNA; /* Module exported */
+#else
+static int board_type = TANGENT;
+#endif
+
+#ifdef MODULE
+static int io = 0x240;         /* Default IO for Dayna */
+static int irq = 5;            /* Default IRQ */
+#else
+static int io = 0;             /* Default IO for Dayna */
+static int irq = 0;            /* Default IRQ */
+#endif
+
+/*
+ *     COPS Autoprobe information.
+ *     Right now if port address is right but IRQ is not 5 this will
+ *      return a 5 no matter what since we will still get a status response.
+ *      Need one more additional check to narrow down after we have gotten
+ *      the ioaddr. But since only other possible IRQs is 3 and 4 so no real
+ *     hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with
+ *     this driver.
+ * 
+ *     This driver has 2 modes and they are: Dayna mode and Tangent mode.
+ *     Each mode corresponds with the type of card. It has been found
+ *     that there are 2 main types of cards and all other cards are
+ *     the same and just have different names or only have minor differences
+ *     such as more IO ports. As this driver is tested it will
+ *     become more clear on exactly what cards are supported. The driver
+ *     defaults to using Dayna mode. To change the drivers mode, simply
+ *     select Dayna or Tangent mode when configuring the kernel.
+ *
+ *      This driver should support:
+ *      TANGENT driver mode:
+ *              Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
+ *             COPS LT-1
+ *      DAYNA driver mode:
+ *              Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 
+ *             Farallon PhoneNET PC III, Farallon PhoneNET PC II
+ *     Other cards possibly supported mode unkown though:
+ *             Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
+ *
+ *     Cards NOT supported by this driver but supported by the ltpc.c
+ *     driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *             Farallon PhoneNET PC
+ *             Original Apple LocalTalk PC card
+ * 
+ *      N.B.
+ *
+ *      The Daystar Digital LT200 boards do not support interrupt-driven
+ *      IO.  You must specify 'irq=0xff' as a module parameter to invoke
+ *      polled mode.  I also believe that the port probing logic is quite
+ *      dangerous at best and certainly hopeless for a polled card.  Best to 
+ *      specify both. - Steve H.
+ *
+ */
+
+/*
+ * Zero terminated list of IO ports to probe.
+ */
+
+static unsigned int cops_portlist[] = { 
+       0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 
+       0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360,
+       0
+};
+
+/*
+ * Zero terminated list of IRQ ports to probe.
+ */
+
+static int cops_irqlist[] = {
+       5, 4, 3, 0 
+};
+
+static struct timer_list cops_timer;
+
+/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
+#ifndef COPS_DEBUG
+#define COPS_DEBUG 1 
+#endif
+static unsigned int cops_debug = COPS_DEBUG;
+
+/* The number of low I/O ports used by the card. */
+#define COPS_IO_EXTENT       8
+
+/* Information that needs to be kept for each board. */
+
+struct cops_local
+{
+        struct net_device_stats stats;
+        int board;                     /* Holds what board type is. */
+       int nodeid;                     /* Set to 1 once have nodeid. */
+        unsigned char node_acquire;    /* Node ID when acquired. */
+        struct at_addr node_addr;      /* Full node addres */
+};
+
+/* Index to functions, as function prototypes. */
+extern int  cops_probe (struct net_device *dev);
+static int  cops_probe1 (struct net_device *dev, int ioaddr);
+static int  cops_irq (int ioaddr, int board);
+
+static int  cops_open (struct net_device *dev);
+static int  cops_jumpstart (struct net_device *dev);
+static void cops_reset (struct net_device *dev, int sleep);
+static void cops_load (struct net_device *dev);
+static int  cops_nodeid (struct net_device *dev, int nodeid);
+
+static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void cops_poll (unsigned long ltdev);
+static void cops_timeout(struct net_device *dev);
+static void cops_rx (struct net_device *dev);
+static int  cops_send_packet (struct sk_buff *skb, struct net_device *dev);
+static void set_multicast_list (struct net_device *dev);
+static int  cops_hard_header (struct sk_buff *skb, struct net_device *dev,
+                             unsigned short type, void *daddr, void *saddr, 
+                             unsigned len);
+
+static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int  cops_close (struct net_device *dev);
+static struct net_device_stats *cops_get_stats (struct net_device *dev);
+
+
+/*
+ *      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 in [1..0x1ff], always return failure.
+ *        otherwise go with what we pass in.
+ */
+int __init cops_probe(struct net_device *dev)
+{
+       int i;
+        int base_addr = dev ? dev->base_addr : 0;
+        
+        if(base_addr == 0 && io)
+               base_addr=io;
+
+        if(base_addr > 0x1ff)    /* Check a single specified location. */
+                return cops_probe1(dev, base_addr);
+       else if(base_addr != 0)  /* Don't probe at all. */
+                       return -ENXIO;
+       
+       /* FIXME  Does this really work for cards which generate irq?
+        * It's definitely N.G. for polled Tangent. sh
+        * Dayna cards don't autoprobe well at all, but if your card is
+        * at IRQ 5 & IO 0x240 we find it every time. ;) JS
+        */
+        for(i=0; cops_portlist[i]; i++) {
+               int ioaddr = cops_portlist[i];
+               if(check_region(ioaddr, COPS_IO_EXTENT))
+                        continue;
+                if(cops_probe1(dev, ioaddr) == 0)
+                        return 0;
+        }
+       
+        return -ENODEV;
+}
+
+/*
+ *      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 __init cops_probe1(struct net_device *dev, int ioaddr)
+{
+        struct cops_local *lp;
+       static unsigned version_printed = 0;
+
+       int board = board_type;
+       
+        if(cops_debug && version_printed++ == 0)
+               printk("%s", version);
+
+        /*
+         * Since this board has jumpered interrupts, allocate the interrupt
+         * vector now. There is no point in waiting since no other device
+         * can use the interrupt, and this marks the irq as busy. Jumpered
+         * interrupts are typically not reported by the boards, and we must
+         * used AutoIRQ to find them.
+        */
+       switch (dev->irq)
+       {
+               case 0:
+                       /* COPS AutoIRQ routine */
+                       dev->irq = cops_irq(ioaddr, board);
+                       if(!dev->irq)
+                               return -EINVAL; /* No IRQ found on this port */
+                       break;
+
+               case 1:
+                       return -EINVAL;
+                       break;
+
+               /* Fixup for users that don't know that IRQ 2 is really
+                * IRQ 9, or don't know which one to set.
+                */
+               case 2:
+                       dev->irq = 9;
+                       break;
+
+               /* Polled operation requested. Although irq of zero passed as
+                * a parameter tells the init routines to probe, we'll
+                * overload it to denote polled operation at runtime.
+                */
+               case 0xff:
+                       dev->irq = 0;
+                       break;
+
+               default:
+                       break;
+       }
+
+       /* Reserve any actual interrupt. */
+       if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev))
+               return -EINVAL;
+
+       /* Grab the region so no one else tries to probe our ioports. */
+       request_region(ioaddr, COPS_IO_EXTENT, cardname);
+       dev->base_addr          = ioaddr;
+
+       /* Initialize the private device structure. */
+        dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL);
+        if(dev->priv == NULL)
+               return -ENOMEM;
+
+        lp = (struct cops_local *)dev->priv;
+        memset(lp, 0, sizeof(struct cops_local));
+
+       /* Copy local board variable to lp struct. */
+       lp->board               = board;
+
+       /* Fill in the fields of the device structure with LocalTalk values. */
+       ltalk_setup(dev);
+
+       dev->hard_start_xmit    = cops_send_packet;
+       dev->tx_timeout         = cops_timeout;
+       dev->watchdog_timeo     = HZ * 2;
+       dev->hard_header        = cops_hard_header;
+        dev->get_stats          = cops_get_stats;
+       dev->open               = cops_open;
+        dev->stop               = cops_close;
+        dev->do_ioctl           = cops_ioctl;
+       dev->set_multicast_list = set_multicast_list;
+        dev->mc_list            = NULL;
+
+       /* Tell the user where the card is and what mode we're in. */
+       if(board==DAYNA)
+               printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
+                       dev->name, cardname, ioaddr, dev->irq);
+       if(board==TANGENT) {
+               if(dev->irq)
+                       printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
+                               dev->name, cardname, ioaddr, dev->irq);
+               else
+                       printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
+                               dev->name, cardname, ioaddr);
+
+       }
+        return 0;
+}
+
+static int __init cops_irq (int ioaddr, int board)
+{       /*
+         * This does not use the IRQ to determine where the IRQ is. We just
+         * assume that when we get a correct status response that it's the IRQ.
+         * This really just verifies the IO port but since we only have access
+         * to such a small number of IRQs (5, 4, 3) this is not bad.
+         * This will probably not work for more than one card.
+         */
+        int irqaddr=0;
+        int i, x, status;
+
+        if(board==DAYNA)
+        {
+                outb(0, ioaddr+DAYNA_RESET);
+                inb(ioaddr+DAYNA_RESET);
+                udelay(333333);
+        }
+        if(board==TANGENT)
+        {
+                inb(ioaddr);
+                outb(0, ioaddr);
+                outb(0, ioaddr+TANG_RESET);
+        }
+
+        for(i=0; cops_irqlist[i] !=0; i++)
+        {
+                irqaddr = cops_irqlist[i];
+                for(x = 0xFFFF; x>0; x --)    /* wait for response */
+                {
+                        if(board==DAYNA)
+                        {
+                                status = (inb(ioaddr+DAYNA_CARD_STATUS)&3);
+                                if(status == 1)
+                                        return irqaddr;
+                        }
+                        if(board==TANGENT)
+                        {
+                                if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0)
+                                        return irqaddr;
+                        }
+                }
+        }
+        return 0;       /* no IRQ found */
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ */
+static int cops_open(struct net_device *dev)
+{
+    struct cops_local *lp = (struct cops_local *)dev->priv;
+
+       if(dev->irq==0)
+       {
+               /*
+                * I don't know if the Dayna-style boards support polled 
+                * operation.  For now, only allow it for Tangent.
+                */
+               if(lp->board==TANGENT)  /* Poll 20 times per second */
+               {
+                   init_timer(&cops_timer);
+                   cops_timer.function = cops_poll;
+                   cops_timer.data     = (unsigned long)dev;
+                   cops_timer.expires  = jiffies + 5;
+                   add_timer(&cops_timer);
+               } 
+               else 
+               {
+                       printk(KERN_WARNING "%s: No irq line set\n", dev->name);
+                       return -EAGAIN;
+               }
+       }
+
+       cops_jumpstart(dev);    /* Start the card up. */
+
+       netif_start_queue(dev);
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
+
+        return 0;
+}
+
+/*
+ *     This allows for a dynamic start/restart of the entire card.
+ */
+static int cops_jumpstart(struct net_device *dev)
+{
+       struct cops_local *lp = (struct cops_local *)dev->priv;
+
+       /*
+         *      Once the card has the firmware loaded and has acquired
+         *      the nodeid, if it is reset it will lose it all.
+         */
+        cops_reset(dev,1);     /* Need to reset card before load firmware. */
+        cops_load(dev);                /* Load the firmware. */
+
+       /*
+        *      If atalkd already gave us a nodeid we will use that
+        *      one again, else we wait for atalkd to give us a nodeid
+        *      in cops_ioctl. This may cause a problem if someone steals
+        *      our nodeid while we are resetting.
+        */     
+       if(lp->nodeid == 1)
+               cops_nodeid(dev,lp->node_acquire);
+
+       return 0;
+}
+
+static void tangent_wait_reset(int ioaddr)
+{
+       int timeout=0;
+
+       while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+               mdelay(1);   /* Wait 1 second */
+}
+
+/*
+ *      Reset the LocalTalk board.
+ */
+static void cops_reset(struct net_device *dev, int sleep)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr=dev->base_addr;
+
+        if(lp->board==TANGENT)
+        {
+                inb(ioaddr);           /* Clear request latch. */
+                outb(0,ioaddr);                /* Clear the TANG_TX_READY flop. */
+                outb(0, ioaddr+TANG_RESET);    /* Reset the adapter. */
+
+               tangent_wait_reset(ioaddr);
+                outb(0, ioaddr+TANG_CLEAR_INT);
+        }
+        if(lp->board==DAYNA)
+        {
+                outb(0, ioaddr+DAYNA_RESET);   /* Assert the reset port */
+                inb(ioaddr+DAYNA_RESET);       /* Clear the reset */
+                if(sleep)
+                {
+                        long snap=jiffies;
+
+                       /* Let card finish initializing, about 1/3 second */
+                       while(jiffies-snap<HZ/3)
+                                schedule();
+                }
+                else
+                        udelay(333333);
+        }
+       netif_wake_queue(dev);
+       return;
+}
+
+static void cops_load (struct net_device *dev)
+{
+        struct ifreq ifr;
+        struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data;
+        struct cops_local *lp=(struct cops_local *)dev->priv;
+        int ioaddr=dev->base_addr;
+       int length, i = 0;
+
+        strcpy(ifr.ifr_name,"lt0");
+
+        /* Get card's firmware code and do some checks on it. */
+#ifdef CONFIG_COPS_DAYNA        
+        if(lp->board==DAYNA)
+        {
+                ltf->length=sizeof(ffdrv_code);
+                ltf->data=ffdrv_code;
+        }
+        else
+#endif        
+#ifdef CONFIG_COPS_TANGENT
+        if(lp->board==TANGENT)
+        {
+                ltf->length=sizeof(ltdrv_code);
+                ltf->data=ltdrv_code;
+        }
+        else
+#endif
+       {
+               printk(KERN_INFO "%s; unsupported board type.\n", dev->name);
+               return;
+       }
+       
+        /* Check to make sure firmware is correct length. */
+        if(lp->board==DAYNA && ltf->length!=5983)
+        {
+                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);
+                return;
+        }
+        if(lp->board==TANGENT && ltf->length!=2501)
+        {
+                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);
+                return;
+        }
+
+        if(lp->board==DAYNA)
+        {
+                /*
+                 *      We must wait for a status response
+                 *      with the DAYNA board.
+                 */
+                while(++i<65536)
+                {
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)
+                                break;
+                }
+
+                if(i==65536)
+                        return;
+        }
+
+        /*
+         *      Upload the firmware and kick. Byte-by-byte works nicely here.
+         */
+       i=0;
+        length = ltf->length;
+        while(length--)
+        {
+                outb(ltf->data[i], ioaddr);
+                i++;
+        }
+
+       if(cops_debug > 1)
+               printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
+                       dev->name, i, ltf->length);
+
+        if(lp->board==DAYNA)   /* Tell Dayna to run the firmware code. */
+                outb(1, ioaddr+DAYNA_INT_CARD);
+       else                    /* Tell Tang to run the firmware code. */
+               inb(ioaddr);
+
+        if(lp->board==TANGENT)
+        {
+                tangent_wait_reset(ioaddr);
+                inb(ioaddr);   /* Clear initial ready signal. */
+        }
+
+        return;
+}
+
+/*
+ *     Get the LocalTalk Nodeid from the card. We can suggest
+ *     any nodeid 1-254. The card will try and get that exact
+ *     address else we can specify 0 as the nodeid and the card
+ *     will autoprobe for a nodeid.
+ */
+static int cops_nodeid (struct net_device *dev, int nodeid)
+{
+       struct cops_local *lp = (struct cops_local *) dev->priv;
+       int ioaddr = dev->base_addr;
+
+       if(lp->board == DAYNA)
+        {
+               /* Empty any pending adapter responses. */
+                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
+                {
+                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+                               cops_rx(dev);   /* Kick any packets waiting. */
+                       schedule();
+                }
+
+                outb(2, ioaddr);               /* Output command packet length as 2. */
+                outb(0, ioaddr);
+                outb(LAP_INIT, ioaddr);        /* Send LAP_INIT command byte. */
+                outb(nodeid, ioaddr);          /* Suggest node address. */
+        }
+
+       if(lp->board == TANGENT)
+        {
+                /* Empty any pending adapter responses. */
+                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
+                {
+                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */
+                       cops_rx(dev);           /* Kick out packets waiting. */
+                       schedule();
+                }
+
+               /* Not sure what Tangent does if nodeid picked is used. */
+                if(nodeid == 0)                                /* Seed. */
+                       nodeid = jiffies&0xFF;          /* Get a random try */
+                outb(2, ioaddr);                       /* Command length LSB */
+                outb(0, ioaddr);                               /* Command length MSB */
+                outb(LAP_INIT, ioaddr);                /* Send LAP_INIT byte */
+                outb(nodeid, ioaddr);                  /* LAP address hint. */
+                outb(0xFF, ioaddr);                    /* Int. level to use */
+        }
+
+       lp->node_acquire=0;             /* Set nodeid holder to 0. */
+        while(lp->node_acquire==0)     /* Get *True* nodeid finally. */
+       {
+               outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */
+
+               if(lp->board == DAYNA)
+               {
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+                               cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
+               }
+               if(lp->board == TANGENT)
+               {       
+                       if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
+                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
+               }
+               schedule();
+       }
+
+       if(cops_debug > 1)
+               printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
+                       dev->name, lp->node_acquire);
+
+       lp->nodeid=1;   /* Set got nodeid to 1. */
+
+        return 0;
+}
+
+/*
+ *     Poll the Tangent type cards to see if we have work.
+ */
+static void cops_poll(unsigned long ltdev)
+{
+       int ioaddr, status;
+       int boguscount = 0;
+
+       struct net_device *dev = (struct net_device *)ltdev;
+
+       del_timer(&cops_timer);
+
+       if(dev == NULL)
+               return; /* We've been downed */
+
+       ioaddr = dev->base_addr;
+       do {
+               status=inb(ioaddr+TANG_CARD_STATUS);
+               if(status & TANG_RX_READY)
+                       cops_rx(dev);
+               if(status & TANG_TX_READY)
+                       netif_wake_queue(dev);
+               status = inb(ioaddr+TANG_CARD_STATUS);
+       } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+
+       cops_timer.expires = jiffies+5;
+       add_timer(&cops_timer);
+
+       return;
+}
+
+/*
+ *      The typical workload of the driver:
+ *      Handle the network interface interrupts.
+ */
+static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+        struct net_device *dev = dev_id;
+        struct cops_local *lp;
+        int ioaddr, status;
+        int boguscount = 0;
+
+        ioaddr = dev->base_addr;
+        lp = (struct cops_local *)dev->priv;
+
+       if(lp->board==DAYNA)
+       {
+               do {
+                       outb(0, ioaddr + COPS_CLEAR_INT);
+                               status=inb(ioaddr+DAYNA_CARD_STATUS);
+                               if((status&0x03)==DAYNA_RX_REQUEST)
+                                       cops_rx(dev);
+                       netif_wake_queue(dev);
+               } while(++boguscount < 20);
+       }
+       else
+       {
+               do {
+                               status=inb(ioaddr+TANG_CARD_STATUS);
+                       if(status & TANG_RX_READY)
+                               cops_rx(dev);
+                       if(status & TANG_TX_READY)
+                               netif_wake_queue(dev);
+                       status=inb(ioaddr+TANG_CARD_STATUS);
+               } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+       }
+
+        return;
+}
+
+/*
+ *      We have a good packet(s), get it/them out of the buffers.
+ */
+static void cops_rx(struct net_device *dev)
+{
+        int pkt_len = 0;
+        int rsp_type = 0;
+        struct sk_buff *skb;
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr = dev->base_addr;
+        int boguscount = 0;
+        unsigned long flags;
+
+
+       save_flags(flags);
+        cli();  /* Disable interrupts. */
+
+        if(lp->board==DAYNA)
+        {
+                outb(0, ioaddr);                /* Send out Zero length. */
+                outb(0, ioaddr);
+                outb(DATA_READ, ioaddr);        /* Send read command out. */
+
+                /* Wait for DMA to turn around. */
+                while(++boguscount<1000000)
+                {
+                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
+                                break;
+                }
+
+                if(boguscount==1000000)
+                {
+                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);
+                        return;
+                }
+        }
+
+        /* Get response length. */
+       if(lp->board==DAYNA)
+               pkt_len = inb(ioaddr) & 0xFF;
+       else
+               pkt_len = inb(ioaddr) & 0x00FF;
+        pkt_len |= (inb(ioaddr) << 8);
+        /* Input IO code. */
+        rsp_type=inb(ioaddr);
+
+        /* Malloc up new buffer. */
+        skb = dev_alloc_skb(pkt_len);
+        if(skb == NULL)
+        {
+                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
+                       dev->name);
+                lp->stats.rx_dropped++;
+                while(pkt_len--)        /* Discard packet */
+                        inb(ioaddr);
+                return;
+        }
+        skb->dev = dev;
+        skb_put(skb, pkt_len);
+        skb->protocol = htons(ETH_P_LOCALTALK);
+
+        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
+
+        if(lp->board==DAYNA)
+                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
+
+        restore_flags(flags);  /* Restore interrupts. */
+
+        /* Check for bad response length */
+        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
+        {
+               printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
+                       dev->name, pkt_len);
+                lp->stats.tx_errors++;
+                kfree_skb(skb);
+                return;
+        }
+
+        /* Set nodeid and then get out. */
+        if(rsp_type == LAP_INIT_RSP)
+        {      /* Nodeid taken from received packet. */
+                lp->node_acquire = skb->data[0];
+                kfree_skb(skb);
+                return;
+        }
+
+        /* One last check to make sure we have a good packet. */
+        if(rsp_type != LAP_RESPONSE)
+        {
+                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
+                lp->stats.tx_errors++;
+                kfree_skb(skb);
+                return;
+        }
+
+        skb->mac.raw    = skb->data;    /* Point to entire packet. */
+        skb_pull(skb,3);
+        skb->h.raw      = skb->data;    /* Point to data (Skip header). */
+
+        /* Update the counters. */
+        lp->stats.rx_packets++;
+        lp->stats.rx_bytes += skb->len;
+
+        /* Send packet to a higher place. */
+        netif_rx(skb);
+
+        return;
+}
+
+static void cops_timeout(struct net_device *dev)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr = dev->base_addr;
+
+       lp->stats.tx_errors++;
+        if(lp->board==TANGENT)
+        {
+               if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+                               printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
+       }
+       printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
+       cops_jumpstart(dev);    /* Restart the card. */
+       dev->trans_start = jiffies;
+       netif_wake_queue(dev);
+}
+
+
+/*
+ *     Make the card transmit a LocalTalk packet.
+ */
+
+static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr = dev->base_addr;
+        unsigned long flags;
+
+        /*
+         * Block a timer-based transmit from overlapping. 
+        */
+        
+       netif_stop_queue(dev);
+
+       save_flags(flags);      
+       cli();  /* Disable interrupts. */
+       if(lp->board == DAYNA)   /* Wait for adapter transmit buffer. */
+               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+       if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
+               while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
+
+       /* Output IO length. */
+       outb(skb->len, ioaddr);
+       if(lp->board == DAYNA)
+                       outb(skb->len >> 8, ioaddr);
+       else
+               outb((skb->len >> 8)&0x0FF, ioaddr);
+
+       /* Output IO code. */
+       outb(LAP_WRITE, ioaddr);
+
+       if(lp->board == DAYNA)  /* Check the transmit buffer again. */
+               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+
+       outsb(ioaddr, skb->data, skb->len);     /* Send out the data. */
+
+       if(lp->board==DAYNA)    /* Dayna requires you kick the card */
+               outb(1, ioaddr+DAYNA_INT_CARD);
+
+       restore_flags(flags);   /* Restore interrupts. */
+
+       /* Done sending packet, update counters and cleanup. */
+       lp->stats.tx_packets++;
+       lp->stats.tx_bytes += skb->len;
+       dev->trans_start = jiffies;
+       dev_kfree_skb (skb);
+        return 0;
+}
+
+/*
+ *     Dummy function to keep the Appletalk layer happy.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+        if(cops_debug >= 3)
+               printk("%s: set_multicast_list executed\n", dev->name);
+}
+
+/*
+ *      Another Dummy function to keep the Appletalk layer happy.
+ */
+static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
+                           unsigned short type, void *daddr, void *saddr, 
+                           unsigned len)
+{
+        if(cops_debug >= 3)
+                printk("%s: cops_hard_header executed. Wow!\n", dev->name);
+        return 0;
+}
+
+/*
+ *      System ioctls for the COPS LocalTalk card.
+ */
+static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr;
+        struct at_addr *aa=(struct at_addr *)&lp->node_addr;
+
+        switch(cmd)
+        {
+                case SIOCSIFADDR:
+                       /* Get and set the nodeid and network # atalkd wants. */
+                       cops_nodeid(dev, sa->sat_addr.s_node);
+                       aa->s_net               = sa->sat_addr.s_net;
+                        aa->s_node              = lp->node_acquire;
+
+                       /* Set broardcast address. */
+                        dev->broadcast[0]       = 0xFF;
+                       
+                       /* Set hardware address. */
+                        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 -EOPNOTSUPP;
+        }
+}
+
+/*
+ *     The inverse routine to cops_open().
+ */
+static int cops_close(struct net_device *dev)
+{
+       struct cops_local *lp = (struct cops_local *)dev->priv;
+
+       /* If we were running polled, yank the timer.
+        */
+       if(lp->board==TANGENT && dev->irq==0)
+               del_timer(&cops_timer);
+
+       netif_stop_queue(dev);
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
+       
+        return 0;
+}
+
+/*
+ *      Get the current statistics.
+ *      This may be called with the card open or closed.
+ */
+static struct net_device_stats *cops_get_stats(struct net_device *dev)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        return &lp->stats;
+}
+
+#ifdef MODULE
+static char lt_name[16];
+
+static struct net_device cops0_dev =
+{
+       lt_name,        /* device name */
+        0, 0, 0, 0,
+        0x0, 0,  /* I/O address, IRQ */
+        0, 0, 0, NULL, cops_probe
+};
+
+
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(board_type, "i");
+
+int init_module(void)
+{
+        int result, err;
+
+        if(io == 0)
+               printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
+                       cardname);
+
+        /* Copy the parameters from insmod into the device structure. */
+        cops0_dev.base_addr = io;
+        cops0_dev.irq       = irq;
+
+       err=dev_alloc_name(&cops0_dev, "lt%d");
+        if(err < 0)
+                return err;
+
+        if((result = register_netdev(&cops0_dev)) != 0)
+                return result;
+
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+       unregister_netdev(&cops0_dev);
+       if(cops0_dev.priv)
+                kfree_s(cops0_dev.priv, sizeof(struct cops_local));
+       if(cops0_dev.irq)
+               free_irq(cops0_dev.irq, &cops0_dev);
+        release_region(cops0_dev.base_addr, COPS_IO_EXTENT);
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
+ *  c-basic-offset: 4
+ *  c-file-offsets: ((substatement-open . 0))
+ * End:
+ */
diff --git a/drivers/net/appletalk/cops.h b/drivers/net/appletalk/cops.h
new file mode 100644 (file)
index 0000000..4386349
--- /dev/null
@@ -0,0 +1,60 @@
+/*      cops.h: LocalTalk driver for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ */
+
+#ifndef __LINUX_COPSLTALK_H
+#define __LINUX_COPSLTALK_H
+
+#ifdef __KERNEL__
+
+/* Max LLAP size we will accept. */
+#define MAX_LLAP_SIZE          603
+
+/* Tangent */
+#define TANG_CARD_STATUS        1
+#define TANG_CLEAR_INT          1
+#define TANG_RESET              3
+
+#define TANG_TX_READY           1
+#define TANG_RX_READY           2
+
+/* Dayna */
+#define DAYNA_CMD_DATA          0
+#define DAYNA_CLEAR_INT         1
+#define DAYNA_CARD_STATUS       2
+#define DAYNA_INT_CARD          3
+#define DAYNA_RESET             4
+
+#define DAYNA_RX_READY          0
+#define DAYNA_TX_READY          1
+#define DAYNA_RX_REQUEST        3
+
+/* Same on both card types */
+#define COPS_CLEAR_INT  1
+
+/* LAP response codes received from the cards. */
+#define LAP_INIT        1       /* Init cmd */
+#define LAP_INIT_RSP    2       /* Init response */
+#define LAP_WRITE       3       /* Write cmd */
+#define DATA_READ       4       /* Data read */
+#define LAP_RESPONSE    4       /* Received ALAP frame response */
+#define LAP_GETSTAT     5       /* Get LAP and HW status */
+#define LAP_RSPSTAT     6       /* Status response */
+
+#endif
+
+/*
+ *     Structure to hold the firmware information.
+ */
+struct ltfirmware
+{
+        unsigned int length;
+        unsigned char * data;
+};
+
+#define DAYNA 1
+#define TANGENT 2
+
+#endif
diff --git a/drivers/net/appletalk/cops_ffdrv.h b/drivers/net/appletalk/cops_ffdrv.h
new file mode 100644 (file)
index 0000000..3a20437
--- /dev/null
@@ -0,0 +1,533 @@
+
+/*
+ *     The firmware this driver downloads into the Localtalk card is a
+ *     separate program and is not GPL'd source code, even though the Linux
+ *     side driver and the routine that loads this data into the card are.
+ *     
+ *     It is taken from the COPS SDK and is under the following license
+ *
+ *     This material is licensed to you strictly for use in conjunction with
+ *     the use of COPS LocalTalk adapters.
+ *     There is no charge for this SDK. And no waranty express or implied
+ *     about its fitness for any purpose. However, we will cheerefully
+ *     refund every penny you paid for this SDK...
+ *     Regards,
+ *
+ *     Thomas F. Divine
+ *     Chief Scientist
+ */
+
+
+/*      cops_ffdrv.h: LocalTalk driver firmware dump for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_COPS_DAYNA
+
+unsigned char ffdrv_code[] = {
+       58,3,0,50,228,149,33,255,255,34,226,149,
+       249,17,40,152,33,202,154,183,237,82,77,68,
+       11,107,98,19,54,0,237,176,175,50,80,0,
+       62,128,237,71,62,32,237,57,51,62,12,237,
+       57,50,237,57,54,62,6,237,57,52,62,12,
+       237,57,49,33,107,137,34,32,128,33,83,130,
+       34,40,128,33,86,130,34,42,128,33,112,130,
+       34,36,128,33,211,130,34,38,128,62,0,237,
+       57,16,33,63,148,34,34,128,237,94,205,15,
+       130,251,205,168,145,24,141,67,111,112,121,114,
+       105,103,104,116,32,40,67,41,32,49,57,56,
+       56,32,45,32,68,97,121,110,97,32,67,111,
+       109,109,117,110,105,99,97,116,105,111,110,115,
+       32,32,32,65,108,108,32,114,105,103,104,116,
+       115,32,114,101,115,101,114,118,101,100,46,32,
+       32,40,68,40,68,7,16,8,34,7,22,6,
+       16,5,12,4,8,3,6,140,0,16,39,128,
+       0,4,96,10,224,6,0,7,126,2,64,11,
+       118,12,6,13,0,14,193,15,0,5,96,3,
+       192,1,64,9,8,62,9,211,66,62,192,211,
+       66,62,100,61,32,253,6,28,33,205,129,14,
+       66,237,163,194,253,129,6,28,33,205,129,14,
+       64,237,163,194,9,130,201,62,47,50,71,152,
+       62,47,211,68,58,203,129,237,57,20,58,204,
+       129,237,57,21,33,77,152,54,132,205,233,129,
+       58,228,149,254,209,40,6,56,4,62,0,24,
+       2,219,96,33,233,149,119,230,62,33,232,149,
+       119,213,33,8,152,17,7,0,25,119,19,25,
+       119,209,201,251,237,77,245,197,213,229,221,229,
+       205,233,129,62,1,50,106,137,205,158,139,221,
+       225,225,209,193,241,251,237,77,245,197,213,219,
+       72,237,56,16,230,46,237,57,16,237,56,12,
+       58,72,152,183,32,26,6,20,17,128,2,237,
+       56,46,187,32,35,237,56,47,186,32,29,219,
+       72,230,1,32,3,5,32,232,175,50,72,152,
+       229,221,229,62,1,50,106,137,205,158,139,221,
+       225,225,24,25,62,1,50,72,152,58,201,129,
+       237,57,12,58,202,129,237,57,13,237,56,16,
+       246,17,237,57,16,209,193,241,251,237,77,245,
+       197,229,213,221,229,237,56,16,230,17,237,57,
+       16,237,56,20,58,34,152,246,16,246,8,211,
+       68,62,6,61,32,253,58,34,152,246,8,211,
+       68,58,203,129,237,57,20,58,204,129,237,57,
+       21,237,56,16,246,34,237,57,16,221,225,209,
+       225,193,241,251,237,77,33,2,0,57,126,230,
+       3,237,100,1,40,2,246,128,230,130,245,62,
+       5,211,64,241,211,64,201,229,213,243,237,56,
+       16,230,46,237,57,16,237,56,12,251,70,35,
+       35,126,254,175,202,77,133,254,129,202,15,133,
+       230,128,194,191,132,43,58,44,152,119,33,76,
+       152,119,35,62,132,119,120,254,255,40,4,58,
+       49,152,119,219,72,43,43,112,17,3,0,237,
+       56,52,230,248,237,57,52,219,72,230,1,194,
+       141,131,209,225,237,56,52,246,6,237,57,52,
+       62,1,55,251,201,62,3,211,66,62,192,211,
+       66,62,48,211,66,0,0,219,66,230,1,40,
+       4,219,67,24,240,205,203,135,58,75,152,254,
+       255,202,128,132,58,49,152,254,161,250,207,131,
+       58,34,152,211,68,62,10,211,66,62,128,211,
+       66,62,11,211,66,62,6,211,66,24,0,62,
+       14,211,66,62,33,211,66,62,1,211,66,62,
+       64,211,66,62,3,211,66,62,209,211,66,62,
+       100,71,219,66,230,1,32,6,5,32,247,195,
+       248,132,219,67,71,58,44,152,184,194,248,132,
+       62,100,71,219,66,230,1,32,6,5,32,247,
+       195,248,132,219,67,62,100,71,219,66,230,1,
+       32,6,5,32,247,195,248,132,219,67,254,133,
+       32,7,62,0,50,74,152,24,17,254,173,32,
+       7,62,1,50,74,152,24,6,254,141,194,248,
+       132,71,209,225,58,49,152,254,132,32,10,62,
+       50,205,2,134,205,144,135,24,27,254,140,32,
+       15,62,110,205,2,134,62,141,184,32,5,205,
+       144,135,24,8,62,10,205,2,134,205,8,134,
+       62,1,50,106,137,205,158,139,237,56,52,246,
+       6,237,57,52,175,183,251,201,62,20,135,237,
+       57,20,175,237,57,21,237,56,16,246,2,237,
+       57,16,237,56,20,95,237,56,21,123,254,10,
+       48,244,237,56,16,230,17,237,57,16,209,225,
+       205,144,135,62,1,50,106,137,205,158,139,237,
+       56,52,246,6,237,57,52,175,183,251,201,209,
+       225,243,219,72,230,1,40,13,62,10,211,66,
+       0,0,219,66,230,192,202,226,132,237,56,52,
+       246,6,237,57,52,62,1,55,251,201,205,203,
+       135,62,1,50,106,137,205,158,139,237,56,52,
+       246,6,237,57,52,183,251,201,209,225,62,1,
+       50,106,137,205,158,139,237,56,52,246,6,237,
+       57,52,62,2,55,251,201,209,225,243,219,72,
+       230,1,202,213,132,62,10,211,66,0,0,219,
+       66,230,192,194,213,132,229,62,1,50,106,137,
+       42,40,152,205,65,143,225,17,3,0,205,111,
+       136,62,6,211,66,58,44,152,211,66,237,56,
+       52,246,6,237,57,52,183,251,201,209,197,237,
+       56,52,230,248,237,57,52,219,72,230,1,32,
+       15,193,225,237,56,52,246,6,237,57,52,62,
+       1,55,251,201,14,23,58,37,152,254,0,40,
+       14,14,2,254,1,32,5,62,140,119,24,3,
+       62,132,119,43,43,197,205,203,135,193,62,1,
+       211,66,62,64,211,66,62,3,211,66,62,193,
+       211,66,62,100,203,39,71,219,66,230,1,32,
+       6,5,32,247,195,229,133,33,238,151,219,67,
+       71,58,44,152,184,194,229,133,119,62,100,71,
+       219,66,230,1,32,6,5,32,247,195,229,133,
+       219,67,35,119,13,32,234,193,225,62,1,50,
+       106,137,205,158,139,237,56,52,246,6,237,57,
+       52,175,183,251,201,33,234,151,35,35,62,255,
+       119,193,225,62,1,50,106,137,205,158,139,237,
+       56,52,246,6,237,57,52,175,251,201,243,61,
+       32,253,251,201,62,3,211,66,62,192,211,66,
+       58,49,152,254,140,32,19,197,229,213,17,181,
+       129,33,185,129,1,2,0,237,176,209,225,193,
+       24,27,229,213,33,187,129,58,49,152,230,15,
+       87,30,2,237,92,25,17,181,129,126,18,19,
+       35,126,18,209,225,58,34,152,246,8,211,68,
+       58,49,152,254,165,40,14,254,164,40,10,62,
+       10,211,66,62,224,211,66,24,25,58,74,152,
+       254,0,40,10,62,10,211,66,62,160,211,66,
+       24,8,62,10,211,66,62,128,211,66,62,11,
+       211,66,62,6,211,66,205,147,143,62,5,211,
+       66,62,224,211,66,62,5,211,66,62,96,211,
+       66,62,5,61,32,253,62,5,211,66,62,224,
+       211,66,62,14,61,32,253,62,5,211,66,62,
+       233,211,66,62,128,211,66,58,181,129,61,32,
+       253,62,1,211,66,62,192,211,66,1,254,19,
+       237,56,46,187,32,6,13,32,247,195,226,134,
+       62,192,211,66,0,0,219,66,203,119,40,250,
+       219,66,203,87,40,250,243,237,56,16,230,17,
+       237,57,16,237,56,20,251,62,5,211,66,62,
+       224,211,66,58,182,129,61,32,253,229,33,181,
+       129,58,183,129,203,63,119,35,58,184,129,119,
+       225,62,10,211,66,62,224,211,66,62,11,211,
+       66,62,118,211,66,62,47,211,68,62,5,211,
+       66,62,233,211,66,58,181,129,61,32,253,62,
+       5,211,66,62,224,211,66,58,182,129,61,32,
+       253,62,5,211,66,62,96,211,66,201,229,213,
+       58,50,152,230,15,87,30,2,237,92,33,187,
+       129,25,17,181,129,126,18,35,19,126,18,209,
+       225,58,71,152,246,8,211,68,58,50,152,254,
+       165,40,14,254,164,40,10,62,10,211,66,62,
+       224,211,66,24,8,62,10,211,66,62,128,211,
+       66,62,11,211,66,62,6,211,66,195,248,135,
+       62,3,211,66,62,192,211,66,197,229,213,17,
+       181,129,33,183,129,1,2,0,237,176,209,225,
+       193,62,47,211,68,62,10,211,66,62,224,211,
+       66,62,11,211,66,62,118,211,66,62,1,211,
+       66,62,0,211,66,205,147,143,195,16,136,62,
+       3,211,66,62,192,211,66,197,229,213,17,181,
+       129,33,183,129,1,2,0,237,176,209,225,193,
+       62,47,211,68,62,10,211,66,62,224,211,66,
+       62,11,211,66,62,118,211,66,205,147,143,62,
+       5,211,66,62,224,211,66,62,5,211,66,62,
+       96,211,66,62,5,61,32,253,62,5,211,66,
+       62,224,211,66,62,14,61,32,253,62,5,211,
+       66,62,233,211,66,62,128,211,66,58,181,129,
+       61,32,253,62,1,211,66,62,192,211,66,1,
+       254,19,237,56,46,187,32,6,13,32,247,195,
+       88,136,62,192,211,66,0,0,219,66,203,119,
+       40,250,219,66,203,87,40,250,62,5,211,66,
+       62,224,211,66,58,182,129,61,32,253,62,5,
+       211,66,62,96,211,66,201,197,14,67,6,0,
+       62,3,211,66,62,192,211,66,62,48,211,66,
+       0,0,219,66,230,1,40,4,219,67,24,240,
+       62,5,211,66,62,233,211,66,62,128,211,66,
+       58,181,129,61,32,253,237,163,29,62,192,211,
+       66,219,66,230,4,40,250,237,163,29,32,245,
+       219,66,230,4,40,250,62,255,71,219,66,230,
+       4,40,3,5,32,247,219,66,230,4,40,250,
+       62,5,211,66,62,224,211,66,58,182,129,61,
+       32,253,62,5,211,66,62,96,211,66,58,71,
+       152,254,1,202,18,137,62,16,211,66,62,56,
+       211,66,62,14,211,66,62,33,211,66,62,1,
+       211,66,62,248,211,66,237,56,48,246,153,230,
+       207,237,57,48,62,3,211,66,62,221,211,66,
+       193,201,58,71,152,211,68,62,10,211,66,62,
+       128,211,66,62,11,211,66,62,6,211,66,62,
+       6,211,66,58,44,152,211,66,62,16,211,66,
+       62,56,211,66,62,48,211,66,0,0,62,14,
+       211,66,62,33,211,66,62,1,211,66,62,248,
+       211,66,237,56,48,246,145,246,8,230,207,237,
+       57,48,62,3,211,66,62,221,211,66,193,201,
+       44,3,1,0,70,69,1,245,197,213,229,175,
+       50,72,152,237,56,16,230,46,237,57,16,237,
+       56,12,62,1,211,66,0,0,219,66,95,230,
+       160,32,3,195,20,139,123,230,96,194,72,139,
+       62,48,211,66,62,1,211,66,62,64,211,66,
+       237,91,40,152,205,207,143,25,43,55,237,82,
+       218,70,139,34,42,152,98,107,58,44,152,190,
+       194,210,138,35,35,62,130,190,194,200,137,62,
+       1,50,48,152,62,175,190,202,82,139,62,132,
+       190,32,44,50,50,152,62,47,50,71,152,229,
+       175,50,106,137,42,40,152,205,65,143,225,54,
+       133,43,70,58,44,152,119,43,112,17,3,0,
+       62,10,205,2,134,205,111,136,195,158,138,62,
+       140,190,32,19,50,50,152,58,233,149,230,4,
+       202,222,138,62,1,50,71,152,195,219,137,126,
+       254,160,250,185,138,254,166,242,185,138,50,50,
+       152,43,126,35,229,213,33,234,149,95,22,0,
+       25,126,254,132,40,18,254,140,40,14,58,50,
+       152,230,15,87,126,31,21,242,65,138,56,2,
+       175,119,58,50,152,230,15,87,58,233,149,230,
+       62,31,21,242,85,138,218,98,138,209,225,195,
+       20,139,58,50,152,33,100,137,230,15,95,22,
+       0,25,126,50,71,152,209,225,58,50,152,254,
+       164,250,135,138,58,73,152,254,0,40,4,54,
+       173,24,2,54,133,43,70,58,44,152,119,43,
+       112,17,3,0,205,70,135,175,50,106,137,205,
+       208,139,58,199,129,237,57,12,58,200,129,237,
+       57,13,237,56,16,246,17,237,57,16,225,209,
+       193,241,251,237,77,62,129,190,194,227,138,54,
+       130,43,70,58,44,152,119,43,112,17,3,0,
+       205,144,135,195,20,139,35,35,126,254,132,194,
+       227,138,175,50,106,137,205,158,139,24,42,58,
+       201,154,254,1,40,7,62,1,50,106,137,24,
+       237,58,106,137,254,1,202,222,138,62,128,166,
+       194,222,138,221,229,221,33,67,152,205,127,142,
+       205,109,144,221,225,225,209,193,241,251,237,77,
+       58,106,137,254,1,202,44,139,58,50,152,254,
+       164,250,44,139,58,73,152,238,1,50,73,152,
+       221,229,221,33,51,152,205,127,142,221,225,62,
+       1,50,106,137,205,158,139,195,13,139,24,208,
+       24,206,24,204,230,64,40,3,195,20,139,195,
+       20,139,43,126,33,8,152,119,35,58,44,152,
+       119,43,237,91,35,152,205,203,135,205,158,139,
+       195,13,139,175,50,78,152,62,3,211,66,62,
+       192,211,66,201,197,33,4,0,57,126,35,102,
+       111,62,1,50,106,137,219,72,205,141,139,193,
+       201,62,1,50,78,152,34,40,152,54,0,35,
+       35,54,0,195,163,139,58,78,152,183,200,229,
+       33,181,129,58,183,129,119,35,58,184,129,119,
+       225,62,47,211,68,62,14,211,66,62,193,211,
+       66,62,10,211,66,62,224,211,66,62,11,211,
+       66,62,118,211,66,195,3,140,58,78,152,183,
+       200,58,71,152,211,68,254,69,40,4,254,70,
+       32,17,58,73,152,254,0,40,10,62,10,211,
+       66,62,160,211,66,24,8,62,10,211,66,62,
+       128,211,66,62,11,211,66,62,6,211,66,62,
+       6,211,66,58,44,152,211,66,62,16,211,66,
+       62,56,211,66,62,48,211,66,0,0,219,66,
+       230,1,40,4,219,67,24,240,62,14,211,66,
+       62,33,211,66,42,40,152,205,65,143,62,1,
+       211,66,62,248,211,66,237,56,48,246,145,246,
+       8,230,207,237,57,48,62,3,211,66,62,221,
+       211,66,201,62,16,211,66,62,56,211,66,62,
+       48,211,66,0,0,219,66,230,1,40,4,219,
+       67,24,240,62,14,211,66,62,33,211,66,62,
+       1,211,66,62,248,211,66,237,56,48,246,153,
+       230,207,237,57,48,62,3,211,66,62,221,211,
+       66,201,229,213,33,234,149,95,22,0,25,126,
+       254,132,40,4,254,140,32,2,175,119,123,209,
+       225,201,6,8,14,0,31,48,1,12,16,250,
+       121,201,33,4,0,57,94,35,86,33,2,0,
+       57,126,35,102,111,221,229,34,89,152,237,83,
+       91,152,221,33,63,152,205,127,142,58,81,152,
+       50,82,152,58,80,152,135,50,80,152,205,162,
+       140,254,3,56,16,58,81,152,135,60,230,15,
+       50,81,152,175,50,80,152,24,23,58,79,152,
+       205,162,140,254,3,48,13,58,81,152,203,63,
+       50,81,152,62,255,50,79,152,58,81,152,50,
+       82,152,58,79,152,135,50,79,152,62,32,50,
+       83,152,50,84,152,237,56,16,230,17,237,57,
+       16,219,72,62,192,50,93,152,62,93,50,94,
+       152,58,93,152,61,50,93,152,32,9,58,94,
+       152,61,50,94,152,40,44,62,170,237,57,20,
+       175,237,57,21,237,56,16,246,2,237,57,16,
+       219,72,230,1,202,29,141,237,56,20,71,237,
+       56,21,120,254,10,48,237,237,56,16,230,17,
+       237,57,16,243,62,14,211,66,62,65,211,66,
+       251,58,39,152,23,23,60,50,39,152,71,58,
+       82,152,160,230,15,40,22,71,14,10,219,66,
+       230,16,202,186,141,219,72,230,1,202,186,141,
+       13,32,239,16,235,42,89,152,237,91,91,152,
+       205,47,131,48,7,61,202,186,141,195,227,141,
+       221,225,33,0,0,201,221,33,55,152,205,127,
+       142,58,84,152,61,50,84,152,40,19,58,82,
+       152,246,1,50,82,152,58,79,152,246,1,50,
+       79,152,195,29,141,221,225,33,1,0,201,221,
+       33,59,152,205,127,142,58,80,152,246,1,50,
+       80,152,58,82,152,135,246,1,50,82,152,58,
+       83,152,61,50,83,152,194,29,141,221,225,33,
+       2,0,201,221,229,33,0,0,57,17,4,0,
+       25,126,50,44,152,230,128,50,85,152,58,85,
+       152,183,40,6,221,33,88,2,24,4,221,33,
+       150,0,58,44,152,183,40,53,60,40,50,60,
+       40,47,61,61,33,86,152,119,35,119,35,54,
+       129,175,50,48,152,221,43,221,229,225,124,181,
+       40,42,33,86,152,17,3,0,205,189,140,17,
+       232,3,27,123,178,32,251,58,48,152,183,40,
+       224,58,44,152,71,62,7,128,230,127,71,58,
+       85,152,176,50,44,152,24,162,221,225,201,183,
+       221,52,0,192,221,52,1,192,221,52,2,192,
+       221,52,3,192,55,201,245,62,1,211,100,241,
+       201,245,62,1,211,96,241,201,33,2,0,57,
+       126,35,102,111,237,56,48,230,175,237,57,48,
+       62,48,237,57,49,125,237,57,32,124,237,57,
+       33,62,0,237,57,34,62,88,237,57,35,62,
+       0,237,57,36,237,57,37,33,128,2,125,237,
+       57,38,124,237,57,39,237,56,48,246,97,230,
+       207,237,57,48,62,0,237,57,0,62,0,211,
+       96,211,100,201,33,2,0,57,126,35,102,111,
+       237,56,48,230,175,237,57,48,62,12,237,57,
+       49,62,76,237,57,32,62,0,237,57,33,237,
+       57,34,125,237,57,35,124,237,57,36,62,0,
+       237,57,37,33,128,2,125,237,57,38,124,237,
+       57,39,237,56,48,246,97,230,207,237,57,48,
+       62,1,211,96,201,33,2,0,57,126,35,102,
+       111,229,237,56,48,230,87,237,57,48,125,237,
+       57,40,124,237,57,41,62,0,237,57,42,62,
+       67,237,57,43,62,0,237,57,44,58,106,137,
+       254,1,32,5,33,6,0,24,3,33,128,2,
+       125,237,57,46,124,237,57,47,237,56,50,230,
+       252,246,2,237,57,50,225,201,33,4,0,57,
+       94,35,86,33,2,0,57,126,35,102,111,237,
+       56,48,230,87,237,57,48,125,237,57,40,124,
+       237,57,41,62,0,237,57,42,62,67,237,57,
+       43,62,0,237,57,44,123,237,57,46,122,237,
+       57,47,237,56,50,230,244,246,0,237,57,50,
+       237,56,48,246,145,230,207,237,57,48,201,213,
+       237,56,46,95,237,56,47,87,237,56,46,111,
+       237,56,47,103,183,237,82,32,235,33,128,2,
+       183,237,82,209,201,213,237,56,38,95,237,56,
+       39,87,237,56,38,111,237,56,39,103,183,237,
+       82,32,235,33,128,2,183,237,82,209,201,245,
+       197,1,52,0,237,120,230,253,237,121,193,241,
+       201,245,197,1,52,0,237,120,246,2,237,121,
+       193,241,201,33,2,0,57,126,35,102,111,126,
+       35,110,103,201,33,0,0,34,102,152,34,96,
+       152,34,98,152,33,202,154,34,104,152,237,91,
+       104,152,42,226,149,183,237,82,17,0,255,25,
+       34,100,152,203,124,40,6,33,0,125,34,100,
+       152,42,104,152,35,35,35,229,205,120,139,193,
+       201,205,186,149,229,42,40,152,35,35,35,229,
+       205,39,144,193,124,230,3,103,221,117,254,221,
+       116,255,237,91,42,152,35,35,35,183,237,82,
+       32,12,17,5,0,42,42,152,205,171,149,242,
+       169,144,42,40,152,229,205,120,139,193,195,198,
+       149,237,91,42,152,42,98,152,25,34,98,152,
+       19,19,19,42,102,152,25,34,102,152,237,91,
+       100,152,33,158,253,25,237,91,102,152,205,171,
+       149,242,214,144,33,0,0,34,102,152,62,1,
+       50,95,152,205,225,144,195,198,149,58,95,152,
+       183,200,237,91,96,152,42,102,152,205,171,149,
+       242,5,145,237,91,102,152,33,98,2,25,237,
+       91,96,152,205,171,149,250,37,145,237,91,96,
+       152,42,102,152,183,237,82,32,7,42,98,152,
+       125,180,40,13,237,91,102,152,42,96,152,205,
+       171,149,242,58,145,237,91,104,152,42,102,152,
+       25,35,35,35,229,205,120,139,193,175,50,95,
+       152,201,195,107,139,205,206,149,250,255,243,205,
+       225,144,251,58,230,149,183,194,198,149,17,1,
+       0,42,98,152,205,171,149,250,198,149,62,1,
+       50,230,149,237,91,96,152,42,104,152,25,221,
+       117,252,221,116,253,237,91,104,152,42,96,152,
+       25,35,35,35,221,117,254,221,116,255,35,35,
+       35,229,205,39,144,124,230,3,103,35,35,35,
+       221,117,250,221,116,251,235,221,110,252,221,102,
+       253,115,35,114,35,54,4,62,1,211,100,211,
+       84,195,198,149,33,0,0,34,102,152,34,96,
+       152,34,98,152,33,202,154,34,104,152,237,91,
+       104,152,42,226,149,183,237,82,17,0,255,25,
+       34,100,152,33,109,152,54,0,33,107,152,229,
+       205,240,142,193,62,47,50,34,152,62,132,50,
+       49,152,205,241,145,205,61,145,58,39,152,60,
+       50,39,152,24,241,205,206,149,251,255,33,109,
+       152,126,183,202,198,149,110,221,117,251,33,109,
+       152,54,0,221,126,251,254,1,40,28,254,3,
+       40,101,254,4,202,190,147,254,5,202,147,147,
+       254,8,40,87,33,107,152,229,205,240,142,195,
+       198,149,58,201,154,183,32,21,33,111,152,126,
+       50,229,149,205,52,144,33,110,152,110,38,0,
+       229,205,11,142,193,237,91,96,152,42,104,152,
+       25,221,117,254,221,116,255,35,35,54,2,17,
+       2,0,43,43,115,35,114,58,44,152,35,35,
+       119,58,228,149,35,119,62,1,211,100,211,84,
+       62,1,50,201,154,24,169,205,153,142,58,231,
+       149,183,40,250,175,50,231,149,33,110,152,126,
+       254,255,40,91,58,233,149,230,63,183,40,83,
+       94,22,0,33,234,149,25,126,183,40,13,33,
+       110,152,94,33,234,150,25,126,254,3,32,36,
+       205,81,148,125,180,33,110,152,94,22,0,40,
+       17,33,234,149,25,54,0,33,107,152,229,205,
+       240,142,193,195,198,149,33,234,150,25,54,0,
+       33,110,152,94,22,0,33,234,149,25,126,50,
+       49,152,254,132,32,37,62,47,50,34,152,42,
+       107,152,229,33,110,152,229,205,174,140,193,193,
+       125,180,33,110,152,94,22,0,33,234,150,202,
+       117,147,25,52,195,120,147,58,49,152,254,140,
+       32,7,62,1,50,34,152,24,210,62,32,50,
+       106,152,24,19,58,49,152,95,58,106,152,163,
+       183,58,106,152,32,11,203,63,50,106,152,58,
+       106,152,183,32,231,254,2,40,51,254,4,40,
+       38,254,8,40,26,254,16,40,13,254,32,32,
+       158,62,165,50,49,152,62,69,24,190,62,164,
+       50,49,152,62,70,24,181,62,163,50,49,152,
+       175,24,173,62,162,50,49,152,62,1,24,164,
+       62,161,50,49,152,62,3,24,155,25,54,0,
+       221,126,251,254,8,40,7,58,230,149,183,202,
+       32,146,33,107,152,229,205,240,142,193,211,84,
+       195,198,149,237,91,96,152,42,104,152,25,221,
+       117,254,221,116,255,35,35,54,6,17,2,0,
+       43,43,115,35,114,58,228,149,35,35,119,58,
+       233,149,35,119,205,146,142,195,32,146,237,91,
+       96,152,42,104,152,25,229,205,160,142,193,58,
+       231,149,183,40,250,175,50,231,149,243,237,91,
+       96,152,42,104,152,25,221,117,254,221,116,255,
+       78,35,70,221,113,252,221,112,253,89,80,42,
+       98,152,183,237,82,34,98,152,203,124,40,19,
+       33,0,0,34,98,152,34,102,152,34,96,152,
+       62,1,50,95,152,24,40,221,94,252,221,86,
+       253,19,19,19,42,96,152,25,34,96,152,237,
+       91,100,152,33,158,253,25,237,91,96,152,205,
+       171,149,242,55,148,33,0,0,34,96,152,175,
+       50,230,149,251,195,32,146,245,62,1,50,231,
+       149,62,16,237,57,0,211,80,241,251,237,77,
+       201,205,186,149,229,229,33,0,0,34,37,152,
+       33,110,152,126,50,234,151,58,44,152,33,235,
+       151,119,221,54,253,0,221,54,254,0,195,230,
+       148,33,236,151,54,175,33,3,0,229,33,234,
+       151,229,205,174,140,193,193,33,236,151,126,254,
+       255,40,74,33,245,151,110,221,117,255,33,249,
+       151,126,221,166,255,221,119,255,33,253,151,126,
+       221,166,255,221,119,255,58,232,149,95,221,126,
+       255,163,221,119,255,183,40,15,230,191,33,110,
+       152,94,22,0,33,234,149,25,119,24,12,33,
+       110,152,94,22,0,33,234,149,25,54,132,33,
+       0,0,195,198,149,221,110,253,221,102,254,35,
+       221,117,253,221,116,254,17,32,0,221,110,253,
+       221,102,254,205,171,149,250,117,148,58,233,149,
+       203,87,40,84,33,1,0,34,37,152,221,54,
+       253,0,221,54,254,0,24,53,33,236,151,54,
+       175,33,3,0,229,33,234,151,229,205,174,140,
+       193,193,33,236,151,126,254,255,40,14,33,110,
+       152,94,22,0,33,234,149,25,54,140,24,159,
+       221,110,253,221,102,254,35,221,117,253,221,116,
+       254,17,32,0,221,110,253,221,102,254,205,171,
+       149,250,12,149,33,2,0,34,37,152,221,54,
+       253,0,221,54,254,0,24,54,33,236,151,54,
+       175,33,3,0,229,33,234,151,229,205,174,140,
+       193,193,33,236,151,126,254,255,40,15,33,110,
+       152,94,22,0,33,234,149,25,54,132,195,211,
+       148,221,110,253,221,102,254,35,221,117,253,221,
+       116,254,17,32,0,221,110,253,221,102,254,205,
+       171,149,250,96,149,33,1,0,195,198,149,124,
+       170,250,179,149,237,82,201,124,230,128,237,82,
+       60,201,225,253,229,221,229,221,33,0,0,221,
+       57,233,221,249,221,225,253,225,201,233,225,253,
+       229,221,229,221,33,0,0,221,57,94,35,86,
+       35,235,57,249,235,233,0,0,0,0,0,0,
+       62,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       175,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,133,1,0,0,0,63,
+       255,255,255,255,0,0,0,63,0,0,0,0,
+       0,0,0,0,0,0,0,24,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0
+       } ;
+
+#endif
diff --git a/drivers/net/appletalk/cops_ltdrv.h b/drivers/net/appletalk/cops_ltdrv.h
new file mode 100644 (file)
index 0000000..e3e850c
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *     The firmware this driver downloads into the Localtalk card is a
+ *     separate program and is not GPL'd source code, even though the Linux
+ *     side driver and the routine that loads this data into the card are.
+ *     
+ *     It is taken from the COPS SDK and is under the following license
+ *
+ *     This material is licensed to you strictly for use in conjunction with
+ *     the use of COPS LocalTalk adapters.
+ *     There is no charge for this SDK. And no waranty express or implied
+ *     about its fitness for any purpose. However, we will cheerefully
+ *     refund every penny you paid for this SDK...
+ *     Regards,
+ *
+ *     Thomas F. Divine
+ *     Chief Scientist
+ */
+
+
+/*      cops_ltdrv.h: LocalTalk driver firmware dump for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_COPS_TANGENT
+
+unsigned char ltdrv_code[] = {
+       58,3,0,50,148,10,33,143,15,62,85,119,
+       190,32,9,62,170,119,190,32,3,35,24,241,
+       34,146,10,249,17,150,10,33,143,15,183,237,
+       82,77,68,11,107,98,19,54,0,237,176,62,
+       16,237,57,51,62,0,237,57,50,237,57,54,
+       62,12,237,57,49,62,195,33,39,2,50,56,
+       0,34,57,0,237,86,205,30,2,251,205,60,
+       10,24,169,67,111,112,121,114,105,103,104,116,
+       32,40,99,41,32,49,57,56,56,45,49,57,
+       57,50,44,32,80,114,105,110,116,105,110,103,
+       32,67,111,109,109,117,110,105,99,97,116,105,
+       111,110,115,32,65,115,115,111,99,105,97,116,
+       101,115,44,32,73,110,99,46,65,108,108,32,
+       114,105,103,104,116,115,32,114,101,115,101,114,
+       118,101,100,46,32,32,4,4,22,40,255,60,
+       4,96,10,224,6,0,7,126,2,64,11,246,
+       12,6,13,0,14,193,15,0,5,96,3,192,
+       1,0,9,8,62,3,211,82,62,192,211,82,
+       201,62,3,211,82,62,213,211,82,201,62,5,
+       211,82,62,224,211,82,201,62,5,211,82,62,
+       224,211,82,201,62,5,211,82,62,96,211,82,
+       201,6,28,33,180,1,14,82,237,163,194,4,
+       2,33,39,2,34,64,0,58,3,0,230,1,
+       192,62,11,237,121,62,118,237,121,201,33,182,
+       10,54,132,205,253,1,201,245,197,213,229,42,
+       150,10,14,83,17,98,2,67,20,237,162,58,
+       179,1,95,219,82,230,1,32,6,29,32,247,
+       195,17,3,62,1,211,82,219,82,95,230,160,
+       32,10,237,162,32,225,21,32,222,195,15,3,
+       237,162,123,230,96,194,21,3,62,48,211,82,
+       62,1,211,82,175,211,82,237,91,150,10,43,
+       55,237,82,218,19,3,34,152,10,98,107,58,
+       154,10,190,32,81,62,1,50,158,10,35,35,
+       62,132,190,32,44,54,133,43,70,58,154,10,
+       119,43,112,17,3,0,205,137,3,62,16,211,
+       82,62,56,211,82,205,217,1,42,150,10,14,
+       83,17,98,2,67,20,58,178,1,95,195,59,
+       2,62,129,190,194,227,2,54,130,43,70,58,
+       154,10,119,43,112,17,3,0,205,137,3,195,
+       254,2,35,35,126,254,132,194,227,2,205,61,
+       3,24,20,62,128,166,194,222,2,221,229,221,
+       33,175,10,205,93,6,205,144,7,221,225,225,
+       209,193,241,251,237,77,221,229,221,33,159,10,
+       205,93,6,221,225,205,61,3,195,247,2,24,
+       237,24,235,24,233,230,64,40,2,24,227,24,
+       225,175,50,179,10,205,208,1,201,197,33,4,
+       0,57,126,35,102,111,205,51,3,193,201,62,
+       1,50,179,10,34,150,10,54,0,58,179,10,
+       183,200,62,14,211,82,62,193,211,82,62,10,
+       211,82,62,224,211,82,62,6,211,82,58,154,
+       10,211,82,62,16,211,82,62,56,211,82,62,
+       48,211,82,219,82,230,1,40,4,219,83,24,
+       242,62,14,211,82,62,33,211,82,62,1,211,
+       82,62,9,211,82,62,32,211,82,205,217,1,
+       201,14,83,205,208,1,24,23,14,83,205,208,
+       1,205,226,1,58,174,1,61,32,253,205,244,
+       1,58,174,1,61,32,253,205,226,1,58,175,
+       1,61,32,253,62,5,211,82,62,233,211,82,
+       62,128,211,82,58,176,1,61,32,253,237,163,
+       27,62,192,211,82,219,82,230,4,40,250,237,
+       163,27,122,179,32,243,219,82,230,4,40,250,
+       58,178,1,71,219,82,230,4,40,3,5,32,
+       247,219,82,230,4,40,250,205,235,1,58,177,
+       1,61,32,253,205,244,1,201,229,213,35,35,
+       126,230,128,194,145,4,43,58,154,10,119,43,
+       70,33,181,10,119,43,112,17,3,0,243,62,
+       10,211,82,219,82,230,128,202,41,4,209,225,
+       62,1,55,251,201,205,144,3,58,180,10,254,
+       255,202,127,4,205,217,1,58,178,1,71,219,
+       82,230,1,32,6,5,32,247,195,173,4,219,
+       83,71,58,154,10,184,194,173,4,58,178,1,
+       71,219,82,230,1,32,6,5,32,247,195,173,
+       4,219,83,58,178,1,71,219,82,230,1,32,
+       6,5,32,247,195,173,4,219,83,254,133,194,
+       173,4,58,179,1,24,4,58,179,1,135,61,
+       32,253,209,225,205,137,3,205,61,3,183,251,
+       201,209,225,243,62,10,211,82,219,82,230,128,
+       202,164,4,62,1,55,251,201,205,144,3,205,
+       61,3,183,251,201,209,225,62,2,55,251,201,
+       243,62,14,211,82,62,33,211,82,251,201,33,
+       4,0,57,94,35,86,33,2,0,57,126,35,
+       102,111,221,229,34,193,10,237,83,195,10,221,
+       33,171,10,205,93,6,58,185,10,50,186,10,
+       58,184,10,135,50,184,10,205,112,6,254,3,
+       56,16,58,185,10,135,60,230,15,50,185,10,
+       175,50,184,10,24,23,58,183,10,205,112,6,
+       254,3,48,13,58,185,10,203,63,50,185,10,
+       62,255,50,183,10,58,185,10,50,186,10,58,
+       183,10,135,50,183,10,62,32,50,187,10,50,
+       188,10,6,255,219,82,230,16,32,3,5,32,
+       247,205,180,4,6,40,219,82,230,16,40,3,
+       5,32,247,62,10,211,82,219,82,230,128,194,
+       46,5,219,82,230,16,40,214,237,95,71,58,
+       186,10,160,230,15,40,32,71,14,10,62,10,
+       211,82,219,82,230,128,202,119,5,205,180,4,
+       195,156,5,219,82,230,16,202,156,5,13,32,
+       229,16,225,42,193,10,237,91,195,10,205,252,
+       3,48,7,61,202,156,5,195,197,5,221,225,
+       33,0,0,201,221,33,163,10,205,93,6,58,
+       188,10,61,50,188,10,40,19,58,186,10,246,
+       1,50,186,10,58,183,10,246,1,50,183,10,
+       195,46,5,221,225,33,1,0,201,221,33,167,
+       10,205,93,6,58,184,10,246,1,50,184,10,
+       58,186,10,135,246,1,50,186,10,58,187,10,
+       61,50,187,10,194,46,5,221,225,33,2,0,
+       201,221,229,33,0,0,57,17,4,0,25,126,
+       50,154,10,230,128,50,189,10,58,189,10,183,
+       40,6,221,33,88,2,24,4,221,33,150,0,
+       58,154,10,183,40,49,60,40,46,61,33,190,
+       10,119,35,119,35,54,129,175,50,158,10,221,
+       43,221,229,225,124,181,40,42,33,190,10,17,
+       3,0,205,206,4,17,232,3,27,123,178,32,
+       251,58,158,10,183,40,224,58,154,10,71,62,
+       7,128,230,127,71,58,189,10,176,50,154,10,
+       24,166,221,225,201,183,221,52,0,192,221,52,
+       1,192,221,52,2,192,221,52,3,192,55,201,
+       6,8,14,0,31,48,1,12,16,250,121,201,
+       33,2,0,57,94,35,86,35,78,35,70,35,
+       126,35,102,105,79,120,68,103,237,176,201,33,
+       2,0,57,126,35,102,111,62,17,237,57,48,
+       125,237,57,40,124,237,57,41,62,0,237,57,
+       42,62,64,237,57,43,62,0,237,57,44,33,
+       128,2,125,237,57,46,124,237,57,47,62,145,
+       237,57,48,211,68,58,149,10,211,66,201,33,
+       2,0,57,126,35,102,111,62,33,237,57,48,
+       62,64,237,57,32,62,0,237,57,33,237,57,
+       34,125,237,57,35,124,237,57,36,62,0,237,
+       57,37,33,128,2,125,237,57,38,124,237,57,
+       39,62,97,237,57,48,211,67,58,149,10,211,
+       66,201,237,56,46,95,237,56,47,87,237,56,
+       46,111,237,56,47,103,183,237,82,32,235,33,
+       128,2,183,237,82,201,237,56,38,95,237,56,
+       39,87,237,56,38,111,237,56,39,103,183,237,
+       82,32,235,33,128,2,183,237,82,201,205,106,
+       10,221,110,6,221,102,7,126,35,110,103,195,
+       118,10,205,106,10,33,0,0,34,205,10,34,
+       198,10,34,200,10,33,143,15,34,207,10,237,
+       91,207,10,42,146,10,183,237,82,17,0,255,
+       25,34,203,10,203,124,40,6,33,0,125,34,
+       203,10,42,207,10,229,205,37,3,195,118,10,
+       205,106,10,229,42,150,10,35,35,35,229,205,
+       70,7,193,124,230,3,103,221,117,254,221,116,
+       255,237,91,152,10,35,35,35,183,237,82,32,
+       12,17,5,0,42,152,10,205,91,10,242,203,
+       7,42,150,10,229,205,37,3,195,118,10,237,
+       91,152,10,42,200,10,25,34,200,10,42,205,
+       10,25,34,205,10,237,91,203,10,33,158,253,
+       25,237,91,205,10,205,91,10,242,245,7,33,
+       0,0,34,205,10,62,1,50,197,10,205,5,
+       8,33,0,0,57,249,195,118,10,205,106,10,
+       58,197,10,183,202,118,10,237,91,198,10,42,
+       205,10,205,91,10,242,46,8,237,91,205,10,
+       33,98,2,25,237,91,198,10,205,91,10,250,
+       78,8,237,91,198,10,42,205,10,183,237,82,
+       32,7,42,200,10,125,180,40,13,237,91,205,
+       10,42,198,10,205,91,10,242,97,8,237,91,
+       207,10,42,205,10,25,229,205,37,3,175,50,
+       197,10,195,118,10,205,29,3,33,0,0,57,
+       249,195,118,10,205,106,10,58,202,10,183,40,
+       22,205,14,7,237,91,209,10,19,19,19,205,
+       91,10,242,139,8,33,1,0,195,118,10,33,
+       0,0,195,118,10,205,126,10,252,255,205,108,
+       8,125,180,194,118,10,237,91,200,10,33,0,
+       0,205,91,10,242,118,10,237,91,207,10,42,
+       198,10,25,221,117,254,221,116,255,35,35,35,
+       229,205,70,7,193,124,230,3,103,35,35,35,
+       221,117,252,221,116,253,229,221,110,254,221,102,
+       255,229,33,212,10,229,205,124,6,193,193,221,
+       110,252,221,102,253,34,209,10,33,211,10,54,
+       4,33,209,10,227,205,147,6,193,62,1,50,
+       202,10,243,221,94,252,221,86,253,42,200,10,
+       183,237,82,34,200,10,203,124,40,17,33,0,
+       0,34,200,10,34,205,10,34,198,10,50,197,
+       10,24,37,221,94,252,221,86,253,42,198,10,
+       25,34,198,10,237,91,203,10,33,158,253,25,
+       237,91,198,10,205,91,10,242,68,9,33,0,
+       0,34,198,10,205,5,8,33,0,0,57,249,
+       251,195,118,10,205,106,10,33,49,13,126,183,
+       40,16,205,42,7,237,91,47,13,19,19,19,
+       205,91,10,242,117,9,58,142,15,198,1,50,
+       142,15,195,118,10,33,49,13,126,254,1,40,
+       25,254,3,202,7,10,254,5,202,21,10,33,
+       49,13,54,0,33,47,13,229,205,207,6,195,
+       118,10,58,141,15,183,32,72,33,51,13,126,
+       50,149,10,205,86,7,33,50,13,126,230,127,
+       183,32,40,58,142,15,230,127,50,142,15,183,
+       32,5,198,1,50,142,15,33,50,13,126,111,
+       23,159,103,203,125,58,142,15,40,5,198,128,
+       50,142,15,33,50,13,119,33,50,13,126,111,
+       23,159,103,229,205,237,5,193,33,211,10,54,
+       2,33,2,0,34,209,10,58,154,10,33,212,
+       10,119,58,148,10,33,213,10,119,33,209,10,
+       229,205,147,6,193,24,128,42,47,13,229,33,
+       50,13,229,205,191,4,193,24,239,33,211,10,
+       54,6,33,3,0,34,209,10,58,154,10,33,
+       212,10,119,58,148,10,33,213,10,119,33,214,
+       10,54,5,33,209,10,229,205,147,6,24,200,
+       205,106,10,33,49,13,54,0,33,47,13,229,
+       205,207,6,33,209,10,227,205,147,6,193,205,
+       80,9,205,145,8,24,248,124,170,250,99,10,
+       237,82,201,124,230,128,237,82,60,201,225,253,
+       229,221,229,221,33,0,0,221,57,233,221,249,
+       221,225,253,225,201,233,225,253,229,221,229,221,
+       33,0,0,221,57,94,35,86,35,235,57,249,
+       235,233,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0
+       } ;
+
+#endif
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
new file mode 100644 (file)
index 0000000..a089ed9
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *     ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
+ *              Appletalk-IP to IP Decapsulation driver for Linux
+ *
+ *     Authors:
+ *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *     - DDP-IP Decap by: Jay Schulist <jschlst@turbolinux.com>
+ *
+ *     Derived from:
+ *     - Almost all code already existed in net/appletalk/ddp.c I just
+ *       moved/reorginized it into a driver file. Original IP-over-DDP code
+ *       was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *      - skeleton.c: A network driver outline for linux.
+ *        Written 1993-94 by Donald Becker.
+ *     - dummy.c: A dummy net driver. By Nick Holloway.
+ *     - MacGate: A user space Daemon for Appletalk-IP Decap for
+ *       Linux by Jay Schulist <jschlst@turbolinux.com>
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU Public License, incorporated herein by reference.
+ */
+
+static const char *version = 
+       "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/atalk.h>
+#include <linux/ip.h>
+#include <net/route.h>
+#include <linux/inet.h>
+
+#include "ipddp.h"             /* Our stuff */
+
+static struct ipddp_route *ipddp_route_list = NULL;
+
+#ifdef CONFIG_IPDDP_ENCAP
+static int ipddp_mode = IPDDP_ENCAP;
+#else
+static int ipddp_mode = IPDDP_DECAP;
+#endif
+
+/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
+#ifndef IPDDP_DEBUG
+#define IPDDP_DEBUG 1
+#endif
+static unsigned int ipddp_debug = IPDDP_DEBUG;
+
+/* Index to functions, as function prototypes. */
+static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
+static int ipddp_create(struct ipddp_route *new_rt);
+static int ipddp_delete(struct ipddp_route *rt);
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
+static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+
+static int ipddp_open(struct net_device *dev)
+{
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
+
+        return 0;
+}
+
+static int ipddp_close(struct net_device *dev)
+{
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
+
+        return 0;
+}
+
+int ipddp_init(struct net_device *dev)
+{
+       static unsigned version_printed = 0;
+
+       if (ipddp_debug && version_printed++ == 0)
+                printk("%s", version);
+
+       /* Let the user now what mode we are in */
+       if(ipddp_mode == IPDDP_ENCAP)
+               printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
+                       dev->name);
+       if(ipddp_mode == IPDDP_DECAP)
+               printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@turbolinux.com>\n", 
+                       dev->name);
+
+       /* Fill in the device structure with ethernet-generic values. */
+        ether_setup(dev);
+
+       /* Initalize the device structure. */
+        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->open           = ipddp_open;
+        dev->stop          = ipddp_close;
+        dev->get_stats      = ipddp_get_stats;
+        dev->do_ioctl       = ipddp_ioctl;
+
+        dev->type = ARPHRD_IPDDP;              /* IP over DDP tunnel */
+        dev->mtu = 585;
+        dev->flags |= IFF_NOARP;
+
+        /*
+         *      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;
+
+        return 0;
+}
+
+/*
+ * Get the current statistics. This may be called with the card open or closed.
+ */
+static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
+{
+        return (struct net_device_stats *)dev->priv;
+}
+
+/*
+ * Transmit LLAP/ELAP frame using aarp_send_ddp.
+ */
+static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
+        struct ddpehdr *ddp;
+        struct ipddp_route *rt;
+        struct at_addr *our_addr;
+
+       /*
+         * Find appropriate route to use, based only on IP number.
+         */
+        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
+        {
+                if(rt->ip == paddr)
+                        break;
+        }
+        if(rt == NULL)
+                return 0;
+
+        our_addr = atalk_find_dev_addr(rt->dev);
+
+       if(ipddp_mode == IPDDP_DECAP)
+               /* 
+                * Pull off the excess room that should not be there.
+                * This is due to a hard-header problem. This is the
+                * quick fix for now though, till it breaks.
+                */
+               skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
+
+       /* Create the Extended DDP header */
+       ddp = (struct ddpehdr *)skb->data;
+        ddp->deh_len = skb->len;
+        ddp->deh_hops = 1;
+        ddp->deh_pad = 0;
+        ddp->deh_sum = 0;
+
+       /*
+         * For Localtalk we need aarp_send_ddp to strip the
+         * long DDP header and place a shot DDP header on it.
+         */
+        if(rt->dev->type == ARPHRD_LOCALTLK)
+        {
+                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
+                ddp->deh_snet  = 0;
+        }
+        else
+        {
+                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 */
+        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));        /* fix up length field */
+
+        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
+
+       ((struct net_device_stats *) dev->priv)->tx_packets++;
+        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
+
+        if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
+                dev_kfree_skb(skb);
+
+        return 0;
+}
+
+/*
+ * Create a routing entry. We first verify that the
+ * record does not already exist. If it does we return -EEXIST
+ */
+static int ipddp_create(struct ipddp_route *new_rt)
+{
+        struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
+       struct ipddp_route *test;
+
+        if(rt == NULL)
+                return -ENOMEM;
+
+        rt->ip = new_rt->ip;
+        rt->at = new_rt->at;
+        rt->next = NULL;
+        rt->dev = atrtr_get_dev(&rt->at);
+        if(rt->dev == NULL)
+                return (-ENETUNREACH);
+
+       test = ipddp_find_route(rt);
+       if(test != NULL)
+               return (-EEXIST);
+       
+        rt->next = ipddp_route_list;
+        ipddp_route_list = rt;
+
+        return 0;
+}
+
+/*
+ * Delete a route, we only delete a FULL match.
+ * If route does not exist we return -ENOENT.
+ */
+static int ipddp_delete(struct ipddp_route *rt)
+{
+        struct ipddp_route **r = &ipddp_route_list;
+        struct ipddp_route *tmp;
+
+        while((tmp = *r) != NULL)
+        {
+                if(tmp->ip == rt->ip
+                        && tmp->at.s_net == rt->at.s_net
+                        && tmp->at.s_node == rt->at.s_node)
+                {
+                        *r = tmp->next;
+                        kfree_s(tmp, sizeof(struct ipddp_route));
+                        return 0;
+                }
+                r = &tmp->next;
+        }
+
+        return (-ENOENT);
+}
+
+/*
+ * Find a routing entry, we only return a FULL match
+ */
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
+{
+        struct ipddp_route *f;
+
+        for(f = ipddp_route_list; f != NULL; f = f->next)
+        {
+                if(f->ip == rt->ip
+                        && f->at.s_net == rt->at.s_net
+                        && f->at.s_node == rt->at.s_node)
+                        return (f);
+        }
+
+        return (NULL);
+}
+
+static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
+
+        if(!capable(CAP_NET_ADMIN))
+                return -EPERM;
+
+        switch(cmd)
+        {
+               case SIOCADDIPDDPRT:
+                        return (ipddp_create(rt));
+
+                case SIOCFINDIPDDPRT:
+                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
+                                return -EFAULT;
+                        return 0;
+
+                case SIOCDELIPDDPRT:
+                        return (ipddp_delete(rt));
+
+                default:
+                        return -EINVAL;
+        }
+}
+
+#ifdef MODULE  /* Module specific functions for ipddp.c */
+
+static struct net_device dev_ipddp=
+{
+        "ipddp0\0   ",
+                0, 0, 0, 0,
+                0x0, 0,
+                0, 0, 0, NULL, ipddp_init
+};
+
+MODULE_PARM(ipddp_mode, "i");
+
+int init_module(void)
+{
+       int err;
+
+       err=dev_alloc_name(&dev_ipddp, "ipddp%d");
+        if(err < 0)
+                return err;
+
+       if(register_netdev(&dev_ipddp) != 0)
+                return -EIO;
+
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       unregister_netdev(&dev_ipddp);
+        kfree(dev_ipddp.priv);
+       dev_ipddp.priv = NULL;
+}
+
+#endif /* MODULE */
diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h
new file mode 100644 (file)
index 0000000..0729a4d
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *     ipddp.h: Header for IP-over-DDP driver for Linux.
+ */
+
+#ifndef __LINUX_IPDDP_H
+#define __LINUX_IPDDP_H
+
+#ifdef __KERNEL__
+
+#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
+#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
+#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
+
+struct ipddp_route
+{
+        struct net_device *dev;             /* Carrier device */
+        __u32 ip;                       /* IP address */
+        struct at_addr at;              /* Gateway appletalk address */
+        int flags;
+        struct ipddp_route *next;
+};
+
+#define IPDDP_ENCAP    1
+#define IPDDP_DECAP    2
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_IPDDP_H */
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
new file mode 100644 (file)
index 0000000..2728d63
--- /dev/null
@@ -0,0 +1,1367 @@
+/***    ltpc.c -- a driver for the LocalTalk PC card.
+ *
+ *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *      This is ALPHA code at best.  It may not work for you.  It may
+ *      damage your equipment.  It may damage your relations with other
+ *      users of your network.  Use it at your own risk!
+ *
+ *      Based in part on:
+ *      skeleton.c      by Donald Becker
+ *      dummy.c         by Nick Holloway and Alan Cox
+ *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
+ *      the netatalk source code (UMICH)
+ *      lots of work on the card...
+ *
+ *      I do not have access to the (proprietary) SDK that goes with the card.
+ *      If you do, I don't want to know about it, and you can probably write
+ *      a better driver yourself anyway.  This does mean that the pieces that
+ *      talk to the card are guesswork on my part, so use at your own risk!
+ *
+ *      This is my first try at writing Linux networking code, and is also
+ *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
+ *      welcome suggestions)
+ *
+ *      This is a loadable kernel module which seems to work at my site
+ *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
+ *      the kernel support from 1.3.3b2 including patches routing.patch
+ *      and ddp.disappears.from.chooser.  In order to run it, you will need
+ *      to patch ddp.c and aarp.c in the kernel, but only a little...
+ *
+ *      I'm fairly confident that while this is arguably badly written, the
+ *      problems that people experience will be "higher level", that is, with
+ *      complications in the netatalk code.  The driver itself doesn't do
+ *      anything terribly complicated -- it pretends to be an ether device
+ *      as far as netatalk is concerned, strips the DDP data out of the ether
+ *      frame and builds a LLAP packet to send out the card.  In the other
+ *      direction, it receives LLAP frames from the card and builds a fake
+ *      ether packet that it then tosses up to the networking code.  You can
+ *      argue (correctly) that this is an ugly way to do things, but it
+ *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
+ *
+ *      The card will do a lot more than is used here -- I *think* it has the
+ *      layers up through ATP.  Even if you knew how that part works (which I
+ *      don't) it would be a big job to carve up the kernel ddp code to insert
+ *      things at a higher level, and probably a bad idea...
+ *
+ *      There are a number of other cards that do LocalTalk on the PC.  If
+ *      nobody finds any insurmountable (at the netatalk level) problems
+ *      here, this driver should encourage people to put some work into the
+ *      other cards (some of which I gather are still commercially available)
+ *      and also to put hooks for LocalTalk into the official ddp code.
+ *
+ *      I welcome comments and suggestions.  This is my first try at Linux
+ *      networking stuff, and there are probably lots of things that I did
+ *      suboptimally.  
+ *
+ ***/
+
+/***
+ *
+ * $Log: ltpc.c,v $
+ * Revision 1.1.2.1  2000/03/01 05:35:07  jgarzik
+ * at and tr cleanup
+ *
+ * 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
+ *
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+   and to probe for things in the standard order of i/o, irq, dma.  This
+   removes the "reset the reset" hack, because I couldn't figure out an
+   easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+   line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+   other localtalk driver, and to clear up the inconsistency between the
+   module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+   codes and the register offsets, but I'm still not sure exactly what their
+   semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+   I'm responsible for that...
+
+ *
+ * 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
+
+static int io=0;
+static int irq=0;
+static int dma=0;
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include <linux/atalk.h>
+
+/* our stuff */
+#include "ltpc.h"
+
+/* function prototypes */
+static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
+       void *dbuf, int dbuflen);
+static int sendup_buffer (struct net_device *dev);
+
+/* Dma Memory related stuff, cribbed directly from 3c505.c */
+
+static unsigned long dma_mem_alloc(int size)
+{
+        int order = get_order(size);
+
+        return __get_dma_pages(GFP_KERNEL, order);
+}
+
+/* DMA data buffer, DMA command buffer */
+static unsigned char *ltdmabuf;
+static unsigned char *ltdmacbuf;
+
+/* private struct, holds our appletalk address */
+
+struct ltpc_private
+{
+       struct net_device_stats stats;
+       struct at_addr my_addr;
+};
+
+/* transmit queue element struct */
+
+struct xmitQel {
+       struct xmitQel *next;
+       /* command buffer */
+       unsigned char *cbuf;
+       short cbuflen;
+       /* data buffer */
+       unsigned char *dbuf;
+       short dbuflen;
+       unsigned char QWrite;   /* read or write data */
+       unsigned char mailbox;
+};
+
+/* the transmit queue itself */
+
+static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
+
+static void enQ(struct xmitQel *qel)
+{
+       unsigned long flags;
+       qel->next = NULL;
+       save_flags(flags);
+       cli();
+       if (xmQtl) {
+               xmQtl->next = qel;
+       } else {
+               xmQhd = qel;
+       }
+       xmQtl = qel;
+       restore_flags(flags);
+
+       if (debug&DEBUG_LOWER)
+               printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
+}
+
+static struct xmitQel *deQ(void)
+{
+       unsigned long flags;
+       int i;
+       struct xmitQel *qel=NULL;
+       save_flags(flags);
+       cli();
+       if (xmQhd) {
+               qel = xmQhd;
+               xmQhd = qel->next;
+               if(!xmQhd) xmQtl = NULL;
+       }
+       restore_flags(flags);
+
+       if ((debug&DEBUG_LOWER) && qel) {
+               int n;
+               printk("ltpc: dequeued command ");
+               n = qel->cbuflen;
+               if (n>100) n=100;
+               for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
+               printk("\n");
+       }
+
+       return qel;
+}
+
+/* and... the queue elements we'll be using */
+static struct xmitQel qels[16];
+
+/* and their corresponding mailboxes */
+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 net_device *dev, int c)
+{
+       /* returns true if it stayed c */
+       /* this uses base+6, but it's ok */
+       int i;
+       int timeout;
+
+       /* twenty second or so total */
+
+       for(i=0;i<20000;i++) {
+               if ( c != inb_p(dev->base_addr+6) ) return 0;
+               for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
+       }
+       return 1; /* timed out */
+}
+
+/* get the first free mailbox */
+
+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;
+}
+
+/* read a command from the card */
+static void handlefc(struct net_device *dev)
+{
+       /* called *only* from idle, non-reentrant */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+
+       flags=claim_dma_lock();
+       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);
+       release_dma_lock(flags);
+
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
+}
+
+/* read data from the card */
+static void handlefd(struct net_device *dev)
+{
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+       flags=claim_dma_lock();
+       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);
+       release_dma_lock(flags);
+
+       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 net_device *dev)
+{
+       /* called *only* from idle, non-reentrant */
+       /* on entry, 0xfb and ltdmabuf holds data */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+       
+       flags=claim_dma_lock();
+       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);
+       release_dma_lock(flags);
+       
+       inb_p(base+3);
+       inb_p(base+2);
+
+       if ( wait_timeout(dev,0xfb) ) {
+               flags=claim_dma_lock();
+               printk("timed out in handlewrite, dma res %d\n",
+                       get_dma_residue(dev->dma) );
+               release_dma_lock(flags);
+       }
+}
+
+static void handleread(struct net_device *dev)
+{
+       /* on entry, 0xfb */
+       /* on exit, ltdmabuf holds data */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+       
+       flags=claim_dma_lock();
+       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);
+       release_dma_lock(flags);
+
+       inb_p(base+3);
+       inb_p(base+2);
+       if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
+}
+
+static void handlecommand(struct net_device *dev)
+{
+       /* on entry, 0xfa and ltdmacbuf holds command */
+       int dma = dev->dma;
+       int base = dev->base_addr;
+       unsigned long flags;
+
+       flags=claim_dma_lock();
+       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);
+       release_dma_lock(flags);
+       inb_p(base+3);
+       inb_p(base+2);
+       if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
+} 
+
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,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 net_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 base = dev->base_addr;
+
+       save_flags(flags);
+       cli();
+       if(QInIdle) {
+               restore_flags(flags);
+               return;
+       }
+       QInIdle = 1;
+
+
+       restore_flags(flags);
+
+       /* this tri-states the IRQ line */
+       (void) inb_p(base+6);
+
+       oops = 100;
+
+loop:
+       if (0>oops--) { 
+               printk("idle: looped too many times\n");
+               goto done;
+       }
+
+       state = inb_p(base+6);
+       if (state != inb_p(base+6)) goto loop;
+
+       switch(state) {
+               case 0xfc:
+                       /* incoming command */
+                       if (debug&DEBUG_LOWER) printk("idle: fc\n");
+                       handlefc(dev); 
+                       break;
+               case 0xfd:
+                       /* incoming data */
+                       if(debug&DEBUG_LOWER) printk("idle: fd\n");
+                       handlefd(dev); 
+                       break;
+               case 0xf9:
+                       /* result ready */
+                       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:
+                       /* waiting for command */
+                       if(debug&DEBUG_LOWER) printk("idle: fa\n");
+                       if (xmQhd) {
+                               q=deQ();
+                               memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
+                               ltdmacbuf[1] = q->mailbox;
+                               if (debug>1) { 
+                                       int n;
+                                       printk("ltpc: sent command     ");
+                                       n = q->cbuflen;
+                                       if (n>100) n=100;
+                                       for(i=0;i<n;i++)
+                                               printk("%02x ",ltdmacbuf[i]);
+                                       printk("\n");
+                               }
+                               handlecommand(dev);
+                                       if(0xfa==inb_p(base+6)) {
+                                               /* we timed out, so return */
+                                               goto done;
+                                       } 
+                       } else {
+                               /* we don't seem to have a command */
+                               if (!mboxinuse[0]) {
+                                       mboxinuse[0] = 1;
+                                       qels[0].cbuf = rescbuf;
+                                       qels[0].cbuflen = 2;
+                                       qels[0].dbuf = resdbuf;
+                                       qels[0].dbuflen = 2;
+                                       qels[0].QWrite = 0;
+                                       qels[0].mailbox = 0;
+                                       enQ(&qels[0]);
+                               } else {
+                                       printk("trouble: response command already queued\n");
+                                       goto done;
+                               }
+                       } 
+                       break;
+               case 0Xfb:
+                       /* data transfer ready */
+                       if(debug&DEBUG_LOWER) printk("idle: fb\n");
+                       if(q->QWrite) {
+                               memcpy(ltdmabuf,q->dbuf,q->dbuflen);
+                               handlewrite(dev);
+                       } else {
+                               handleread(dev);
+                               /* non-zero mailbox numbers are for
+                                  commmands, 0 is for GETRESULT
+                                  requests */
+                               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 read takes it out of tri-state (but still high) */
+       /* the second resets it */
+       /* note that after this point, any read of base+6 will
+          trigger an interrupt */
+
+       if (dev->irq) {
+               inb_p(base+7);
+               inb_p(base+7);
+       }
+       return;
+}
+
+
+static int do_write(struct net_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 net_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 net_device *dev);
+static struct net_device_stats *ltpc_get_stats(struct net_device *dev);
+
+static int ltpc_open(struct net_device *dev)
+{
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+       return 0;
+}
+
+static int ltpc_close(struct net_device *dev)
+{
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+       return 0;
+}
+
+static int read_30 ( struct net_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 net_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);
+}
+
+/* LLAP to DDP translation */
+
+static int sendup_buffer (struct net_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 net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
+       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;
+
+       stats->rx_packets++;
+       stats->rx_bytes+=skb->len;
+
+       /* toss it onwards */
+       netif_rx(skb);
+       return 0;
+}
+
+/* the handler for the board interrupt */
+static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+{
+       struct net_device *dev = dev_id;
+
+       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 net_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 ltpc_private *)dev->priv)->my_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 net_device *dev)
+{
+       /* This needs to be present to keep netatalk happy. */
+       /* Actually netatalk needs fixing! */
+}
+
+static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, 
+       unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+       if(debug&DEBUG_VERBOSE)
+               printk("ltpc_hard_header called for device %s\n",
+                       dev->name);
+       return 0;
+}
+
+static int ltpc_init(struct net_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->hard_header = ltpc_hard_header;
+
+       dev->priv = kmalloc(sizeof(struct ltpc_private), 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 ltpc_private));
+       dev->get_stats = ltpc_get_stats;
+
+       dev->open = ltpc_open;
+       dev->stop = ltpc_close;
+
+       /* add the ltpc-specific things */
+       dev->do_ioctl = &ltpc_ioctl;
+
+       dev->set_multicast_list = &set_multicast_list;
+       dev->mc_list = NULL;
+
+       return 0;
+}
+
+static int ltpc_poll_counter = 0;
+
+static void ltpc_poll(unsigned long l)
+{
+       struct net_device *dev = (struct net_device *) l;
+
+       del_timer(&ltpc_timer);
+
+       if(debug&DEBUG_VERBOSE) {
+               if (!ltpc_poll_counter) {
+                       ltpc_poll_counter = 50;
+                       printk("ltpc poll is alive\n");
+               }
+               ltpc_poll_counter--;
+       }
+  
+       if (!dev)
+               return;  /* we've been downed */
+
+       idle(dev);
+       ltpc_timer.expires = jiffies+5;
+       
+       add_timer(&ltpc_timer);
+}
+
+/* DDP to LLAP translation */
+
+static int ltpc_xmit(struct sk_buff *skb, struct net_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 ltpc_private *)dev->priv)->stats;
+
+       int i;
+       struct lt_sendlap cbuf;
+
+       cbuf.command = LT_SENDLAP;
+       cbuf.dnode = skb->data[0];
+       cbuf.laptype = skb->data[2];
+       skb_pull(skb,3);        /* skip past LLAP header */
+       cbuf.length = skb->len; /* this is host order */
+       skb->h.raw=skb->data;
+
+       if(debug&DEBUG_UPPER) {
+               printk("command ");
+               for(i=0;i<6;i++)
+                       printk("%02x ",((unsigned char *)&cbuf)[i]);
+               printk("\n");
+       }
+
+       do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
+
+       if(debug&DEBUG_UPPER) {
+               printk("sent %d ddp bytes\n",skb->len);
+               for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
+               printk("\n");
+       }
+
+       stats->tx_packets++;
+       stats->tx_bytes+=skb->len;
+
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+static struct net_device_stats *ltpc_get_stats(struct net_device *dev)
+{
+       struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats;
+       return stats;
+}
+
+/* initialization stuff */
+  
+int __init ltpc_probe_dma(int base)
+{
+       int dma = 0;
+       int timeout;
+       unsigned long f;
+  
+       if (!request_dma(1,"ltpc")) {
+               f=claim_dma_lock();
+               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);
+               release_dma_lock(f);
+               dma|=1;
+       }
+       if (!request_dma(3,"ltpc")) {
+               f=claim_dma_lock();
+               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);
+               release_dma_lock(f);
+               dma|=2;
+       }
+
+       /* set up request */
+
+       /* FIXME -- do timings better! */
+
+       ltdmabuf[0] = LT_READMEM;
+       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(io+1);
+       inb_p(io+0);
+       timeout = jiffies+100*HZ/100;
+       while(time_before(jiffies, timeout)) {
+               if ( 0xfa == inb_p(io+6) ) break;
+       }
+
+       inb_p(io+3);
+       inb_p(io+2);
+       while(time_before(jiffies, timeout)) {
+               if ( 0xfb == inb_p(io+6) ) break;
+       }
+
+       /* release the other dma channel (if we opened both of them) */
+
+       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);
+       }
+
+       /* fix up dma number */
+       dma|=1;
+
+       return dma;
+}
+
+int __init ltpc_probe(struct net_device *dev)
+{
+       int err;
+       int x=0,y=0;
+       int timeout;
+       int autoirq;
+       unsigned long flags;
+       unsigned long f;
+
+       save_flags(flags);
+
+       /* probe for the I/O port address */
+       if (io != 0x240 && !check_region(0x220,8)) {
+               x = inb_p(0x220+6);
+               if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
+       }
+       
+       if (io != 0x220 && !check_region(0x240,8)) {
+               y = inb_p(0x240+6);
+               if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
+       } 
+
+       if(io) {
+               /* found it, now grab it */
+               request_region(io,8,"ltpc");
+       } else {
+               /* give up in despair */
+               printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
+                       x,y);
+               restore_flags(flags);
+               return -1;
+       }
+
+       /* probe for the IRQ line */
+       if (irq < 2) {
+               autoirq_setup(2);
+
+               /* reset the interrupt line */
+               inb_p(io+7);
+               inb_p(io+7);
+               /* trigger an interrupt (I hope) */
+               inb_p(io+6);
+
+               autoirq = autoirq_report(1);
+
+               if (autoirq == 0) {
+                       printk("ltpc: probe at %#x failed to detect IRQ line.\n",
+                               io);
+               }
+               else {
+                       irq = autoirq;
+               }
+       }
+
+       /* allocate a DMA buffer */
+       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+       if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
+
+       if (!ltdmabuf) {
+               printk("ltpc: mem alloc failed\n");
+               restore_flags(flags);
+               return(-1);
+       }
+
+       if(debug&DEBUG_VERBOSE) {
+               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+       }
+
+       /* reset the card */
+
+       inb_p(io+1);
+       inb_p(io+3);
+       timeout = jiffies+2*HZ/100;
+       while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */
+       inb_p(io+0);
+       inb_p(io+2);
+       inb_p(io+7); /* clear reset */
+       inb_p(io+4); 
+       inb_p(io+5);
+       inb_p(io+5); /* enable dma */
+       inb_p(io+6); /* tri-state interrupt line */
+
+       timeout = jiffies+100*HZ/100;
+       
+       while(time_before(jiffies, timeout)) {
+               /* wait for the card to complete initialization */
+       }
+       /* now, figure out which dma channel we're using, unless it's
+          already been specified */
+       /* well, 0 is a legal DMA channel, but the LTPC card doesn't
+          use it... */
+       if (dma == 0) {
+               dma = ltpc_probe_dma(io);
+               if (!dma) {  /* no dma channel */
+                       printk("No DMA channel found on ltpc card.\n");
+                       restore_flags(flags);
+                       return -1;
+               }
+       }
+
+       /* print out friendly message */
+
+       if(irq)
+               printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
+       else
+               printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
+
+       /* seems more logical to do this *after* probing the card... */
+       err = ltpc_init(dev);
+       if (err) return err;
+
+       dev->base_addr = io;
+       dev->irq = irq;
+       dev->dma = dma;
+
+       /* the card will want to send a result at this point */
+       /* (I think... leaving out this part makes the kernel crash,
+           so I put it back in...) */
+
+       f=claim_dma_lock();
+       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);
+       release_dma_lock(f);
+
+       (void) inb_p(io+3);
+       (void) inb_p(io+2);
+       timeout = jiffies+100*HZ/100;
+       while(time_before(jiffies, timeout)) {
+               if( 0xf9 == inb_p(io+6)) break;
+       }
+
+       if(debug&DEBUG_VERBOSE) {
+               printk("setting up timer and irq\n");
+       }
+
+       if (irq) {
+               /* grab it and don't let go :-) */
+               (void) request_irq( irq, &ltpc_interrupt, 0, "ltpc", dev);
+               (void) inb_p(io+7);  /* enable interrupts from board */
+               (void) inb_p(io+7);  /* and reset irq line */
+       } else {
+               /* polled mode -- 20 times per second */
+               /* this is really, really slow... should it poll more often? */
+               init_timer(&ltpc_timer);
+               ltpc_timer.function=ltpc_poll;
+               ltpc_timer.data = (unsigned long) dev;
+
+               ltpc_timer.expires = jiffies + 5;
+               add_timer(&ltpc_timer);
+               restore_flags(flags); 
+       }
+
+       return 0;
+}
+
+/* handles "ltpc=io,irq,dma" kernel command lines */
+static int __init ltpc_setup(char *str)
+{
+       int ints[5];
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       if (ints[0] == 0) {
+               if (str && !strncmp(str, "auto", 4)) {
+                       /* do nothing :-) */
+               }
+               else {
+                       /* usage message */
+                       printk (KERN_ERR
+                               "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+               }
+               return 1;
+       } else {
+               io = ints[1];
+               if (ints[0] > 1) {
+                       irq = ints[2];
+                       return 1;
+               }
+               if (ints[0] > 2) {
+                       dma = ints[3];
+                       return 1;
+               }
+               /* ignore any other paramters */
+       }
+       return 1;
+}
+
+__setup("ltpc=", ltpc_setup);
+
+#ifdef MODULE
+
+static char dev_name[8];
+
+static struct net_device dev_ltpc = {
+               dev_name, 
+               0, 0, 0, 0,
+               0x0, 0,
+               0, 0, 0, NULL, ltpc_probe };
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+
+int init_module(void)
+{
+       int err, result;
+       
+        if(io == 0)
+               printk(KERN_NOTICE
+                      "ltpc: Autoprobing is not recommended for modules\n");
+
+       /* Find a name for this unit */
+       err=dev_alloc_name(&dev_ltpc,"lt%d");
+       
+       if(err<0)
+               return err;
+
+       if ((result = register_netdev(&dev_ltpc)) != 0) {
+               printk(KERN_DEBUG "could not register Localtalk-PC device\n");
+               return result;
+       } 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,&dev_ltpc);
+               dev_ltpc.irq = 0;
+       }
+
+       if(del_timer(&ltpc_timer)) 
+       {
+               /* either the poll was never started, or a poll is in process */
+               if(debug&DEBUG_VERBOSE) printk("waiting\n");
+               /* if it's in process, wait a bit for it to finish */
+               timeout = jiffies+HZ; 
+               add_timer(&ltpc_timer);
+               while(del_timer(&ltpc_timer) && time_after(timeout, jiffies))
+               {
+                       add_timer(&ltpc_timer);
+                       schedule();
+               }
+       }
+
+       if(debug&DEBUG_VERBOSE) printk("freeing dma\n");
+
+       if(dev_ltpc.dma) {
+               free_dma(dev_ltpc.dma);
+               dev_ltpc.dma = 0;
+       }
+
+       if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n");
+
+       if(dev_ltpc.base_addr) {
+               release_region(dev_ltpc.base_addr,8);
+               dev_ltpc.base_addr = 0;
+       }
+
+       if(debug&DEBUG_VERBOSE) printk("free_pages\n");
+
+       free_pages( (unsigned long) ltdmabuf, get_order(1000));
+       ltdmabuf=NULL;
+       ltdmacbuf=NULL;
+
+       if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n");
+
+       unregister_netdev(&dev_ltpc);
+
+       if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
+}
+#endif /* MODULE */
+
diff --git a/drivers/net/appletalk/ltpc.h b/drivers/net/appletalk/ltpc.h
new file mode 100644 (file)
index 0000000..cd30544
--- /dev/null
@@ -0,0 +1,73 @@
+/***   ltpc.h
+ *
+ *
+ ***/
+
+#define LT_GETRESULT  0x00
+#define LT_WRITEMEM   0x01
+#define LT_READMEM    0x02
+#define LT_GETFLAGS   0x04
+#define LT_SETFLAGS   0x05
+#define LT_INIT       0x10
+#define LT_SENDLAP    0x13
+#define LT_RCVLAP     0x14
+
+/* the flag that we care about */
+#define LT_FLAG_ALLLAP 0x04
+
+struct lt_getresult {
+       unsigned char command;
+       unsigned char mailbox;
+};
+
+struct lt_mem {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned short addr;    /* host order */
+       unsigned short length;  /* host order */
+};
+
+struct lt_setflags {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char flags;
+};
+
+struct lt_getflags {
+       unsigned char command;
+       unsigned char mailbox;
+};
+
+struct lt_init {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char hint;
+};
+
+struct lt_sendlap {
+       unsigned char command;
+       unsigned char mailbox;
+       unsigned char dnode;
+       unsigned char laptype;
+       unsigned short length;  /* host order */
+};
+
+struct lt_rcvlap {
+       unsigned char command;
+       unsigned char dnode;
+       unsigned char snode;
+       unsigned char laptype;
+       unsigned short length;  /* host order */
+};
+
+union lt_command {
+       struct lt_getresult getresult;
+       struct lt_mem mem;
+       struct lt_setflags setflags;
+       struct lt_getflags getflags;
+       struct lt_init init;
+       struct lt_sendlap sendlap;
+       struct lt_rcvlap rcvlap;
+};
+typedef union lt_command lt_command;
+
diff --git a/drivers/net/cops.c b/drivers/net/cops.c
deleted file mode 100644 (file)
index 466705f..0000000
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*      cops.c: LocalTalk driver for Linux.
- *
- *     Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- *
- *     With more than a little help from;
- *     - Alan Cox <Alan.Cox@linux.org> 
- *
- *      Derived from:
- *      - skeleton.c: A network driver outline for linux.
- *        Written 1993-94 by Donald Becker.
- *     - ltpc.c: A driver for the LocalTalk PC card.
- *       Written by Bradford W. Johnson.
- *
- *      Copyright 1993 United States Government as represented by the
- *      Director, National Security Agency.
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU Public License, incorporated herein by reference.
- *
- *     Changes:
- *     19970608        Alan Cox        Allowed dual card type support
- *                                     Can set board type in insmod
- *                                     Hooks for cops_setup routine
- *                                     (not yet implemented).
- *     19971101        Jay Schulist    Fixes for multiple lt* devices.
- *     19980607        Steven Hirsch   Fixed the badly broken support
- *                                     for Tangent type cards. Only
- *                                      tested on Daystar LT200. Some
- *                                      cleanup of formatting and program
- *                                      logic.  Added emacs 'local-vars'
- *                                      setup for Jay's brace style.
- *     20000211        Alan Cox        Cleaned up for softnet
- */
-
-static const char *version =
-"cops.c:v0.04 6/7/98 Jay Schulist <jschlst@turbolinux.com>\n";
-/*
- *  Sources:
- *      COPS Localtalk SDK. This provides almost all of the information
- *      needed.
- */
-
-/*
- * insmod/modprobe configurable stuff.
- *     - IO Port, choose one your card supports or 0 if you dare.
- *     - IRQ, also choose one your card supports or nothing and let
- *       the driver figure it out.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>    /* For ltalk_setup() */
-#include <linux/delay.h>       /* For udelay() */
-#include <linux/atalk.h>
-
-#include "cops.h"              /* Our Stuff */
-#include "cops_ltdrv.h"                /* Firmware code for Tangent type cards. */
-#include "cops_ffdrv.h"                /* Firmware code for Dayna type cards. */
-
-/*
- *      The name of the card. Is used for messages and in the requests for
- *      io regions, irqs and dma channels
- */
-
-static const char *cardname = "cops";
-
-#ifdef CONFIG_COPS_DAYNA
-static int board_type = DAYNA; /* Module exported */
-#else
-static int board_type = TANGENT;
-#endif
-
-#ifdef MODULE
-static int io = 0x240;         /* Default IO for Dayna */
-static int irq = 5;            /* Default IRQ */
-#else
-static int io = 0;             /* Default IO for Dayna */
-static int irq = 0;            /* Default IRQ */
-#endif
-
-/*
- *     COPS Autoprobe information.
- *     Right now if port address is right but IRQ is not 5 this will
- *      return a 5 no matter what since we will still get a status response.
- *      Need one more additional check to narrow down after we have gotten
- *      the ioaddr. But since only other possible IRQs is 3 and 4 so no real
- *     hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with
- *     this driver.
- * 
- *     This driver has 2 modes and they are: Dayna mode and Tangent mode.
- *     Each mode corresponds with the type of card. It has been found
- *     that there are 2 main types of cards and all other cards are
- *     the same and just have different names or only have minor differences
- *     such as more IO ports. As this driver is tested it will
- *     become more clear on exactly what cards are supported. The driver
- *     defaults to using Dayna mode. To change the drivers mode, simply
- *     select Dayna or Tangent mode when configuring the kernel.
- *
- *      This driver should support:
- *      TANGENT driver mode:
- *              Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
- *             COPS LT-1
- *      DAYNA driver mode:
- *              Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 
- *             Farallon PhoneNET PC III, Farallon PhoneNET PC II
- *     Other cards possibly supported mode unkown though:
- *             Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
- *
- *     Cards NOT supported by this driver but supported by the ltpc.c
- *     driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *             Farallon PhoneNET PC
- *             Original Apple LocalTalk PC card
- * 
- *      N.B.
- *
- *      The Daystar Digital LT200 boards do not support interrupt-driven
- *      IO.  You must specify 'irq=0xff' as a module parameter to invoke
- *      polled mode.  I also believe that the port probing logic is quite
- *      dangerous at best and certainly hopeless for a polled card.  Best to 
- *      specify both. - Steve H.
- *
- */
-
-/*
- * Zero terminated list of IO ports to probe.
- */
-
-static unsigned int cops_portlist[] = { 
-       0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 
-       0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360,
-       0
-};
-
-/*
- * Zero terminated list of IRQ ports to probe.
- */
-
-static int cops_irqlist[] = {
-       5, 4, 3, 0 
-};
-
-static struct timer_list cops_timer;
-
-/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef COPS_DEBUG
-#define COPS_DEBUG 1 
-#endif
-static unsigned int cops_debug = COPS_DEBUG;
-
-/* The number of low I/O ports used by the card. */
-#define COPS_IO_EXTENT       8
-
-/* Information that needs to be kept for each board. */
-
-struct cops_local
-{
-        struct net_device_stats stats;
-        int board;                     /* Holds what board type is. */
-       int nodeid;                     /* Set to 1 once have nodeid. */
-        unsigned char node_acquire;    /* Node ID when acquired. */
-        struct at_addr node_addr;      /* Full node addres */
-};
-
-/* Index to functions, as function prototypes. */
-extern int  cops_probe (struct net_device *dev);
-static int  cops_probe1 (struct net_device *dev, int ioaddr);
-static int  cops_irq (int ioaddr, int board);
-
-static int  cops_open (struct net_device *dev);
-static int  cops_jumpstart (struct net_device *dev);
-static void cops_reset (struct net_device *dev, int sleep);
-static void cops_load (struct net_device *dev);
-static int  cops_nodeid (struct net_device *dev, int nodeid);
-
-static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static void cops_poll (unsigned long ltdev);
-static void cops_timeout(struct net_device *dev);
-static void cops_rx (struct net_device *dev);
-static int  cops_send_packet (struct sk_buff *skb, struct net_device *dev);
-static void set_multicast_list (struct net_device *dev);
-static int  cops_hard_header (struct sk_buff *skb, struct net_device *dev,
-                             unsigned short type, void *daddr, void *saddr, 
-                             unsigned len);
-
-static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static int  cops_close (struct net_device *dev);
-static struct net_device_stats *cops_get_stats (struct net_device *dev);
-
-
-/*
- *      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 in [1..0x1ff], always return failure.
- *        otherwise go with what we pass in.
- */
-int __init cops_probe(struct net_device *dev)
-{
-       int i;
-        int base_addr = dev ? dev->base_addr : 0;
-        
-        if(base_addr == 0 && io)
-               base_addr=io;
-
-        if(base_addr > 0x1ff)    /* Check a single specified location. */
-                return cops_probe1(dev, base_addr);
-       else if(base_addr != 0)  /* Don't probe at all. */
-                       return -ENXIO;
-       
-       /* FIXME  Does this really work for cards which generate irq?
-        * It's definitely N.G. for polled Tangent. sh
-        * Dayna cards don't autoprobe well at all, but if your card is
-        * at IRQ 5 & IO 0x240 we find it every time. ;) JS
-        */
-        for(i=0; cops_portlist[i]; i++) {
-               int ioaddr = cops_portlist[i];
-               if(check_region(ioaddr, COPS_IO_EXTENT))
-                        continue;
-                if(cops_probe1(dev, ioaddr) == 0)
-                        return 0;
-        }
-       
-        return -ENODEV;
-}
-
-/*
- *      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 __init cops_probe1(struct net_device *dev, int ioaddr)
-{
-        struct cops_local *lp;
-       static unsigned version_printed = 0;
-
-       int board = board_type;
-       
-        if(cops_debug && version_printed++ == 0)
-               printk("%s", version);
-
-        /*
-         * Since this board has jumpered interrupts, allocate the interrupt
-         * vector now. There is no point in waiting since no other device
-         * can use the interrupt, and this marks the irq as busy. Jumpered
-         * interrupts are typically not reported by the boards, and we must
-         * used AutoIRQ to find them.
-        */
-       switch (dev->irq)
-       {
-               case 0:
-                       /* COPS AutoIRQ routine */
-                       dev->irq = cops_irq(ioaddr, board);
-                       if(!dev->irq)
-                               return -EINVAL; /* No IRQ found on this port */
-                       break;
-
-               case 1:
-                       return -EINVAL;
-                       break;
-
-               /* Fixup for users that don't know that IRQ 2 is really
-                * IRQ 9, or don't know which one to set.
-                */
-               case 2:
-                       dev->irq = 9;
-                       break;
-
-               /* Polled operation requested. Although irq of zero passed as
-                * a parameter tells the init routines to probe, we'll
-                * overload it to denote polled operation at runtime.
-                */
-               case 0xff:
-                       dev->irq = 0;
-                       break;
-
-               default:
-                       break;
-       }
-
-       /* Reserve any actual interrupt. */
-       if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev))
-               return -EINVAL;
-
-       /* Grab the region so no one else tries to probe our ioports. */
-       request_region(ioaddr, COPS_IO_EXTENT, cardname);
-       dev->base_addr          = ioaddr;
-
-       /* Initialize the private device structure. */
-        dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL);
-        if(dev->priv == NULL)
-               return -ENOMEM;
-
-        lp = (struct cops_local *)dev->priv;
-        memset(lp, 0, sizeof(struct cops_local));
-
-       /* Copy local board variable to lp struct. */
-       lp->board               = board;
-
-       /* Fill in the fields of the device structure with LocalTalk values. */
-       ltalk_setup(dev);
-
-       dev->hard_start_xmit    = cops_send_packet;
-       dev->tx_timeout         = cops_timeout;
-       dev->watchdog_timeo     = HZ * 2;
-       dev->hard_header        = cops_hard_header;
-        dev->get_stats          = cops_get_stats;
-       dev->open               = cops_open;
-        dev->stop               = cops_close;
-        dev->do_ioctl           = cops_ioctl;
-       dev->set_multicast_list = set_multicast_list;
-        dev->mc_list            = NULL;
-
-       /* Tell the user where the card is and what mode we're in. */
-       if(board==DAYNA)
-               printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
-                       dev->name, cardname, ioaddr, dev->irq);
-       if(board==TANGENT) {
-               if(dev->irq)
-                       printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
-                               dev->name, cardname, ioaddr, dev->irq);
-               else
-                       printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
-                               dev->name, cardname, ioaddr);
-
-       }
-        return 0;
-}
-
-static int __init cops_irq (int ioaddr, int board)
-{       /*
-         * This does not use the IRQ to determine where the IRQ is. We just
-         * assume that when we get a correct status response that it's the IRQ.
-         * This really just verifies the IO port but since we only have access
-         * to such a small number of IRQs (5, 4, 3) this is not bad.
-         * This will probably not work for more than one card.
-         */
-        int irqaddr=0;
-        int i, x, status;
-
-        if(board==DAYNA)
-        {
-                outb(0, ioaddr+DAYNA_RESET);
-                inb(ioaddr+DAYNA_RESET);
-                udelay(333333);
-        }
-        if(board==TANGENT)
-        {
-                inb(ioaddr);
-                outb(0, ioaddr);
-                outb(0, ioaddr+TANG_RESET);
-        }
-
-        for(i=0; cops_irqlist[i] !=0; i++)
-        {
-                irqaddr = cops_irqlist[i];
-                for(x = 0xFFFF; x>0; x --)    /* wait for response */
-                {
-                        if(board==DAYNA)
-                        {
-                                status = (inb(ioaddr+DAYNA_CARD_STATUS)&3);
-                                if(status == 1)
-                                        return irqaddr;
-                        }
-                        if(board==TANGENT)
-                        {
-                                if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0)
-                                        return irqaddr;
-                        }
-                }
-        }
-        return 0;       /* no IRQ found */
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- */
-static int cops_open(struct net_device *dev)
-{
-    struct cops_local *lp = (struct cops_local *)dev->priv;
-
-       if(dev->irq==0)
-       {
-               /*
-                * I don't know if the Dayna-style boards support polled 
-                * operation.  For now, only allow it for Tangent.
-                */
-               if(lp->board==TANGENT)  /* Poll 20 times per second */
-               {
-                   init_timer(&cops_timer);
-                   cops_timer.function = cops_poll;
-                   cops_timer.data     = (unsigned long)dev;
-                   cops_timer.expires  = jiffies + 5;
-                   add_timer(&cops_timer);
-               } 
-               else 
-               {
-                       printk(KERN_WARNING "%s: No irq line set\n", dev->name);
-                       return -EAGAIN;
-               }
-       }
-
-       cops_jumpstart(dev);    /* Start the card up. */
-
-       netif_start_queue(dev);
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
-
-        return 0;
-}
-
-/*
- *     This allows for a dynamic start/restart of the entire card.
- */
-static int cops_jumpstart(struct net_device *dev)
-{
-       struct cops_local *lp = (struct cops_local *)dev->priv;
-
-       /*
-         *      Once the card has the firmware loaded and has acquired
-         *      the nodeid, if it is reset it will lose it all.
-         */
-        cops_reset(dev,1);     /* Need to reset card before load firmware. */
-        cops_load(dev);                /* Load the firmware. */
-
-       /*
-        *      If atalkd already gave us a nodeid we will use that
-        *      one again, else we wait for atalkd to give us a nodeid
-        *      in cops_ioctl. This may cause a problem if someone steals
-        *      our nodeid while we are resetting.
-        */     
-       if(lp->nodeid == 1)
-               cops_nodeid(dev,lp->node_acquire);
-
-       return 0;
-}
-
-static void tangent_wait_reset(int ioaddr)
-{
-       int timeout=0;
-
-       while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-               mdelay(1);   /* Wait 1 second */
-}
-
-/*
- *      Reset the LocalTalk board.
- */
-static void cops_reset(struct net_device *dev, int sleep)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr=dev->base_addr;
-
-        if(lp->board==TANGENT)
-        {
-                inb(ioaddr);           /* Clear request latch. */
-                outb(0,ioaddr);                /* Clear the TANG_TX_READY flop. */
-                outb(0, ioaddr+TANG_RESET);    /* Reset the adapter. */
-
-               tangent_wait_reset(ioaddr);
-                outb(0, ioaddr+TANG_CLEAR_INT);
-        }
-        if(lp->board==DAYNA)
-        {
-                outb(0, ioaddr+DAYNA_RESET);   /* Assert the reset port */
-                inb(ioaddr+DAYNA_RESET);       /* Clear the reset */
-                if(sleep)
-                {
-                        long snap=jiffies;
-
-                       /* Let card finish initializing, about 1/3 second */
-                       while(jiffies-snap<HZ/3)
-                                schedule();
-                }
-                else
-                        udelay(333333);
-        }
-       netif_wake_queue(dev);
-       return;
-}
-
-static void cops_load (struct net_device *dev)
-{
-        struct ifreq ifr;
-        struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data;
-        struct cops_local *lp=(struct cops_local *)dev->priv;
-        int ioaddr=dev->base_addr;
-       int length, i = 0;
-
-        strcpy(ifr.ifr_name,"lt0");
-
-        /* Get card's firmware code and do some checks on it. */
-#ifdef CONFIG_COPS_DAYNA        
-        if(lp->board==DAYNA)
-        {
-                ltf->length=sizeof(ffdrv_code);
-                ltf->data=ffdrv_code;
-        }
-        else
-#endif        
-#ifdef CONFIG_COPS_TANGENT
-        if(lp->board==TANGENT)
-        {
-                ltf->length=sizeof(ltdrv_code);
-                ltf->data=ltdrv_code;
-        }
-        else
-#endif
-       {
-               printk(KERN_INFO "%s; unsupported board type.\n", dev->name);
-               return;
-       }
-       
-        /* Check to make sure firmware is correct length. */
-        if(lp->board==DAYNA && ltf->length!=5983)
-        {
-                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);
-                return;
-        }
-        if(lp->board==TANGENT && ltf->length!=2501)
-        {
-                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);
-                return;
-        }
-
-        if(lp->board==DAYNA)
-        {
-                /*
-                 *      We must wait for a status response
-                 *      with the DAYNA board.
-                 */
-                while(++i<65536)
-                {
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)
-                                break;
-                }
-
-                if(i==65536)
-                        return;
-        }
-
-        /*
-         *      Upload the firmware and kick. Byte-by-byte works nicely here.
-         */
-       i=0;
-        length = ltf->length;
-        while(length--)
-        {
-                outb(ltf->data[i], ioaddr);
-                i++;
-        }
-
-       if(cops_debug > 1)
-               printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
-                       dev->name, i, ltf->length);
-
-        if(lp->board==DAYNA)   /* Tell Dayna to run the firmware code. */
-                outb(1, ioaddr+DAYNA_INT_CARD);
-       else                    /* Tell Tang to run the firmware code. */
-               inb(ioaddr);
-
-        if(lp->board==TANGENT)
-        {
-                tangent_wait_reset(ioaddr);
-                inb(ioaddr);   /* Clear initial ready signal. */
-        }
-
-        return;
-}
-
-/*
- *     Get the LocalTalk Nodeid from the card. We can suggest
- *     any nodeid 1-254. The card will try and get that exact
- *     address else we can specify 0 as the nodeid and the card
- *     will autoprobe for a nodeid.
- */
-static int cops_nodeid (struct net_device *dev, int nodeid)
-{
-       struct cops_local *lp = (struct cops_local *) dev->priv;
-       int ioaddr = dev->base_addr;
-
-       if(lp->board == DAYNA)
-        {
-               /* Empty any pending adapter responses. */
-                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
-                {
-                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
-                               cops_rx(dev);   /* Kick any packets waiting. */
-                       schedule();
-                }
-
-                outb(2, ioaddr);               /* Output command packet length as 2. */
-                outb(0, ioaddr);
-                outb(LAP_INIT, ioaddr);        /* Send LAP_INIT command byte. */
-                outb(nodeid, ioaddr);          /* Suggest node address. */
-        }
-
-       if(lp->board == TANGENT)
-        {
-                /* Empty any pending adapter responses. */
-                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
-                {
-                       outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */
-                       cops_rx(dev);           /* Kick out packets waiting. */
-                       schedule();
-                }
-
-               /* Not sure what Tangent does if nodeid picked is used. */
-                if(nodeid == 0)                                /* Seed. */
-                       nodeid = jiffies&0xFF;          /* Get a random try */
-                outb(2, ioaddr);                       /* Command length LSB */
-                outb(0, ioaddr);                               /* Command length MSB */
-                outb(LAP_INIT, ioaddr);                /* Send LAP_INIT byte */
-                outb(nodeid, ioaddr);                  /* LAP address hint. */
-                outb(0xFF, ioaddr);                    /* Int. level to use */
-        }
-
-       lp->node_acquire=0;             /* Set nodeid holder to 0. */
-        while(lp->node_acquire==0)     /* Get *True* nodeid finally. */
-       {
-               outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */
-
-               if(lp->board == DAYNA)
-               {
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
-                               cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
-               }
-               if(lp->board == TANGENT)
-               {       
-                       if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
-                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
-               }
-               schedule();
-       }
-
-       if(cops_debug > 1)
-               printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
-                       dev->name, lp->node_acquire);
-
-       lp->nodeid=1;   /* Set got nodeid to 1. */
-
-        return 0;
-}
-
-/*
- *     Poll the Tangent type cards to see if we have work.
- */
-static void cops_poll(unsigned long ltdev)
-{
-       int ioaddr, status;
-       int boguscount = 0;
-
-       struct net_device *dev = (struct net_device *)ltdev;
-
-       del_timer(&cops_timer);
-
-       if(dev == NULL)
-               return; /* We've been downed */
-
-       ioaddr = dev->base_addr;
-       do {
-               status=inb(ioaddr+TANG_CARD_STATUS);
-               if(status & TANG_RX_READY)
-                       cops_rx(dev);
-               if(status & TANG_TX_READY)
-                       netif_wake_queue(dev);
-               status = inb(ioaddr+TANG_CARD_STATUS);
-       } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
-
-       cops_timer.expires = jiffies+5;
-       add_timer(&cops_timer);
-
-       return;
-}
-
-/*
- *      The typical workload of the driver:
- *      Handle the network interface interrupts.
- */
-static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-        struct net_device *dev = dev_id;
-        struct cops_local *lp;
-        int ioaddr, status;
-        int boguscount = 0;
-
-        ioaddr = dev->base_addr;
-        lp = (struct cops_local *)dev->priv;
-
-       if(lp->board==DAYNA)
-       {
-               do {
-                       outb(0, ioaddr + COPS_CLEAR_INT);
-                               status=inb(ioaddr+DAYNA_CARD_STATUS);
-                               if((status&0x03)==DAYNA_RX_REQUEST)
-                                       cops_rx(dev);
-                       netif_wake_queue(dev);
-               } while(++boguscount < 20);
-       }
-       else
-       {
-               do {
-                               status=inb(ioaddr+TANG_CARD_STATUS);
-                       if(status & TANG_RX_READY)
-                               cops_rx(dev);
-                       if(status & TANG_TX_READY)
-                               netif_wake_queue(dev);
-                       status=inb(ioaddr+TANG_CARD_STATUS);
-               } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
-       }
-
-        return;
-}
-
-/*
- *      We have a good packet(s), get it/them out of the buffers.
- */
-static void cops_rx(struct net_device *dev)
-{
-        int pkt_len = 0;
-        int rsp_type = 0;
-        struct sk_buff *skb;
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr = dev->base_addr;
-        int boguscount = 0;
-        unsigned long flags;
-
-
-       save_flags(flags);
-        cli();  /* Disable interrupts. */
-
-        if(lp->board==DAYNA)
-        {
-                outb(0, ioaddr);                /* Send out Zero length. */
-                outb(0, ioaddr);
-                outb(DATA_READ, ioaddr);        /* Send read command out. */
-
-                /* Wait for DMA to turn around. */
-                while(++boguscount<1000000)
-                {
-                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
-                                break;
-                }
-
-                if(boguscount==1000000)
-                {
-                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);
-                        return;
-                }
-        }
-
-        /* Get response length. */
-       if(lp->board==DAYNA)
-               pkt_len = inb(ioaddr) & 0xFF;
-       else
-               pkt_len = inb(ioaddr) & 0x00FF;
-        pkt_len |= (inb(ioaddr) << 8);
-        /* Input IO code. */
-        rsp_type=inb(ioaddr);
-
-        /* Malloc up new buffer. */
-        skb = dev_alloc_skb(pkt_len);
-        if(skb == NULL)
-        {
-                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
-                       dev->name);
-                lp->stats.rx_dropped++;
-                while(pkt_len--)        /* Discard packet */
-                        inb(ioaddr);
-                return;
-        }
-        skb->dev = dev;
-        skb_put(skb, pkt_len);
-        skb->protocol = htons(ETH_P_LOCALTALK);
-
-        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
-
-        if(lp->board==DAYNA)
-                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
-
-        restore_flags(flags);  /* Restore interrupts. */
-
-        /* Check for bad response length */
-        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
-        {
-               printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
-                       dev->name, pkt_len);
-                lp->stats.tx_errors++;
-                kfree_skb(skb);
-                return;
-        }
-
-        /* Set nodeid and then get out. */
-        if(rsp_type == LAP_INIT_RSP)
-        {      /* Nodeid taken from received packet. */
-                lp->node_acquire = skb->data[0];
-                kfree_skb(skb);
-                return;
-        }
-
-        /* One last check to make sure we have a good packet. */
-        if(rsp_type != LAP_RESPONSE)
-        {
-                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
-                lp->stats.tx_errors++;
-                kfree_skb(skb);
-                return;
-        }
-
-        skb->mac.raw    = skb->data;    /* Point to entire packet. */
-        skb_pull(skb,3);
-        skb->h.raw      = skb->data;    /* Point to data (Skip header). */
-
-        /* Update the counters. */
-        lp->stats.rx_packets++;
-        lp->stats.rx_bytes += skb->len;
-
-        /* Send packet to a higher place. */
-        netif_rx(skb);
-
-        return;
-}
-
-static void cops_timeout(struct net_device *dev)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr = dev->base_addr;
-
-       lp->stats.tx_errors++;
-        if(lp->board==TANGENT)
-        {
-               if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-                               printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
-       }
-       printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
-       cops_jumpstart(dev);    /* Restart the card. */
-       dev->trans_start = jiffies;
-       netif_wake_queue(dev);
-}
-
-
-/*
- *     Make the card transmit a LocalTalk packet.
- */
-
-static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr = dev->base_addr;
-        unsigned long flags;
-
-        /*
-         * Block a timer-based transmit from overlapping. 
-        */
-        
-       netif_stop_queue(dev);
-
-       save_flags(flags);      
-       cli();  /* Disable interrupts. */
-       if(lp->board == DAYNA)   /* Wait for adapter transmit buffer. */
-               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
-       if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
-               while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
-
-       /* Output IO length. */
-       outb(skb->len, ioaddr);
-       if(lp->board == DAYNA)
-                       outb(skb->len >> 8, ioaddr);
-       else
-               outb((skb->len >> 8)&0x0FF, ioaddr);
-
-       /* Output IO code. */
-       outb(LAP_WRITE, ioaddr);
-
-       if(lp->board == DAYNA)  /* Check the transmit buffer again. */
-               while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
-
-       outsb(ioaddr, skb->data, skb->len);     /* Send out the data. */
-
-       if(lp->board==DAYNA)    /* Dayna requires you kick the card */
-               outb(1, ioaddr+DAYNA_INT_CARD);
-
-       restore_flags(flags);   /* Restore interrupts. */
-
-       /* Done sending packet, update counters and cleanup. */
-       lp->stats.tx_packets++;
-       lp->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
-       dev_kfree_skb (skb);
-        return 0;
-}
-
-/*
- *     Dummy function to keep the Appletalk layer happy.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-        if(cops_debug >= 3)
-               printk("%s: set_multicast_list executed\n", dev->name);
-}
-
-/*
- *      Another Dummy function to keep the Appletalk layer happy.
- */
-static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
-                           unsigned short type, void *daddr, void *saddr, 
-                           unsigned len)
-{
-        if(cops_debug >= 3)
-                printk("%s: cops_hard_header executed. Wow!\n", dev->name);
-        return 0;
-}
-
-/*
- *      System ioctls for the COPS LocalTalk card.
- */
-static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr;
-        struct at_addr *aa=(struct at_addr *)&lp->node_addr;
-
-        switch(cmd)
-        {
-                case SIOCSIFADDR:
-                       /* Get and set the nodeid and network # atalkd wants. */
-                       cops_nodeid(dev, sa->sat_addr.s_node);
-                       aa->s_net               = sa->sat_addr.s_net;
-                        aa->s_node              = lp->node_acquire;
-
-                       /* Set broardcast address. */
-                        dev->broadcast[0]       = 0xFF;
-                       
-                       /* Set hardware address. */
-                        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 -EOPNOTSUPP;
-        }
-}
-
-/*
- *     The inverse routine to cops_open().
- */
-static int cops_close(struct net_device *dev)
-{
-       struct cops_local *lp = (struct cops_local *)dev->priv;
-
-       /* If we were running polled, yank the timer.
-        */
-       if(lp->board==TANGENT && dev->irq==0)
-               del_timer(&cops_timer);
-
-       netif_stop_queue(dev);
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
-       
-        return 0;
-}
-
-/*
- *      Get the current statistics.
- *      This may be called with the card open or closed.
- */
-static struct net_device_stats *cops_get_stats(struct net_device *dev)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        return &lp->stats;
-}
-
-#ifdef MODULE
-static char lt_name[16];
-
-static struct net_device cops0_dev =
-{
-       lt_name,        /* device name */
-        0, 0, 0, 0,
-        0x0, 0,  /* I/O address, IRQ */
-        0, 0, 0, NULL, cops_probe
-};
-
-
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(board_type, "i");
-
-int init_module(void)
-{
-        int result, err;
-
-        if(io == 0)
-               printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
-                       cardname);
-
-        /* Copy the parameters from insmod into the device structure. */
-        cops0_dev.base_addr = io;
-        cops0_dev.irq       = irq;
-
-       err=dev_alloc_name(&cops0_dev, "lt%d");
-        if(err < 0)
-                return err;
-
-        if((result = register_netdev(&cops0_dev)) != 0)
-                return result;
-
-        return 0;
-}
-
-void cleanup_module(void)
-{
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-       unregister_netdev(&cops0_dev);
-       if(cops0_dev.priv)
-                kfree_s(cops0_dev.priv, sizeof(struct cops_local));
-       if(cops0_dev.irq)
-               free_irq(cops0_dev.irq, &cops0_dev);
-        release_region(cops0_dev.base_addr, COPS_IO_EXTENT);
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
- *  c-basic-offset: 4
- *  c-file-offsets: ((substatement-open . 0))
- * End:
- */
diff --git a/drivers/net/cops.h b/drivers/net/cops.h
deleted file mode 100644 (file)
index 4386349..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*      cops.h: LocalTalk driver for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- */
-
-#ifndef __LINUX_COPSLTALK_H
-#define __LINUX_COPSLTALK_H
-
-#ifdef __KERNEL__
-
-/* Max LLAP size we will accept. */
-#define MAX_LLAP_SIZE          603
-
-/* Tangent */
-#define TANG_CARD_STATUS        1
-#define TANG_CLEAR_INT          1
-#define TANG_RESET              3
-
-#define TANG_TX_READY           1
-#define TANG_RX_READY           2
-
-/* Dayna */
-#define DAYNA_CMD_DATA          0
-#define DAYNA_CLEAR_INT         1
-#define DAYNA_CARD_STATUS       2
-#define DAYNA_INT_CARD          3
-#define DAYNA_RESET             4
-
-#define DAYNA_RX_READY          0
-#define DAYNA_TX_READY          1
-#define DAYNA_RX_REQUEST        3
-
-/* Same on both card types */
-#define COPS_CLEAR_INT  1
-
-/* LAP response codes received from the cards. */
-#define LAP_INIT        1       /* Init cmd */
-#define LAP_INIT_RSP    2       /* Init response */
-#define LAP_WRITE       3       /* Write cmd */
-#define DATA_READ       4       /* Data read */
-#define LAP_RESPONSE    4       /* Received ALAP frame response */
-#define LAP_GETSTAT     5       /* Get LAP and HW status */
-#define LAP_RSPSTAT     6       /* Status response */
-
-#endif
-
-/*
- *     Structure to hold the firmware information.
- */
-struct ltfirmware
-{
-        unsigned int length;
-        unsigned char * data;
-};
-
-#define DAYNA 1
-#define TANGENT 2
-
-#endif
diff --git a/drivers/net/cops_ffdrv.h b/drivers/net/cops_ffdrv.h
deleted file mode 100644 (file)
index 3a20437..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-
-/*
- *     The firmware this driver downloads into the Localtalk card is a
- *     separate program and is not GPL'd source code, even though the Linux
- *     side driver and the routine that loads this data into the card are.
- *     
- *     It is taken from the COPS SDK and is under the following license
- *
- *     This material is licensed to you strictly for use in conjunction with
- *     the use of COPS LocalTalk adapters.
- *     There is no charge for this SDK. And no waranty express or implied
- *     about its fitness for any purpose. However, we will cheerefully
- *     refund every penny you paid for this SDK...
- *     Regards,
- *
- *     Thomas F. Divine
- *     Chief Scientist
- */
-
-
-/*      cops_ffdrv.h: LocalTalk driver firmware dump for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- */
-
-#include <linux/config.h>
-
-#ifdef CONFIG_COPS_DAYNA
-
-unsigned char ffdrv_code[] = {
-       58,3,0,50,228,149,33,255,255,34,226,149,
-       249,17,40,152,33,202,154,183,237,82,77,68,
-       11,107,98,19,54,0,237,176,175,50,80,0,
-       62,128,237,71,62,32,237,57,51,62,12,237,
-       57,50,237,57,54,62,6,237,57,52,62,12,
-       237,57,49,33,107,137,34,32,128,33,83,130,
-       34,40,128,33,86,130,34,42,128,33,112,130,
-       34,36,128,33,211,130,34,38,128,62,0,237,
-       57,16,33,63,148,34,34,128,237,94,205,15,
-       130,251,205,168,145,24,141,67,111,112,121,114,
-       105,103,104,116,32,40,67,41,32,49,57,56,
-       56,32,45,32,68,97,121,110,97,32,67,111,
-       109,109,117,110,105,99,97,116,105,111,110,115,
-       32,32,32,65,108,108,32,114,105,103,104,116,
-       115,32,114,101,115,101,114,118,101,100,46,32,
-       32,40,68,40,68,7,16,8,34,7,22,6,
-       16,5,12,4,8,3,6,140,0,16,39,128,
-       0,4,96,10,224,6,0,7,126,2,64,11,
-       118,12,6,13,0,14,193,15,0,5,96,3,
-       192,1,64,9,8,62,9,211,66,62,192,211,
-       66,62,100,61,32,253,6,28,33,205,129,14,
-       66,237,163,194,253,129,6,28,33,205,129,14,
-       64,237,163,194,9,130,201,62,47,50,71,152,
-       62,47,211,68,58,203,129,237,57,20,58,204,
-       129,237,57,21,33,77,152,54,132,205,233,129,
-       58,228,149,254,209,40,6,56,4,62,0,24,
-       2,219,96,33,233,149,119,230,62,33,232,149,
-       119,213,33,8,152,17,7,0,25,119,19,25,
-       119,209,201,251,237,77,245,197,213,229,221,229,
-       205,233,129,62,1,50,106,137,205,158,139,221,
-       225,225,209,193,241,251,237,77,245,197,213,219,
-       72,237,56,16,230,46,237,57,16,237,56,12,
-       58,72,152,183,32,26,6,20,17,128,2,237,
-       56,46,187,32,35,237,56,47,186,32,29,219,
-       72,230,1,32,3,5,32,232,175,50,72,152,
-       229,221,229,62,1,50,106,137,205,158,139,221,
-       225,225,24,25,62,1,50,72,152,58,201,129,
-       237,57,12,58,202,129,237,57,13,237,56,16,
-       246,17,237,57,16,209,193,241,251,237,77,245,
-       197,229,213,221,229,237,56,16,230,17,237,57,
-       16,237,56,20,58,34,152,246,16,246,8,211,
-       68,62,6,61,32,253,58,34,152,246,8,211,
-       68,58,203,129,237,57,20,58,204,129,237,57,
-       21,237,56,16,246,34,237,57,16,221,225,209,
-       225,193,241,251,237,77,33,2,0,57,126,230,
-       3,237,100,1,40,2,246,128,230,130,245,62,
-       5,211,64,241,211,64,201,229,213,243,237,56,
-       16,230,46,237,57,16,237,56,12,251,70,35,
-       35,126,254,175,202,77,133,254,129,202,15,133,
-       230,128,194,191,132,43,58,44,152,119,33,76,
-       152,119,35,62,132,119,120,254,255,40,4,58,
-       49,152,119,219,72,43,43,112,17,3,0,237,
-       56,52,230,248,237,57,52,219,72,230,1,194,
-       141,131,209,225,237,56,52,246,6,237,57,52,
-       62,1,55,251,201,62,3,211,66,62,192,211,
-       66,62,48,211,66,0,0,219,66,230,1,40,
-       4,219,67,24,240,205,203,135,58,75,152,254,
-       255,202,128,132,58,49,152,254,161,250,207,131,
-       58,34,152,211,68,62,10,211,66,62,128,211,
-       66,62,11,211,66,62,6,211,66,24,0,62,
-       14,211,66,62,33,211,66,62,1,211,66,62,
-       64,211,66,62,3,211,66,62,209,211,66,62,
-       100,71,219,66,230,1,32,6,5,32,247,195,
-       248,132,219,67,71,58,44,152,184,194,248,132,
-       62,100,71,219,66,230,1,32,6,5,32,247,
-       195,248,132,219,67,62,100,71,219,66,230,1,
-       32,6,5,32,247,195,248,132,219,67,254,133,
-       32,7,62,0,50,74,152,24,17,254,173,32,
-       7,62,1,50,74,152,24,6,254,141,194,248,
-       132,71,209,225,58,49,152,254,132,32,10,62,
-       50,205,2,134,205,144,135,24,27,254,140,32,
-       15,62,110,205,2,134,62,141,184,32,5,205,
-       144,135,24,8,62,10,205,2,134,205,8,134,
-       62,1,50,106,137,205,158,139,237,56,52,246,
-       6,237,57,52,175,183,251,201,62,20,135,237,
-       57,20,175,237,57,21,237,56,16,246,2,237,
-       57,16,237,56,20,95,237,56,21,123,254,10,
-       48,244,237,56,16,230,17,237,57,16,209,225,
-       205,144,135,62,1,50,106,137,205,158,139,237,
-       56,52,246,6,237,57,52,175,183,251,201,209,
-       225,243,219,72,230,1,40,13,62,10,211,66,
-       0,0,219,66,230,192,202,226,132,237,56,52,
-       246,6,237,57,52,62,1,55,251,201,205,203,
-       135,62,1,50,106,137,205,158,139,237,56,52,
-       246,6,237,57,52,183,251,201,209,225,62,1,
-       50,106,137,205,158,139,237,56,52,246,6,237,
-       57,52,62,2,55,251,201,209,225,243,219,72,
-       230,1,202,213,132,62,10,211,66,0,0,219,
-       66,230,192,194,213,132,229,62,1,50,106,137,
-       42,40,152,205,65,143,225,17,3,0,205,111,
-       136,62,6,211,66,58,44,152,211,66,237,56,
-       52,246,6,237,57,52,183,251,201,209,197,237,
-       56,52,230,248,237,57,52,219,72,230,1,32,
-       15,193,225,237,56,52,246,6,237,57,52,62,
-       1,55,251,201,14,23,58,37,152,254,0,40,
-       14,14,2,254,1,32,5,62,140,119,24,3,
-       62,132,119,43,43,197,205,203,135,193,62,1,
-       211,66,62,64,211,66,62,3,211,66,62,193,
-       211,66,62,100,203,39,71,219,66,230,1,32,
-       6,5,32,247,195,229,133,33,238,151,219,67,
-       71,58,44,152,184,194,229,133,119,62,100,71,
-       219,66,230,1,32,6,5,32,247,195,229,133,
-       219,67,35,119,13,32,234,193,225,62,1,50,
-       106,137,205,158,139,237,56,52,246,6,237,57,
-       52,175,183,251,201,33,234,151,35,35,62,255,
-       119,193,225,62,1,50,106,137,205,158,139,237,
-       56,52,246,6,237,57,52,175,251,201,243,61,
-       32,253,251,201,62,3,211,66,62,192,211,66,
-       58,49,152,254,140,32,19,197,229,213,17,181,
-       129,33,185,129,1,2,0,237,176,209,225,193,
-       24,27,229,213,33,187,129,58,49,152,230,15,
-       87,30,2,237,92,25,17,181,129,126,18,19,
-       35,126,18,209,225,58,34,152,246,8,211,68,
-       58,49,152,254,165,40,14,254,164,40,10,62,
-       10,211,66,62,224,211,66,24,25,58,74,152,
-       254,0,40,10,62,10,211,66,62,160,211,66,
-       24,8,62,10,211,66,62,128,211,66,62,11,
-       211,66,62,6,211,66,205,147,143,62,5,211,
-       66,62,224,211,66,62,5,211,66,62,96,211,
-       66,62,5,61,32,253,62,5,211,66,62,224,
-       211,66,62,14,61,32,253,62,5,211,66,62,
-       233,211,66,62,128,211,66,58,181,129,61,32,
-       253,62,1,211,66,62,192,211,66,1,254,19,
-       237,56,46,187,32,6,13,32,247,195,226,134,
-       62,192,211,66,0,0,219,66,203,119,40,250,
-       219,66,203,87,40,250,243,237,56,16,230,17,
-       237,57,16,237,56,20,251,62,5,211,66,62,
-       224,211,66,58,182,129,61,32,253,229,33,181,
-       129,58,183,129,203,63,119,35,58,184,129,119,
-       225,62,10,211,66,62,224,211,66,62,11,211,
-       66,62,118,211,66,62,47,211,68,62,5,211,
-       66,62,233,211,66,58,181,129,61,32,253,62,
-       5,211,66,62,224,211,66,58,182,129,61,32,
-       253,62,5,211,66,62,96,211,66,201,229,213,
-       58,50,152,230,15,87,30,2,237,92,33,187,
-       129,25,17,181,129,126,18,35,19,126,18,209,
-       225,58,71,152,246,8,211,68,58,50,152,254,
-       165,40,14,254,164,40,10,62,10,211,66,62,
-       224,211,66,24,8,62,10,211,66,62,128,211,
-       66,62,11,211,66,62,6,211,66,195,248,135,
-       62,3,211,66,62,192,211,66,197,229,213,17,
-       181,129,33,183,129,1,2,0,237,176,209,225,
-       193,62,47,211,68,62,10,211,66,62,224,211,
-       66,62,11,211,66,62,118,211,66,62,1,211,
-       66,62,0,211,66,205,147,143,195,16,136,62,
-       3,211,66,62,192,211,66,197,229,213,17,181,
-       129,33,183,129,1,2,0,237,176,209,225,193,
-       62,47,211,68,62,10,211,66,62,224,211,66,
-       62,11,211,66,62,118,211,66,205,147,143,62,
-       5,211,66,62,224,211,66,62,5,211,66,62,
-       96,211,66,62,5,61,32,253,62,5,211,66,
-       62,224,211,66,62,14,61,32,253,62,5,211,
-       66,62,233,211,66,62,128,211,66,58,181,129,
-       61,32,253,62,1,211,66,62,192,211,66,1,
-       254,19,237,56,46,187,32,6,13,32,247,195,
-       88,136,62,192,211,66,0,0,219,66,203,119,
-       40,250,219,66,203,87,40,250,62,5,211,66,
-       62,224,211,66,58,182,129,61,32,253,62,5,
-       211,66,62,96,211,66,201,197,14,67,6,0,
-       62,3,211,66,62,192,211,66,62,48,211,66,
-       0,0,219,66,230,1,40,4,219,67,24,240,
-       62,5,211,66,62,233,211,66,62,128,211,66,
-       58,181,129,61,32,253,237,163,29,62,192,211,
-       66,219,66,230,4,40,250,237,163,29,32,245,
-       219,66,230,4,40,250,62,255,71,219,66,230,
-       4,40,3,5,32,247,219,66,230,4,40,250,
-       62,5,211,66,62,224,211,66,58,182,129,61,
-       32,253,62,5,211,66,62,96,211,66,58,71,
-       152,254,1,202,18,137,62,16,211,66,62,56,
-       211,66,62,14,211,66,62,33,211,66,62,1,
-       211,66,62,248,211,66,237,56,48,246,153,230,
-       207,237,57,48,62,3,211,66,62,221,211,66,
-       193,201,58,71,152,211,68,62,10,211,66,62,
-       128,211,66,62,11,211,66,62,6,211,66,62,
-       6,211,66,58,44,152,211,66,62,16,211,66,
-       62,56,211,66,62,48,211,66,0,0,62,14,
-       211,66,62,33,211,66,62,1,211,66,62,248,
-       211,66,237,56,48,246,145,246,8,230,207,237,
-       57,48,62,3,211,66,62,221,211,66,193,201,
-       44,3,1,0,70,69,1,245,197,213,229,175,
-       50,72,152,237,56,16,230,46,237,57,16,237,
-       56,12,62,1,211,66,0,0,219,66,95,230,
-       160,32,3,195,20,139,123,230,96,194,72,139,
-       62,48,211,66,62,1,211,66,62,64,211,66,
-       237,91,40,152,205,207,143,25,43,55,237,82,
-       218,70,139,34,42,152,98,107,58,44,152,190,
-       194,210,138,35,35,62,130,190,194,200,137,62,
-       1,50,48,152,62,175,190,202,82,139,62,132,
-       190,32,44,50,50,152,62,47,50,71,152,229,
-       175,50,106,137,42,40,152,205,65,143,225,54,
-       133,43,70,58,44,152,119,43,112,17,3,0,
-       62,10,205,2,134,205,111,136,195,158,138,62,
-       140,190,32,19,50,50,152,58,233,149,230,4,
-       202,222,138,62,1,50,71,152,195,219,137,126,
-       254,160,250,185,138,254,166,242,185,138,50,50,
-       152,43,126,35,229,213,33,234,149,95,22,0,
-       25,126,254,132,40,18,254,140,40,14,58,50,
-       152,230,15,87,126,31,21,242,65,138,56,2,
-       175,119,58,50,152,230,15,87,58,233,149,230,
-       62,31,21,242,85,138,218,98,138,209,225,195,
-       20,139,58,50,152,33,100,137,230,15,95,22,
-       0,25,126,50,71,152,209,225,58,50,152,254,
-       164,250,135,138,58,73,152,254,0,40,4,54,
-       173,24,2,54,133,43,70,58,44,152,119,43,
-       112,17,3,0,205,70,135,175,50,106,137,205,
-       208,139,58,199,129,237,57,12,58,200,129,237,
-       57,13,237,56,16,246,17,237,57,16,225,209,
-       193,241,251,237,77,62,129,190,194,227,138,54,
-       130,43,70,58,44,152,119,43,112,17,3,0,
-       205,144,135,195,20,139,35,35,126,254,132,194,
-       227,138,175,50,106,137,205,158,139,24,42,58,
-       201,154,254,1,40,7,62,1,50,106,137,24,
-       237,58,106,137,254,1,202,222,138,62,128,166,
-       194,222,138,221,229,221,33,67,152,205,127,142,
-       205,109,144,221,225,225,209,193,241,251,237,77,
-       58,106,137,254,1,202,44,139,58,50,152,254,
-       164,250,44,139,58,73,152,238,1,50,73,152,
-       221,229,221,33,51,152,205,127,142,221,225,62,
-       1,50,106,137,205,158,139,195,13,139,24,208,
-       24,206,24,204,230,64,40,3,195,20,139,195,
-       20,139,43,126,33,8,152,119,35,58,44,152,
-       119,43,237,91,35,152,205,203,135,205,158,139,
-       195,13,139,175,50,78,152,62,3,211,66,62,
-       192,211,66,201,197,33,4,0,57,126,35,102,
-       111,62,1,50,106,137,219,72,205,141,139,193,
-       201,62,1,50,78,152,34,40,152,54,0,35,
-       35,54,0,195,163,139,58,78,152,183,200,229,
-       33,181,129,58,183,129,119,35,58,184,129,119,
-       225,62,47,211,68,62,14,211,66,62,193,211,
-       66,62,10,211,66,62,224,211,66,62,11,211,
-       66,62,118,211,66,195,3,140,58,78,152,183,
-       200,58,71,152,211,68,254,69,40,4,254,70,
-       32,17,58,73,152,254,0,40,10,62,10,211,
-       66,62,160,211,66,24,8,62,10,211,66,62,
-       128,211,66,62,11,211,66,62,6,211,66,62,
-       6,211,66,58,44,152,211,66,62,16,211,66,
-       62,56,211,66,62,48,211,66,0,0,219,66,
-       230,1,40,4,219,67,24,240,62,14,211,66,
-       62,33,211,66,42,40,152,205,65,143,62,1,
-       211,66,62,248,211,66,237,56,48,246,145,246,
-       8,230,207,237,57,48,62,3,211,66,62,221,
-       211,66,201,62,16,211,66,62,56,211,66,62,
-       48,211,66,0,0,219,66,230,1,40,4,219,
-       67,24,240,62,14,211,66,62,33,211,66,62,
-       1,211,66,62,248,211,66,237,56,48,246,153,
-       230,207,237,57,48,62,3,211,66,62,221,211,
-       66,201,229,213,33,234,149,95,22,0,25,126,
-       254,132,40,4,254,140,32,2,175,119,123,209,
-       225,201,6,8,14,0,31,48,1,12,16,250,
-       121,201,33,4,0,57,94,35,86,33,2,0,
-       57,126,35,102,111,221,229,34,89,152,237,83,
-       91,152,221,33,63,152,205,127,142,58,81,152,
-       50,82,152,58,80,152,135,50,80,152,205,162,
-       140,254,3,56,16,58,81,152,135,60,230,15,
-       50,81,152,175,50,80,152,24,23,58,79,152,
-       205,162,140,254,3,48,13,58,81,152,203,63,
-       50,81,152,62,255,50,79,152,58,81,152,50,
-       82,152,58,79,152,135,50,79,152,62,32,50,
-       83,152,50,84,152,237,56,16,230,17,237,57,
-       16,219,72,62,192,50,93,152,62,93,50,94,
-       152,58,93,152,61,50,93,152,32,9,58,94,
-       152,61,50,94,152,40,44,62,170,237,57,20,
-       175,237,57,21,237,56,16,246,2,237,57,16,
-       219,72,230,1,202,29,141,237,56,20,71,237,
-       56,21,120,254,10,48,237,237,56,16,230,17,
-       237,57,16,243,62,14,211,66,62,65,211,66,
-       251,58,39,152,23,23,60,50,39,152,71,58,
-       82,152,160,230,15,40,22,71,14,10,219,66,
-       230,16,202,186,141,219,72,230,1,202,186,141,
-       13,32,239,16,235,42,89,152,237,91,91,152,
-       205,47,131,48,7,61,202,186,141,195,227,141,
-       221,225,33,0,0,201,221,33,55,152,205,127,
-       142,58,84,152,61,50,84,152,40,19,58,82,
-       152,246,1,50,82,152,58,79,152,246,1,50,
-       79,152,195,29,141,221,225,33,1,0,201,221,
-       33,59,152,205,127,142,58,80,152,246,1,50,
-       80,152,58,82,152,135,246,1,50,82,152,58,
-       83,152,61,50,83,152,194,29,141,221,225,33,
-       2,0,201,221,229,33,0,0,57,17,4,0,
-       25,126,50,44,152,230,128,50,85,152,58,85,
-       152,183,40,6,221,33,88,2,24,4,221,33,
-       150,0,58,44,152,183,40,53,60,40,50,60,
-       40,47,61,61,33,86,152,119,35,119,35,54,
-       129,175,50,48,152,221,43,221,229,225,124,181,
-       40,42,33,86,152,17,3,0,205,189,140,17,
-       232,3,27,123,178,32,251,58,48,152,183,40,
-       224,58,44,152,71,62,7,128,230,127,71,58,
-       85,152,176,50,44,152,24,162,221,225,201,183,
-       221,52,0,192,221,52,1,192,221,52,2,192,
-       221,52,3,192,55,201,245,62,1,211,100,241,
-       201,245,62,1,211,96,241,201,33,2,0,57,
-       126,35,102,111,237,56,48,230,175,237,57,48,
-       62,48,237,57,49,125,237,57,32,124,237,57,
-       33,62,0,237,57,34,62,88,237,57,35,62,
-       0,237,57,36,237,57,37,33,128,2,125,237,
-       57,38,124,237,57,39,237,56,48,246,97,230,
-       207,237,57,48,62,0,237,57,0,62,0,211,
-       96,211,100,201,33,2,0,57,126,35,102,111,
-       237,56,48,230,175,237,57,48,62,12,237,57,
-       49,62,76,237,57,32,62,0,237,57,33,237,
-       57,34,125,237,57,35,124,237,57,36,62,0,
-       237,57,37,33,128,2,125,237,57,38,124,237,
-       57,39,237,56,48,246,97,230,207,237,57,48,
-       62,1,211,96,201,33,2,0,57,126,35,102,
-       111,229,237,56,48,230,87,237,57,48,125,237,
-       57,40,124,237,57,41,62,0,237,57,42,62,
-       67,237,57,43,62,0,237,57,44,58,106,137,
-       254,1,32,5,33,6,0,24,3,33,128,2,
-       125,237,57,46,124,237,57,47,237,56,50,230,
-       252,246,2,237,57,50,225,201,33,4,0,57,
-       94,35,86,33,2,0,57,126,35,102,111,237,
-       56,48,230,87,237,57,48,125,237,57,40,124,
-       237,57,41,62,0,237,57,42,62,67,237,57,
-       43,62,0,237,57,44,123,237,57,46,122,237,
-       57,47,237,56,50,230,244,246,0,237,57,50,
-       237,56,48,246,145,230,207,237,57,48,201,213,
-       237,56,46,95,237,56,47,87,237,56,46,111,
-       237,56,47,103,183,237,82,32,235,33,128,2,
-       183,237,82,209,201,213,237,56,38,95,237,56,
-       39,87,237,56,38,111,237,56,39,103,183,237,
-       82,32,235,33,128,2,183,237,82,209,201,245,
-       197,1,52,0,237,120,230,253,237,121,193,241,
-       201,245,197,1,52,0,237,120,246,2,237,121,
-       193,241,201,33,2,0,57,126,35,102,111,126,
-       35,110,103,201,33,0,0,34,102,152,34,96,
-       152,34,98,152,33,202,154,34,104,152,237,91,
-       104,152,42,226,149,183,237,82,17,0,255,25,
-       34,100,152,203,124,40,6,33,0,125,34,100,
-       152,42,104,152,35,35,35,229,205,120,139,193,
-       201,205,186,149,229,42,40,152,35,35,35,229,
-       205,39,144,193,124,230,3,103,221,117,254,221,
-       116,255,237,91,42,152,35,35,35,183,237,82,
-       32,12,17,5,0,42,42,152,205,171,149,242,
-       169,144,42,40,152,229,205,120,139,193,195,198,
-       149,237,91,42,152,42,98,152,25,34,98,152,
-       19,19,19,42,102,152,25,34,102,152,237,91,
-       100,152,33,158,253,25,237,91,102,152,205,171,
-       149,242,214,144,33,0,0,34,102,152,62,1,
-       50,95,152,205,225,144,195,198,149,58,95,152,
-       183,200,237,91,96,152,42,102,152,205,171,149,
-       242,5,145,237,91,102,152,33,98,2,25,237,
-       91,96,152,205,171,149,250,37,145,237,91,96,
-       152,42,102,152,183,237,82,32,7,42,98,152,
-       125,180,40,13,237,91,102,152,42,96,152,205,
-       171,149,242,58,145,237,91,104,152,42,102,152,
-       25,35,35,35,229,205,120,139,193,175,50,95,
-       152,201,195,107,139,205,206,149,250,255,243,205,
-       225,144,251,58,230,149,183,194,198,149,17,1,
-       0,42,98,152,205,171,149,250,198,149,62,1,
-       50,230,149,237,91,96,152,42,104,152,25,221,
-       117,252,221,116,253,237,91,104,152,42,96,152,
-       25,35,35,35,221,117,254,221,116,255,35,35,
-       35,229,205,39,144,124,230,3,103,35,35,35,
-       221,117,250,221,116,251,235,221,110,252,221,102,
-       253,115,35,114,35,54,4,62,1,211,100,211,
-       84,195,198,149,33,0,0,34,102,152,34,96,
-       152,34,98,152,33,202,154,34,104,152,237,91,
-       104,152,42,226,149,183,237,82,17,0,255,25,
-       34,100,152,33,109,152,54,0,33,107,152,229,
-       205,240,142,193,62,47,50,34,152,62,132,50,
-       49,152,205,241,145,205,61,145,58,39,152,60,
-       50,39,152,24,241,205,206,149,251,255,33,109,
-       152,126,183,202,198,149,110,221,117,251,33,109,
-       152,54,0,221,126,251,254,1,40,28,254,3,
-       40,101,254,4,202,190,147,254,5,202,147,147,
-       254,8,40,87,33,107,152,229,205,240,142,195,
-       198,149,58,201,154,183,32,21,33,111,152,126,
-       50,229,149,205,52,144,33,110,152,110,38,0,
-       229,205,11,142,193,237,91,96,152,42,104,152,
-       25,221,117,254,221,116,255,35,35,54,2,17,
-       2,0,43,43,115,35,114,58,44,152,35,35,
-       119,58,228,149,35,119,62,1,211,100,211,84,
-       62,1,50,201,154,24,169,205,153,142,58,231,
-       149,183,40,250,175,50,231,149,33,110,152,126,
-       254,255,40,91,58,233,149,230,63,183,40,83,
-       94,22,0,33,234,149,25,126,183,40,13,33,
-       110,152,94,33,234,150,25,126,254,3,32,36,
-       205,81,148,125,180,33,110,152,94,22,0,40,
-       17,33,234,149,25,54,0,33,107,152,229,205,
-       240,142,193,195,198,149,33,234,150,25,54,0,
-       33,110,152,94,22,0,33,234,149,25,126,50,
-       49,152,254,132,32,37,62,47,50,34,152,42,
-       107,152,229,33,110,152,229,205,174,140,193,193,
-       125,180,33,110,152,94,22,0,33,234,150,202,
-       117,147,25,52,195,120,147,58,49,152,254,140,
-       32,7,62,1,50,34,152,24,210,62,32,50,
-       106,152,24,19,58,49,152,95,58,106,152,163,
-       183,58,106,152,32,11,203,63,50,106,152,58,
-       106,152,183,32,231,254,2,40,51,254,4,40,
-       38,254,8,40,26,254,16,40,13,254,32,32,
-       158,62,165,50,49,152,62,69,24,190,62,164,
-       50,49,152,62,70,24,181,62,163,50,49,152,
-       175,24,173,62,162,50,49,152,62,1,24,164,
-       62,161,50,49,152,62,3,24,155,25,54,0,
-       221,126,251,254,8,40,7,58,230,149,183,202,
-       32,146,33,107,152,229,205,240,142,193,211,84,
-       195,198,149,237,91,96,152,42,104,152,25,221,
-       117,254,221,116,255,35,35,54,6,17,2,0,
-       43,43,115,35,114,58,228,149,35,35,119,58,
-       233,149,35,119,205,146,142,195,32,146,237,91,
-       96,152,42,104,152,25,229,205,160,142,193,58,
-       231,149,183,40,250,175,50,231,149,243,237,91,
-       96,152,42,104,152,25,221,117,254,221,116,255,
-       78,35,70,221,113,252,221,112,253,89,80,42,
-       98,152,183,237,82,34,98,152,203,124,40,19,
-       33,0,0,34,98,152,34,102,152,34,96,152,
-       62,1,50,95,152,24,40,221,94,252,221,86,
-       253,19,19,19,42,96,152,25,34,96,152,237,
-       91,100,152,33,158,253,25,237,91,96,152,205,
-       171,149,242,55,148,33,0,0,34,96,152,175,
-       50,230,149,251,195,32,146,245,62,1,50,231,
-       149,62,16,237,57,0,211,80,241,251,237,77,
-       201,205,186,149,229,229,33,0,0,34,37,152,
-       33,110,152,126,50,234,151,58,44,152,33,235,
-       151,119,221,54,253,0,221,54,254,0,195,230,
-       148,33,236,151,54,175,33,3,0,229,33,234,
-       151,229,205,174,140,193,193,33,236,151,126,254,
-       255,40,74,33,245,151,110,221,117,255,33,249,
-       151,126,221,166,255,221,119,255,33,253,151,126,
-       221,166,255,221,119,255,58,232,149,95,221,126,
-       255,163,221,119,255,183,40,15,230,191,33,110,
-       152,94,22,0,33,234,149,25,119,24,12,33,
-       110,152,94,22,0,33,234,149,25,54,132,33,
-       0,0,195,198,149,221,110,253,221,102,254,35,
-       221,117,253,221,116,254,17,32,0,221,110,253,
-       221,102,254,205,171,149,250,117,148,58,233,149,
-       203,87,40,84,33,1,0,34,37,152,221,54,
-       253,0,221,54,254,0,24,53,33,236,151,54,
-       175,33,3,0,229,33,234,151,229,205,174,140,
-       193,193,33,236,151,126,254,255,40,14,33,110,
-       152,94,22,0,33,234,149,25,54,140,24,159,
-       221,110,253,221,102,254,35,221,117,253,221,116,
-       254,17,32,0,221,110,253,221,102,254,205,171,
-       149,250,12,149,33,2,0,34,37,152,221,54,
-       253,0,221,54,254,0,24,54,33,236,151,54,
-       175,33,3,0,229,33,234,151,229,205,174,140,
-       193,193,33,236,151,126,254,255,40,15,33,110,
-       152,94,22,0,33,234,149,25,54,132,195,211,
-       148,221,110,253,221,102,254,35,221,117,253,221,
-       116,254,17,32,0,221,110,253,221,102,254,205,
-       171,149,250,96,149,33,1,0,195,198,149,124,
-       170,250,179,149,237,82,201,124,230,128,237,82,
-       60,201,225,253,229,221,229,221,33,0,0,221,
-       57,233,221,249,221,225,253,225,201,233,225,253,
-       229,221,229,221,33,0,0,221,57,94,35,86,
-       35,235,57,249,235,233,0,0,0,0,0,0,
-       62,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       175,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,133,1,0,0,0,63,
-       255,255,255,255,0,0,0,63,0,0,0,0,
-       0,0,0,0,0,0,0,24,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0
-       } ;
-
-#endif
diff --git a/drivers/net/cops_ltdrv.h b/drivers/net/cops_ltdrv.h
deleted file mode 100644 (file)
index e3e850c..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- *     The firmware this driver downloads into the Localtalk card is a
- *     separate program and is not GPL'd source code, even though the Linux
- *     side driver and the routine that loads this data into the card are.
- *     
- *     It is taken from the COPS SDK and is under the following license
- *
- *     This material is licensed to you strictly for use in conjunction with
- *     the use of COPS LocalTalk adapters.
- *     There is no charge for this SDK. And no waranty express or implied
- *     about its fitness for any purpose. However, we will cheerefully
- *     refund every penny you paid for this SDK...
- *     Regards,
- *
- *     Thomas F. Divine
- *     Chief Scientist
- */
-
-
-/*      cops_ltdrv.h: LocalTalk driver firmware dump for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- */
-#include <linux/config.h>
-
-#ifdef CONFIG_COPS_TANGENT
-
-unsigned char ltdrv_code[] = {
-       58,3,0,50,148,10,33,143,15,62,85,119,
-       190,32,9,62,170,119,190,32,3,35,24,241,
-       34,146,10,249,17,150,10,33,143,15,183,237,
-       82,77,68,11,107,98,19,54,0,237,176,62,
-       16,237,57,51,62,0,237,57,50,237,57,54,
-       62,12,237,57,49,62,195,33,39,2,50,56,
-       0,34,57,0,237,86,205,30,2,251,205,60,
-       10,24,169,67,111,112,121,114,105,103,104,116,
-       32,40,99,41,32,49,57,56,56,45,49,57,
-       57,50,44,32,80,114,105,110,116,105,110,103,
-       32,67,111,109,109,117,110,105,99,97,116,105,
-       111,110,115,32,65,115,115,111,99,105,97,116,
-       101,115,44,32,73,110,99,46,65,108,108,32,
-       114,105,103,104,116,115,32,114,101,115,101,114,
-       118,101,100,46,32,32,4,4,22,40,255,60,
-       4,96,10,224,6,0,7,126,2,64,11,246,
-       12,6,13,0,14,193,15,0,5,96,3,192,
-       1,0,9,8,62,3,211,82,62,192,211,82,
-       201,62,3,211,82,62,213,211,82,201,62,5,
-       211,82,62,224,211,82,201,62,5,211,82,62,
-       224,211,82,201,62,5,211,82,62,96,211,82,
-       201,6,28,33,180,1,14,82,237,163,194,4,
-       2,33,39,2,34,64,0,58,3,0,230,1,
-       192,62,11,237,121,62,118,237,121,201,33,182,
-       10,54,132,205,253,1,201,245,197,213,229,42,
-       150,10,14,83,17,98,2,67,20,237,162,58,
-       179,1,95,219,82,230,1,32,6,29,32,247,
-       195,17,3,62,1,211,82,219,82,95,230,160,
-       32,10,237,162,32,225,21,32,222,195,15,3,
-       237,162,123,230,96,194,21,3,62,48,211,82,
-       62,1,211,82,175,211,82,237,91,150,10,43,
-       55,237,82,218,19,3,34,152,10,98,107,58,
-       154,10,190,32,81,62,1,50,158,10,35,35,
-       62,132,190,32,44,54,133,43,70,58,154,10,
-       119,43,112,17,3,0,205,137,3,62,16,211,
-       82,62,56,211,82,205,217,1,42,150,10,14,
-       83,17,98,2,67,20,58,178,1,95,195,59,
-       2,62,129,190,194,227,2,54,130,43,70,58,
-       154,10,119,43,112,17,3,0,205,137,3,195,
-       254,2,35,35,126,254,132,194,227,2,205,61,
-       3,24,20,62,128,166,194,222,2,221,229,221,
-       33,175,10,205,93,6,205,144,7,221,225,225,
-       209,193,241,251,237,77,221,229,221,33,159,10,
-       205,93,6,221,225,205,61,3,195,247,2,24,
-       237,24,235,24,233,230,64,40,2,24,227,24,
-       225,175,50,179,10,205,208,1,201,197,33,4,
-       0,57,126,35,102,111,205,51,3,193,201,62,
-       1,50,179,10,34,150,10,54,0,58,179,10,
-       183,200,62,14,211,82,62,193,211,82,62,10,
-       211,82,62,224,211,82,62,6,211,82,58,154,
-       10,211,82,62,16,211,82,62,56,211,82,62,
-       48,211,82,219,82,230,1,40,4,219,83,24,
-       242,62,14,211,82,62,33,211,82,62,1,211,
-       82,62,9,211,82,62,32,211,82,205,217,1,
-       201,14,83,205,208,1,24,23,14,83,205,208,
-       1,205,226,1,58,174,1,61,32,253,205,244,
-       1,58,174,1,61,32,253,205,226,1,58,175,
-       1,61,32,253,62,5,211,82,62,233,211,82,
-       62,128,211,82,58,176,1,61,32,253,237,163,
-       27,62,192,211,82,219,82,230,4,40,250,237,
-       163,27,122,179,32,243,219,82,230,4,40,250,
-       58,178,1,71,219,82,230,4,40,3,5,32,
-       247,219,82,230,4,40,250,205,235,1,58,177,
-       1,61,32,253,205,244,1,201,229,213,35,35,
-       126,230,128,194,145,4,43,58,154,10,119,43,
-       70,33,181,10,119,43,112,17,3,0,243,62,
-       10,211,82,219,82,230,128,202,41,4,209,225,
-       62,1,55,251,201,205,144,3,58,180,10,254,
-       255,202,127,4,205,217,1,58,178,1,71,219,
-       82,230,1,32,6,5,32,247,195,173,4,219,
-       83,71,58,154,10,184,194,173,4,58,178,1,
-       71,219,82,230,1,32,6,5,32,247,195,173,
-       4,219,83,58,178,1,71,219,82,230,1,32,
-       6,5,32,247,195,173,4,219,83,254,133,194,
-       173,4,58,179,1,24,4,58,179,1,135,61,
-       32,253,209,225,205,137,3,205,61,3,183,251,
-       201,209,225,243,62,10,211,82,219,82,230,128,
-       202,164,4,62,1,55,251,201,205,144,3,205,
-       61,3,183,251,201,209,225,62,2,55,251,201,
-       243,62,14,211,82,62,33,211,82,251,201,33,
-       4,0,57,94,35,86,33,2,0,57,126,35,
-       102,111,221,229,34,193,10,237,83,195,10,221,
-       33,171,10,205,93,6,58,185,10,50,186,10,
-       58,184,10,135,50,184,10,205,112,6,254,3,
-       56,16,58,185,10,135,60,230,15,50,185,10,
-       175,50,184,10,24,23,58,183,10,205,112,6,
-       254,3,48,13,58,185,10,203,63,50,185,10,
-       62,255,50,183,10,58,185,10,50,186,10,58,
-       183,10,135,50,183,10,62,32,50,187,10,50,
-       188,10,6,255,219,82,230,16,32,3,5,32,
-       247,205,180,4,6,40,219,82,230,16,40,3,
-       5,32,247,62,10,211,82,219,82,230,128,194,
-       46,5,219,82,230,16,40,214,237,95,71,58,
-       186,10,160,230,15,40,32,71,14,10,62,10,
-       211,82,219,82,230,128,202,119,5,205,180,4,
-       195,156,5,219,82,230,16,202,156,5,13,32,
-       229,16,225,42,193,10,237,91,195,10,205,252,
-       3,48,7,61,202,156,5,195,197,5,221,225,
-       33,0,0,201,221,33,163,10,205,93,6,58,
-       188,10,61,50,188,10,40,19,58,186,10,246,
-       1,50,186,10,58,183,10,246,1,50,183,10,
-       195,46,5,221,225,33,1,0,201,221,33,167,
-       10,205,93,6,58,184,10,246,1,50,184,10,
-       58,186,10,135,246,1,50,186,10,58,187,10,
-       61,50,187,10,194,46,5,221,225,33,2,0,
-       201,221,229,33,0,0,57,17,4,0,25,126,
-       50,154,10,230,128,50,189,10,58,189,10,183,
-       40,6,221,33,88,2,24,4,221,33,150,0,
-       58,154,10,183,40,49,60,40,46,61,33,190,
-       10,119,35,119,35,54,129,175,50,158,10,221,
-       43,221,229,225,124,181,40,42,33,190,10,17,
-       3,0,205,206,4,17,232,3,27,123,178,32,
-       251,58,158,10,183,40,224,58,154,10,71,62,
-       7,128,230,127,71,58,189,10,176,50,154,10,
-       24,166,221,225,201,183,221,52,0,192,221,52,
-       1,192,221,52,2,192,221,52,3,192,55,201,
-       6,8,14,0,31,48,1,12,16,250,121,201,
-       33,2,0,57,94,35,86,35,78,35,70,35,
-       126,35,102,105,79,120,68,103,237,176,201,33,
-       2,0,57,126,35,102,111,62,17,237,57,48,
-       125,237,57,40,124,237,57,41,62,0,237,57,
-       42,62,64,237,57,43,62,0,237,57,44,33,
-       128,2,125,237,57,46,124,237,57,47,62,145,
-       237,57,48,211,68,58,149,10,211,66,201,33,
-       2,0,57,126,35,102,111,62,33,237,57,48,
-       62,64,237,57,32,62,0,237,57,33,237,57,
-       34,125,237,57,35,124,237,57,36,62,0,237,
-       57,37,33,128,2,125,237,57,38,124,237,57,
-       39,62,97,237,57,48,211,67,58,149,10,211,
-       66,201,237,56,46,95,237,56,47,87,237,56,
-       46,111,237,56,47,103,183,237,82,32,235,33,
-       128,2,183,237,82,201,237,56,38,95,237,56,
-       39,87,237,56,38,111,237,56,39,103,183,237,
-       82,32,235,33,128,2,183,237,82,201,205,106,
-       10,221,110,6,221,102,7,126,35,110,103,195,
-       118,10,205,106,10,33,0,0,34,205,10,34,
-       198,10,34,200,10,33,143,15,34,207,10,237,
-       91,207,10,42,146,10,183,237,82,17,0,255,
-       25,34,203,10,203,124,40,6,33,0,125,34,
-       203,10,42,207,10,229,205,37,3,195,118,10,
-       205,106,10,229,42,150,10,35,35,35,229,205,
-       70,7,193,124,230,3,103,221,117,254,221,116,
-       255,237,91,152,10,35,35,35,183,237,82,32,
-       12,17,5,0,42,152,10,205,91,10,242,203,
-       7,42,150,10,229,205,37,3,195,118,10,237,
-       91,152,10,42,200,10,25,34,200,10,42,205,
-       10,25,34,205,10,237,91,203,10,33,158,253,
-       25,237,91,205,10,205,91,10,242,245,7,33,
-       0,0,34,205,10,62,1,50,197,10,205,5,
-       8,33,0,0,57,249,195,118,10,205,106,10,
-       58,197,10,183,202,118,10,237,91,198,10,42,
-       205,10,205,91,10,242,46,8,237,91,205,10,
-       33,98,2,25,237,91,198,10,205,91,10,250,
-       78,8,237,91,198,10,42,205,10,183,237,82,
-       32,7,42,200,10,125,180,40,13,237,91,205,
-       10,42,198,10,205,91,10,242,97,8,237,91,
-       207,10,42,205,10,25,229,205,37,3,175,50,
-       197,10,195,118,10,205,29,3,33,0,0,57,
-       249,195,118,10,205,106,10,58,202,10,183,40,
-       22,205,14,7,237,91,209,10,19,19,19,205,
-       91,10,242,139,8,33,1,0,195,118,10,33,
-       0,0,195,118,10,205,126,10,252,255,205,108,
-       8,125,180,194,118,10,237,91,200,10,33,0,
-       0,205,91,10,242,118,10,237,91,207,10,42,
-       198,10,25,221,117,254,221,116,255,35,35,35,
-       229,205,70,7,193,124,230,3,103,35,35,35,
-       221,117,252,221,116,253,229,221,110,254,221,102,
-       255,229,33,212,10,229,205,124,6,193,193,221,
-       110,252,221,102,253,34,209,10,33,211,10,54,
-       4,33,209,10,227,205,147,6,193,62,1,50,
-       202,10,243,221,94,252,221,86,253,42,200,10,
-       183,237,82,34,200,10,203,124,40,17,33,0,
-       0,34,200,10,34,205,10,34,198,10,50,197,
-       10,24,37,221,94,252,221,86,253,42,198,10,
-       25,34,198,10,237,91,203,10,33,158,253,25,
-       237,91,198,10,205,91,10,242,68,9,33,0,
-       0,34,198,10,205,5,8,33,0,0,57,249,
-       251,195,118,10,205,106,10,33,49,13,126,183,
-       40,16,205,42,7,237,91,47,13,19,19,19,
-       205,91,10,242,117,9,58,142,15,198,1,50,
-       142,15,195,118,10,33,49,13,126,254,1,40,
-       25,254,3,202,7,10,254,5,202,21,10,33,
-       49,13,54,0,33,47,13,229,205,207,6,195,
-       118,10,58,141,15,183,32,72,33,51,13,126,
-       50,149,10,205,86,7,33,50,13,126,230,127,
-       183,32,40,58,142,15,230,127,50,142,15,183,
-       32,5,198,1,50,142,15,33,50,13,126,111,
-       23,159,103,203,125,58,142,15,40,5,198,128,
-       50,142,15,33,50,13,119,33,50,13,126,111,
-       23,159,103,229,205,237,5,193,33,211,10,54,
-       2,33,2,0,34,209,10,58,154,10,33,212,
-       10,119,58,148,10,33,213,10,119,33,209,10,
-       229,205,147,6,193,24,128,42,47,13,229,33,
-       50,13,229,205,191,4,193,24,239,33,211,10,
-       54,6,33,3,0,34,209,10,58,154,10,33,
-       212,10,119,58,148,10,33,213,10,119,33,214,
-       10,54,5,33,209,10,229,205,147,6,24,200,
-       205,106,10,33,49,13,54,0,33,47,13,229,
-       205,207,6,33,209,10,227,205,147,6,193,205,
-       80,9,205,145,8,24,248,124,170,250,99,10,
-       237,82,201,124,230,128,237,82,60,201,225,253,
-       229,221,229,221,33,0,0,221,57,233,221,249,
-       221,225,253,225,201,233,225,253,229,221,229,221,
-       33,0,0,221,57,94,35,86,35,235,57,249,
-       235,233,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0
-       } ;
-
-#endif
index 01dd799b3810c0eea78459bea3795334993afe6a..5ef42cf9c62a189b35beb6fcf66c01b36379a011 100644 (file)
@@ -1,4 +1,7 @@
-/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
+/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0
+ *  driver for linux.
+ */
+
 /*
        Written 1996 by Russell Nelson, with reference to skeleton.c
        written 1993-1994 by Donald Becker.
@@ -6,8 +9,8 @@
        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
+        The author may be reached at nelson@crynwr.com, Crynwr
+        Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
 
   Changelog:
 
                     : as an example. Disabled autoprobing in init_module(),
                     : not a good thing to do to other devices while Linux
                     : is running from all accounts.
-                    
+
+  Russ Nelson       : Jul 13 1998.  Added RxOnly DMA support.
+
+  Melody Lee        : Aug 10 1999.  Changes for Linux 2.2.5 compatibility. 
+                    : email: ethernet@crystal.cirrus.com
+
   Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
+
+  Andrew Morton     : andrewm@uow.edu.au
+                    : Kernel 2.3.48
+                    : Handle kmalloc() failures
+                    : Other resource allocation fixes
+                    : Add SMP locks
+                    : Integrate Russ Nelson's ALLOW_DMA functionality back in.
+                    : If ALLOW_DMA is true, make DMA runtime selectable
+                    : Folded in changes from Cirrus (Melody Lee
+                    : <klee@crystal.cirrus.com>)
+                    : Don't call netif_wake_queue() in net_send_packet()
+                    : Fixed an out-of-mem bug in dma_rx()
+                    : Updated Documentation/cs89x0.txt
 */
 
 static char *version =
-"cs89x0.c:v1.03 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
-
-/* ======================= configure the driver here ======================= */
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 2
-#endif
+"cs89x0.c: (kernel 2.3.48) Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
 
 /* ======================= end of configuration ======================= */
 
@@ -52,7 +66,19 @@ static char *version =
 #define MOD_DEC_USE_COUNT
 #endif
 
-#define PRINTK(x) printk x
+/*
+ * Set this to zero to disable DMA code
+ *
+ * Note that even if DMA is turned off we still support the 'dma' and  'use_dma'
+ * module options so we don't break any startup scripts.
+ */
+#define ALLOW_DMA      1
+
+/*
+ * Set this to zero to remove all the debug statements via
+ * dead code elimination
+ */
+#define DEBUGGING      0
 
 /*
   Sources:
@@ -76,39 +102,66 @@ static char *version =
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#if ALLOW_DMA
+#include <asm/dma.h>
+#endif
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+
 #include "cs89x0.h"
 
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int netcard_portlist[] __initdata =
-   { 0x300, 0x320, 0x340, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+   { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 
-static unsigned int net_debug = NET_DEBUG;
+#if DEBUGGING
+static unsigned int net_debug = 5;
+#else
+#define net_debug 0    /* gcc will remove all the debug code for us */
+#endif
 
 /* The number of low I/O ports used by the ethercard. */
 #define NETCARD_IO_EXTENT      16
 
+/* we allow the user to override various values normally set in the EEPROM */
+#define FORCE_RJ45     0x0001    /* pick one of these three */
+#define FORCE_AUI      0x0002
+#define FORCE_BNC      0x0004
+
+#define FORCE_AUTO     0x0010    /* pick one of these three */
+#define FORCE_HALF     0x0020
+#define FORCE_FULL     0x0030
+
 /* 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;
+       int send_cmd;           /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */
+       int auto_neg_cnf;       /* auto-negotiation word from EEPROM */
+       int adapter_cnf;        /* adapter configuration from EEPROM */
+       int isa_config;         /* ISA configuration from EEPROM */
+       int irq_map;            /* IRQ map from EEPROM */
+       int rx_mode;            /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */
+       int curr_rx_cfg;        /* a copy of PP_RxCFG */
+       int linectl;            /* either 0 or LOW_RX_SQUELCH, depending on configuration. */
+       int send_underrun;      /* keep track of how many underruns in a row we get */
+       int force;              /* force various values; see FORCE* above. */
+       spinlock_t lock;
+#if ALLOW_DMA
+       int use_dma;            /* Flag: we're using dma */
+       int dma;                /* DMA channel */
+       int dmasize;            /* 16 or 64 */
+       unsigned char *dma_buff;        /* points to the beginning of the buffer */
+       unsigned char *end_dma_buff;    /* points to the end of the buffer */
+       unsigned char *rx_dma_ptr;      /* points to the next packet  */
+#endif
 };
 
 /* Index to functions, as function prototypes. */
@@ -117,7 +170,7 @@ extern int cs89x0_probe(struct net_device *dev);
 
 static int cs89x0_probe1(struct net_device *dev, int ioaddr);
 static int net_open(struct net_device *dev);
-static int     net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void set_multicast_list(struct net_device *dev);
 static void net_timeout(struct net_device *dev);
@@ -128,7 +181,11 @@ static void reset_chip(struct net_device *dev);
 static int get_eeprom_data(struct net_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 net_device *dev, void *addr);
-
+static void count_rx_errors(int status, struct net_local *lp);
+#if ALLOW_DMA
+static void get_dma_channel(struct net_device *dev);
+static void release_dma_buff(struct net_local *lp);
+#endif
 
 /* Example routines you must write ;->. */
 #define tx_done(dev) 1
@@ -139,6 +196,7 @@ static int set_mac_address(struct net_device *dev, void *addr);
    If dev->base_addr == 1, always return failure.
    If dev->base_addr == 2, allocate space for the device and return success
    (detachable devices only).
+   Return 0 on success.
    */
 
 int __init cs89x0_probe(struct net_device *dev)
@@ -146,6 +204,9 @@ int __init cs89x0_probe(struct net_device *dev)
        int i;
        int base_addr = dev ? dev->base_addr : 0;
 
+       if (net_debug)
+               printk("cs89x0:cs89x0_probe()\n");
+
        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. */
@@ -158,34 +219,38 @@ int __init cs89x0_probe(struct net_device *dev)
                if (cs89x0_probe1(dev, ioaddr) == 0)
                        return 0;
        }
-       printk("cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
+       printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
        return ENODEV;
 }
 
-extern int inline readreg(struct net_device *dev, int portno)
+extern int inline
+readreg(struct net_device *dev, int portno)
 {
        outw(portno, dev->base_addr + ADD_PORT);
        return inw(dev->base_addr + DATA_PORT);
 }
 
-extern  void inline writereg(struct net_device *dev, int portno, int value)
+extern void inline
+writereg(struct net_device *dev, int portno, int value)
 {
        outw(portno, dev->base_addr + ADD_PORT);
        outw(value, dev->base_addr + DATA_PORT);
 }
 
-
-extern int inline readword(struct net_device *dev, int portno)
+extern int inline
+readword(struct net_device *dev, int portno)
 {
        return inw(dev->base_addr + portno);
 }
 
-extern void inline writeword(struct net_device *dev, int portno, int value)
+extern void inline
+writeword(struct net_device *dev, int portno, int value)
 {
        outw(value, dev->base_addr + portno);
 }
 
-static int __init wait_eeprom_ready(struct net_device *dev)
+static int __init
+wait_eeprom_ready(struct net_device *dev)
 {
        int timeout = jiffies;
        /* check to see if the EEPROM is ready, a timeout is used -
@@ -197,7 +262,8 @@ static int __init wait_eeprom_ready(struct net_device *dev)
        return 0;
 }
 
-static int __init get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
+static int __init
+get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
 {
        int i;
 
@@ -214,7 +280,8 @@ static int __init get_eeprom_data(struct net_device *dev, int off, int len, int
         return 0;
 }
 
-static int  __init  get_eeprom_cksum(int off, int len, int *buffer)
+static int  __init
+get_eeprom_cksum(int off, int len, int *buffer)
 {
        int i, cksum;
 
@@ -229,19 +296,28 @@ static int  __init  get_eeprom_cksum(int off, int len, int *buffer)
 
 /* 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.  */
+   verifies that the correct device exists and functions.
+   Return 0 on success.
+ */
 
-static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
+static int __init
+cs89x0_probe1(struct net_device *dev, int ioaddr)
 {
        struct net_local *lp;
        static unsigned version_printed = 0;
        int i;
        unsigned rev_type = 0;
        int eeprom_buff[CHKSUM_LEN];
+       int retval;
 
        /* Initialize the device structure. */
        if (dev->priv == NULL) {
                dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+               if (dev->priv == 0)
+               {
+                       retval = ENOMEM;
+                       goto out;
+               }
                 memset(dev->priv, 0, sizeof(struct net_local));
         }
        lp = (struct net_local *)dev->priv;
@@ -257,7 +333,10 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
        }
 
        if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
-               return ENODEV;
+       {
+               retval = ENODEV;
+               goto out1;
+       }
 
        /* Fill in the 'dev' fields. */
        dev->base_addr = ioaddr;
@@ -278,7 +357,7 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
        if (net_debug  &&  version_printed++ == 0)
                printk(version);
 
-       printk("%s: cs89%c0%s rev %c found at %#3lx",
+       printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ",
               dev->name,
               lp->chip_type==CS8900?'0':'2',
               lp->chip_type==CS8920M?"M":"",
@@ -289,11 +368,11 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
 
        /* 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");
+               printk(KERN_WARNING "\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");
+               printk(KERN_WARNING "\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, relying on command line\n");
+                printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying 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];
@@ -301,16 +380,36 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
                 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;
+
+                /* eeprom_buff has 32-bit ints, so we can't just memcpy it */
+                /* store the initial memory base address */
                 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;
                 }
         }
 
+        /* allow them to force multiple transceivers.  If they force multiple, autosense */
+        {
+               int count = 0;
+               if (lp->force & FORCE_RJ45)     {lp->adapter_cnf |= A_CNF_10B_T; count++; }
+               if (lp->force & FORCE_AUI)      {lp->adapter_cnf |= A_CNF_AUI; count++; }
+               if (lp->force & FORCE_BNC)      {lp->adapter_cnf |= A_CNF_10B_2; count++; }
+               if (count > 1)                  {lp->adapter_cnf |= A_CNF_MEDIA_AUTO; }
+               else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; }
+               else if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_MEDIA_AUI; }
+               else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; }
+        }
+
+        /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
 
-       printk(" media %s%s%s",
+        /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
+
+        /* FIXME: we don't set the Ethernet address on the command line.  Use
+           ifconfig IFACE hw ether AABBCCDDEEFF */
+
+       printk(KERN_INFO "cs89x0 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,":"");
@@ -353,14 +452,33 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
                        dev->irq = i;
        }
 
-       printk(" IRQ %d", dev->irq);
+       printk(", IRQ %d", dev->irq);
 
+#if ALLOW_DMA
+       if (lp->use_dma)
+       {
+               get_dma_channel(dev);
+               printk(", DMA %d", dev->dma);
+       }
+       else
+#endif
+       {
+               printk(", programmed I/O");
+       }
 
        /* print the ethernet address. */
+       printk(", MAC ");
        for (i = 0; i < ETH_ALEN; i++)
-               printk(" %2.2x", dev->dev_addr[i]);
+       {
+               printk("%s%02x", i ? ":" : "", dev->dev_addr[i]);
+       }
 
        /* Grab the region so we can find another board if autoIRQ fails. */
+
+       /*
+        * FIXME: we should check this, but really the isapnp stuff should have given
+        * us a free region.  Sort this out when the isapnp is sorted out
+        */
        request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0");
 
        dev->open               = net_open;
@@ -376,11 +494,188 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
        ether_setup(dev);
 
        printk("\n");
+       if (net_debug)
+               printk("cs89x0_probe1() successful\n");
        return 0;
+out1:
+       kfree(dev->priv);
+       dev->priv = 0;
+out:
+       return retval;
+}
+
+\f
+/*********************************
+ * This page contains DMA routines
+**********************************/
+
+#if ALLOW_DMA
+
+#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
+
+static void
+get_dma_channel(struct net_device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if (lp->dma) {
+               dev->dma = lp->dma;
+               lp->isa_config |= ISA_RxDMA;
+       } else {
+               if ((lp->isa_config & ANY_ISA_DMA) == 0)
+                       return;
+               dev->dma = lp->isa_config & DMA_NO_MASK;
+               if (lp->chip_type == CS8900)
+                       dev->dma += 5;
+               if (dev->dma < 5 || dev->dma > 7) {
+                       lp->isa_config &= ~ANY_ISA_DMA;
+                       return;
+               }
+       }
+       return;
+}
+
+static void
+write_dma(struct net_device *dev, int chip_type, int dma)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       if ((lp->isa_config & ANY_ISA_DMA) == 0)
+               return;
+       if (chip_type == CS8900) {
+               writereg(dev, PP_CS8900_ISADMA, dma-5);
+       } else {
+               writereg(dev, PP_CS8920_ISADMA, dma);
+       }
+}
+
+static void
+set_dma_cfg(struct net_device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if (lp->use_dma)
+       {
+               if ((lp->isa_config & ANY_ISA_DMA) == 0)
+               {
+                       if (net_debug > 3)
+                               printk("set_dma_cfg(): no DMA\n");
+                       return;
+               }
+               if (lp->isa_config & ISA_RxDMA)
+               {
+                       lp->curr_rx_cfg |= RX_DMA_ONLY;
+                       if (net_debug > 3)
+                               printk("set_dma_cfg(): RX_DMA_ONLY\n");
+               }
+               else
+               {
+                       lp->curr_rx_cfg |= AUTO_RX_DMA; /* not that we support it... */
+                       if (net_debug > 3)
+                               printk("set_dma_cfg(): AUTO_RX_DMA\n");
+               }
+       }
+}
+
+static int
+dma_bufcfg(struct net_device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       if (lp->use_dma)
+               return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0;
+       else
+               return 0;
+}
+
+static int
+dma_busctl(struct net_device *dev)
+{
+       int retval = 0;
+       struct net_local *lp = (struct net_local *)dev->priv;
+       if (lp->use_dma)
+       {
+               if (lp->isa_config & ANY_ISA_DMA)
+                       retval |= RESET_RX_DMA; /* Reset the DMA pointer */
+               if (lp->isa_config & DMA_BURST)
+                       retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */
+               if (lp->dmasize == 64)
+                       retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */
+               retval |= MEMORY_ON;    /* we need memory enabled to use DMA. */
+       }
+       return retval;
+}
+
+static void
+dma_rx(struct net_device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       struct sk_buff *skb;
+       int status, length;
+       unsigned char *bp = lp->rx_dma_ptr;
+
+       {
+               int i;
+               for (i = 0; i < 1000; i++)
+                       ;
+       }
+
+       status = bp[0] + (bp[1]<<8);
+       length = bp[2] + (bp[3]<<8);
+       bp += 4;
+       if (net_debug > 5)
+       {
+               printk( "%s: receiving DMA packet at %lx, status %x, length %x\n",
+                       dev->name, (unsigned long)bp, status, length);
+       }
+       if ((status & RX_OK) == 0) {
+               count_rx_errors(status, lp);
+               goto skip_this_frame;
+       }
+
+       /* Malloc up new buffer. */
+       skb = alloc_skb(length, GFP_ATOMIC);
+       if (skb == NULL) {
+               if (net_debug)  /* I don't think we want to do this to a stressed system */
+                       printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+               lp->stats.rx_dropped++;
+
+               /* AKPM: advance bp to the next frame */
+skip_this_frame:
+               bp += (length + 3) & ~3;
+               if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024;
+               lp->rx_dma_ptr = bp;
+               return;
+       }
+
+       skb->len = length;
+       skb->dev = dev;
+
+       if (bp + length > lp->end_dma_buff) {
+               int semi_cnt = lp->end_dma_buff - bp;
+               memcpy(skb_put(skb,semi_cnt), bp, semi_cnt);
+               memcpy(skb_put(skb,length - semi_cnt), lp->dma_buff,
+                      length - semi_cnt);
+       } else {
+               memcpy(skb_put(skb,length), bp, length);
+       }
+       bp += (length + 3) & ~3;
+       if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024;
+       lp->rx_dma_ptr = bp;
+
+       if (net_debug > 3)
+       {
+               printk( "%s: received %d byte DMA packet of type %x\n",
+                       dev->name, length,
+                       (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+       }
+        skb->protocol=eth_type_trans(skb,dev);
+       netif_rx(skb);
+       lp->stats.rx_packets++;
+       return;
 }
 
-void  __init 
-reset_chip(struct net_device *dev)
+#endif /* ALLOW_DMA */
+
+void  __init reset_chip(struct net_device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        int ioaddr = dev->base_addr;
@@ -399,8 +694,8 @@ reset_chip(struct net_device *dev)
                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);
+               outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT);
+               outb((dev->mem_start >> 8) & 0xff,   ioaddr + DATA_PORT + 1);
        }
        /* Wait until the chip is reset */
        reset_start_time = jiffies;
@@ -430,11 +725,18 @@ control_dc_dc(struct net_device *dev, int on_not_off)
 
 }
 
+#define DETECTED_NONE  0
+#define DETECTED_RJ45H 1
+#define DETECTED_RJ45F 2
+#define DETECTED_AUI   3
+#define DETECTED_BNC   4
+
 static int
 detect_tp(struct net_device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
        int timenow = jiffies;
+       int fdx;
 
        if (net_debug > 1) printk("%s: Attempting TP\n", dev->name);
 
@@ -450,35 +752,63 @@ detect_tp(struct net_device *dev)
        for (timenow = jiffies; jiffies - timenow < 15; )
                 ;
        if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
-               return 0;
-
-       if (lp->chip_type != CS8900) {
+               return DETECTED_NONE;
+
+       if (lp->chip_type == CS8900) {
+                switch (lp->force & 0xf0) {
+#if 0
+                case FORCE_AUTO:
+                       printk("%s: cs8900 doesn't autonegotiate\n",dev->name);
+                        return DETECTED_NONE;
+#endif
+               /* CS8900 doesn't support AUTO, change to HALF*/
+                case FORCE_AUTO:
+                       lp->force &= ~FORCE_AUTO;
+                        lp->force |= FORCE_HALF;
+                       break;
+               case FORCE_HALF:
+                       break;
+                case FORCE_FULL:
+                       writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900);
+                       break;
+                }
+               fdx = readreg(dev, PP_TestCTL) & FDX_8900;
+       } else {
+               switch (lp->force & 0xf0) {
+               case FORCE_AUTO:
+                       lp->auto_neg_cnf = AUTO_NEG_ENABLE;
+                       break;
+               case FORCE_HALF:
+                       lp->auto_neg_cnf = 0;
+                       break;
+               case FORCE_FULL:
+                       lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX;
+                       break;
+                }
 
                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);
+                       printk(KERN_INFO "%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");
+                                       printk(KERN_ERR "**** 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);
+               fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE;
        }
-
-       return A_CNF_MEDIA_10B_T;
+       if (fdx)
+               return DETECTED_RJ45F;
+       else
+               return DETECTED_RJ45H;
 }
 
 /* send a test packet - return true if carrier bits are ok */
 static int
 send_test_pkt(struct net_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 */
@@ -490,8 +820,8 @@ send_test_pkt(struct net_device *dev)
        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);
+        writeword(dev, TX_CMD_PORT, TX_AFTER_ALL);
+        writeword(dev, TX_LEN_PORT, ETH_ZLEN);
 
        /* Test to see if the chip has allocated memory for the packet */
        while (jiffies - timenow < 5)
@@ -501,11 +831,7 @@ send_test_pkt(struct net_device *dev)
                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);
-       }
+       outsw(dev->base_addr + 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 */
@@ -531,9 +857,9 @@ detect_aui(struct net_device *dev)
        writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
 
        if (send_test_pkt(dev))
-               return A_CNF_MEDIA_AUI;
+               return DETECTED_AUI;
        else
-               return 0;
+               return DETECTED_NONE;
 }
 
 static int
@@ -547,9 +873,9 @@ detect_bnc(struct net_device *dev)
        writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
 
        if (send_test_pkt(dev))
-               return A_CNF_MEDIA_10B_2;
+               return DETECTED_BNC;
        else
-               return 0;
+               return DETECTED_NONE;
 }
 
 \f
@@ -579,6 +905,9 @@ write_irq(struct net_device *dev, int chip_type, int irq)
    registers that "should" only need to be set once at boot, so that
    there is non-reboot way to recover if something goes wrong.
    */
+
+/* AKPM: do we need to do any locking here? */
+
 static int
 net_open(struct net_device *dev)
 {
@@ -588,9 +917,15 @@ net_open(struct net_device *dev)
 
        if (dev->irq < 2) {
                /* Allow interrupts to be generated by the chip */
+/* Cirrus' release had this: */
+#if 0
+               writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
+#endif
+/* And 2.3.47 had this: */
                writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+
                for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {
-                       if (request_irq (i, NULL, 0, "cs8920", dev) != -EBUSY) {
+                       if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) {
                                write_irq(dev, lp->chip_type, i);
                                writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
                                if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0)
@@ -601,21 +936,74 @@ net_open(struct net_device *dev)
 
                if (i >= CS8920_NO_INTS) {
                        writereg(dev, PP_BusCTL, 0);    /* disable interrupts. */
+                       if (net_debug)
+                               printk("cs89x0: can't get an interrupt\n");
                        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",
+                       printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
                        return -EAGAIN;
                }
+/* FIXME: Cirrus' release had this: */
+               writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
+/* And 2.3.47 had this: */
+#if 0
                writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+#endif
                write_irq(dev, lp->chip_type, dev->irq);
                if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) {
+                       if (net_debug)
+                               printk("cs89x0: request_irq(%d) failed\n", dev->irq);
                        return -EAGAIN;
                }
        }
 
+#if ALLOW_DMA
+       if (lp->use_dma)
+       {
+               if (lp->isa_config & ANY_ISA_DMA) {
+                       unsigned long flags;
+                       lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
+                                                       (lp->dmasize * 1024) / PAGE_SIZE);
+
+                       if (!lp->dma_buff) {
+                               printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize);
+                               goto release_irq;
+                       }
+                       if (net_debug > 1)
+                       {
+                               printk( "%s: dma %lx %lx\n",
+                                       dev->name,
+                                       (unsigned long)lp->dma_buff,
+                                       (unsigned long)virt_to_bus(lp->dma_buff));
+                       }
+                       if ((unsigned long)virt_to_bus(lp->dma_buff) >= MAX_DMA_ADDRESS ||
+                           !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) {
+                               printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name);
+                               goto release_irq;
+                       }
+                       memset(lp->dma_buff, 0, lp->dmasize * 1024);    /* Why? */
+                       if (request_dma(dev->dma, "cs89x0")) {
+                               printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);
+                               goto release_irq;
+                       }
+                       write_dma(dev, lp->chip_type, dev->dma);
+                       lp->rx_dma_ptr = lp->dma_buff;
+                       lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024;
+                       spin_lock_irqsave(&lp->lock, flags);
+                       disable_dma(dev->dma);
+                       clear_dma_ff(dev->dma);
+                       set_dma_mode(dev->dma, 0x14); /* auto_init as well */
+                       set_dma_addr(dev->dma, virt_to_bus(lp->dma_buff));
+                       set_dma_count(dev->dma, lp->dmasize*1024);
+                       enable_dma(dev->dma);
+                       spin_unlock_irqrestore(&lp->lock, flags);
+               }
+       }
+#endif /* ALLOW_DMA */
+
        /* 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));
@@ -637,8 +1025,11 @@ net_open(struct net_device *dev)
         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);
+                printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
+#if ALLOW_DMA
+               release_dma_buff(lp);
+#endif
                 writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
                 free_irq(dev->irq, dev);
                return -EAGAIN;
@@ -648,43 +1039,58 @@ net_open(struct net_device *dev)
        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 */
+                if (result==DETECTED_NONE) {
+                        printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name);
+                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                                result = DETECTED_RJ45H; /* 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 */
+                if (result==DETECTED_NONE) {
+                        printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name);
+                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                                result = DETECTED_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 */
+                if (result==DETECTED_NONE) {
+                        printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name);
+                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                                result = DETECTED_BNC; /* 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)
+                       if ((result = detect_tp(dev)) != DETECTED_NONE)
                                break;
                if (lp->adapter_cnf & A_CNF_AUI)
-                       if ((result = detect_aui(dev)) != 0)
+                       if ((result = detect_aui(dev)) != DETECTED_NONE)
                                break;
                if (lp->adapter_cnf & A_CNF_10B_2)
-                       if ((result = detect_bnc(dev)) != 0)
+                       if ((result = detect_bnc(dev)) != DETECTED_NONE)
                                break;
-               printk("%s: no media detected\n", dev->name);
+               printk(KERN_ERR "%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);
+       case DETECTED_NONE:
+               printk(KERN_ERR "%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;
+       case DETECTED_RJ45H:
+               printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
+               break;
+       case DETECTED_RJ45F:
+               printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);
+               break;
+       case DETECTED_AUI:
+               printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name);
+               break;
+       case DETECTED_BNC:
+               printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name);
+               break;
        }
 
        /* Turn on both receive and transmit operations */
@@ -695,22 +1101,34 @@ net_open(struct net_device *dev)
        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;
-
+#if ALLOW_DMA
+       set_dma_cfg(dev);
+#endif
        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);
+               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);
+#if ALLOW_DMA
+               dma_bufcfg(dev) |
+#endif
+               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->mem_start?MEMORY_ON : 0) /* turn memory on */
+#if ALLOW_DMA
+                | dma_busctl(dev)
+#endif
                  );
         MOD_INC_USE_COUNT;
         netif_start_queue(dev);
+       if (net_debug)
+               printk("cs89x0: net_open() succeeded\n");
        return 0;
 }
 
@@ -727,39 +1145,54 @@ static void net_timeout(struct net_device *dev)
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       short ioaddr = dev->base_addr;
-       unsigned long flags;
 
        if (net_debug > 3)
-               printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+       {
+               printk("%s: sent %d 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();
+       spin_lock_irq(&lp->lock);
        netif_stop_queue(dev);
-       
+
        /* initiate a transmit sequence */
-       outw(lp->send_cmd, ioaddr + TX_CMD_PORT);
-       outw(skb->len, ioaddr + TX_LEN_PORT);
+       writeword(dev, TX_CMD_PORT, lp->send_cmd);
+       writeword(dev, TX_LEN_PORT, skb->len);
 
        /* 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);
+       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.
+                */
+               
+               spin_unlock_irq(&lp->lock);
+               if (net_debug) printk("cs89x0: Tx buffer not free!\n");
                return 1;
        }
        /* Write the contents of the packet */
-        outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
-
-       restore_flags(flags);
+       outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+       spin_unlock_irq(&lp->lock);
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
-       netif_wake_queue(dev);
-       
+
+       /*
+        * We DO NOT call netif_wake_queue() here.
+        * We also DO NOT call netif_start_queue().
+        *
+        * Either of these would cause another bottom half run through
+        * net_send_packet() before this packet has fully gone out.  That causes
+        * us to hit the "Gasp!" above and the send is rescheduled.  it runs like
+        * a dog.  We just return and wait for the Tx completion interrupt handler
+        * to restart the netdevice layer
+        */
+
        return 0;
 }
 \f
@@ -771,7 +1204,7 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        struct net_device *dev = dev_id;
        struct net_local *lp;
        int ioaddr, status;
-
        ioaddr = dev->base_addr;
        lp = (struct net_local *)dev->priv;
 
@@ -792,11 +1225,18 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                case ISQ_TRANSMITTER_EVENT:
                        lp->stats.tx_packets++;
                        netif_wake_queue(dev);  /* 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++;
+                       if ((status & ( TX_OK |
+                                       TX_LOST_CRS |
+                                       TX_SQE_ERROR |
+                                       TX_LATE_COL |
+                                       TX_16_COL)) != TX_OK)
+                       {
+                               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) {
@@ -819,6 +1259,22 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                                   event of a tx underrun */
                                netif_wake_queue(dev);  /* Inform upper layers. */
                         }
+#if ALLOW_DMA
+                       if (lp->use_dma && (status & RX_DMA)) {
+                               int count = readreg(dev, PP_DmaFrameCnt);
+                               while(count) {
+                                       if (net_debug > 5)
+                                               printk("%s: receiving %d DMA frames\n", dev->name, count);
+                                       if (net_debug > 2 && count >1)
+                                               printk("%s: receiving %d DMA frames\n", dev->name, count);
+                                       dma_rx(dev);
+                                       if (--count == 0)
+                                               count = readreg(dev, PP_DmaFrameCnt);
+                                       if (net_debug > 2 && count > 0)
+                                               printk("%s: continuing with %d DMA frames\n", dev->name, count);
+                               }
+                       }
+#endif
                        break;
                case ISQ_RX_MISS_EVENT:
                        lp->stats.rx_missed_errors += (status >>6);
@@ -830,45 +1286,58 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        }
 }
 
+static void
+count_rx_errors(int status, struct net_local *lp)
+{
+       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;
+}
+
 /* We have a good packet(s), get it/them out of the buffers. */
 static void
 net_rx(struct net_device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       int ioaddr = dev->base_addr;
        struct sk_buff *skb;
        int status, length;
 
+       int ioaddr = dev->base_addr;
        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++;
+               count_rx_errors(status, lp);
                return;
        }
 
        /* Malloc up new buffer. */
        skb = alloc_skb(length, GFP_ATOMIC);
        if (skb == NULL) {
-               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+#if 0          /* Again, this seems a cruel thing to do */
+               printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+#endif
                lp->stats.rx_dropped++;
                return;
        }
        skb->len = length;
        skb->dev = dev;
 
-        insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
+       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 (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]);
+       }
 
         skb->protocol=eth_type_trans(skb,dev);
        netif_rx(skb);
@@ -877,10 +1346,23 @@ net_rx(struct net_device *dev)
        return;
 }
 
+#if ALLOW_DMA
+static void release_dma_buff(struct net_local *lp)
+{
+       if (lp->dma_buff)
+       {
+               free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE);
+               lp->dma_buff = 0;
+       }
+}
+#endif
+
 /* The inverse routine to net_open(). */
 static int
 net_close(struct net_device *dev)
 {
+       struct net_local *lp = (struct net_local *)dev->priv;
+
        netif_stop_queue(dev);
        
        writereg(dev, PP_RxCFG, 0);
@@ -890,11 +1372,16 @@ net_close(struct net_device *dev)
 
        free_irq(dev->irq, dev);
 
-       /* Update the statistics here. */
+#if ALLOW_DMA
+       if (lp->use_dma && lp->dma) {
+               free_dma(dev->dma);
+               release_dma_buff(lp);
+       }
+#endif
 
+       /* Update the statistics here. */
         MOD_DEC_USE_COUNT;
        return 0;
-
 }
 
 /* Get the current statistics. This may be called with the card open or
@@ -903,12 +1390,13 @@ static struct net_device_stats *
 net_get_stats(struct net_device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned long flags;
 
-       cli();
+       spin_lock_irqsave(&lp->lock, flags);
        /* 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();
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        return &lp->stats;
 }
@@ -916,7 +1404,9 @@ net_get_stats(struct net_device *dev)
 static void set_multicast_list(struct net_device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned long flags;
 
+       spin_lock_irqsave(&lp->lock, flags);
        if(dev->flags&IFF_PROMISC)
        {
                lp->rx_mode = RX_ALL_ACCEPT;
@@ -935,18 +1425,23 @@ static void set_multicast_list(struct net_device *dev)
        /* 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));
+       spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 
 static int set_mac_address(struct net_device *dev, void *addr)
 {
        int i;
+
        if (netif_running(dev))
                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");
+       if (net_debug)
+       {
+               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));
@@ -963,17 +1458,31 @@ static struct net_device dev_cs89x0 = {
         0, 0,
         0, 0, 0, NULL, NULL };
 
+/*
+ * Support the 'debug' module parm even if we're compiled for non-debug to 
+ * avoid breaking someone's startup scripts 
+ */
+
 static int io=0;
 static int irq=0;
 static int debug=0;
 static char media[8];
 static int duplex=-1;
 
+static int use_dma = 0;                        /* These generate unused var warnings if ALLOW_DMA = 0 */
+static int dma=0;
+static int dmasize=16;                 /* or 64 */
+
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(media, "s");
 MODULE_PARM(duplex, "i");
+MODULE_PARM(dma , "i");
+MODULE_PARM(dmasize , "i");
+MODULE_PARM(use_dma , "i");
+
+MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>");
 
 EXPORT_NO_SYMBOLS;
 
@@ -1008,15 +1517,34 @@ init_module(void)
 {
        struct net_local *lp;
 
+#if DEBUGGING
        net_debug = debug;
+#endif
         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);
+       if (dev_cs89x0.priv == 0)
+       {
+               printk(KERN_ERR "cs89x0.c: Out of memory.\n");
+               return -ENOMEM;
+       }
        memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
        lp = (struct net_local *)dev_cs89x0.priv;
 
+#if ALLOW_DMA
+       if (use_dma)
+       {
+               lp->use_dma = use_dma;
+               lp->dma = dma;
+               lp->dmasize = dmasize;
+       }
+#endif
+
+       spin_lock_init(&lp->lock);
+
         /* boy, they'd better get these right */
         if (!strcmp(media, "rj45"))
                lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
@@ -1031,12 +1559,20 @@ init_module(void)
                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");
+                printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n");
+                printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n");
                 return -EPERM;
         }
+
+#if ALLOW_DMA
+       if (use_dma && dmasize != 16 && dmasize != 64) {
+               printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize);
+               return -EPERM;
+       }
+#endif
+
         if (register_netdev(&dev_cs89x0) != 0) {
-                printk(KERN_WARNING "cs89x0.c: No card found at 0x%x\n", io);
+                printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);
                 return -ENXIO;
         }
        return 0;
@@ -1045,13 +1581,7 @@ init_module(void)
 void
 cleanup_module(void)
 {
-
-#endif
-#ifdef MODULE
-       outw(0, dev_cs89x0.base_addr + ADD_PORT);
-#endif
-#ifdef MODULE
-
+       outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT);
         if (dev_cs89x0.priv != NULL) {
                 /* Free up the private structure, or leak memory :-)  */
                 unregister_netdev(&dev_cs89x0);
index 7e78805af80ff46f4aace206b2da1212f5e3aa9e..d05ca7a42c50002dc0aeffedcaa66e0bea4c041e 100644 (file)
 #define ENDEC_LOOPBACK 0x0200
 #define AUI_LOOPBACK 0x0400
 #define BACKOFF_OFF 0x0800
+#define FDX_8900 0x4000
 #define FAST_TEST 0x8000
 
 /* PP_RxEvent - Receive Event Bit definition - Read-only */
diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c
deleted file mode 100644 (file)
index a089ed9..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- *     ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
- *              Appletalk-IP to IP Decapsulation driver for Linux
- *
- *     Authors:
- *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *     - DDP-IP Decap by: Jay Schulist <jschlst@turbolinux.com>
- *
- *     Derived from:
- *     - Almost all code already existed in net/appletalk/ddp.c I just
- *       moved/reorginized it into a driver file. Original IP-over-DDP code
- *       was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *      - skeleton.c: A network driver outline for linux.
- *        Written 1993-94 by Donald Becker.
- *     - dummy.c: A dummy net driver. By Nick Holloway.
- *     - MacGate: A user space Daemon for Appletalk-IP Decap for
- *       Linux by Jay Schulist <jschlst@turbolinux.com>
- *
- *      Copyright 1993 United States Government as represented by the
- *      Director, National Security Agency.
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU Public License, incorporated herein by reference.
- */
-
-static const char *version = 
-       "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
-
-#include <linux/config.h>
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/atalk.h>
-#include <linux/ip.h>
-#include <net/route.h>
-#include <linux/inet.h>
-
-#include "ipddp.h"             /* Our stuff */
-
-static struct ipddp_route *ipddp_route_list = NULL;
-
-#ifdef CONFIG_IPDDP_ENCAP
-static int ipddp_mode = IPDDP_ENCAP;
-#else
-static int ipddp_mode = IPDDP_DECAP;
-#endif
-
-/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef IPDDP_DEBUG
-#define IPDDP_DEBUG 1
-#endif
-static unsigned int ipddp_debug = IPDDP_DEBUG;
-
-/* Index to functions, as function prototypes. */
-static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
-static int ipddp_create(struct ipddp_route *new_rt);
-static int ipddp_delete(struct ipddp_route *rt);
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
-static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-
-
-static int ipddp_open(struct net_device *dev)
-{
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
-
-        return 0;
-}
-
-static int ipddp_close(struct net_device *dev)
-{
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
-
-        return 0;
-}
-
-int ipddp_init(struct net_device *dev)
-{
-       static unsigned version_printed = 0;
-
-       if (ipddp_debug && version_printed++ == 0)
-                printk("%s", version);
-
-       /* Let the user now what mode we are in */
-       if(ipddp_mode == IPDDP_ENCAP)
-               printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
-                       dev->name);
-       if(ipddp_mode == IPDDP_DECAP)
-               printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@turbolinux.com>\n", 
-                       dev->name);
-
-       /* Fill in the device structure with ethernet-generic values. */
-        ether_setup(dev);
-
-       /* Initalize the device structure. */
-        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->open           = ipddp_open;
-        dev->stop          = ipddp_close;
-        dev->get_stats      = ipddp_get_stats;
-        dev->do_ioctl       = ipddp_ioctl;
-
-        dev->type = ARPHRD_IPDDP;              /* IP over DDP tunnel */
-        dev->mtu = 585;
-        dev->flags |= IFF_NOARP;
-
-        /*
-         *      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;
-
-        return 0;
-}
-
-/*
- * Get the current statistics. This may be called with the card open or closed.
- */
-static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
-{
-        return (struct net_device_stats *)dev->priv;
-}
-
-/*
- * Transmit LLAP/ELAP frame using aarp_send_ddp.
- */
-static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
-        struct ddpehdr *ddp;
-        struct ipddp_route *rt;
-        struct at_addr *our_addr;
-
-       /*
-         * Find appropriate route to use, based only on IP number.
-         */
-        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
-        {
-                if(rt->ip == paddr)
-                        break;
-        }
-        if(rt == NULL)
-                return 0;
-
-        our_addr = atalk_find_dev_addr(rt->dev);
-
-       if(ipddp_mode == IPDDP_DECAP)
-               /* 
-                * Pull off the excess room that should not be there.
-                * This is due to a hard-header problem. This is the
-                * quick fix for now though, till it breaks.
-                */
-               skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
-
-       /* Create the Extended DDP header */
-       ddp = (struct ddpehdr *)skb->data;
-        ddp->deh_len = skb->len;
-        ddp->deh_hops = 1;
-        ddp->deh_pad = 0;
-        ddp->deh_sum = 0;
-
-       /*
-         * For Localtalk we need aarp_send_ddp to strip the
-         * long DDP header and place a shot DDP header on it.
-         */
-        if(rt->dev->type == ARPHRD_LOCALTLK)
-        {
-                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
-                ddp->deh_snet  = 0;
-        }
-        else
-        {
-                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 */
-        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));        /* fix up length field */
-
-        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
-
-       ((struct net_device_stats *) dev->priv)->tx_packets++;
-        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
-
-        if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
-                dev_kfree_skb(skb);
-
-        return 0;
-}
-
-/*
- * Create a routing entry. We first verify that the
- * record does not already exist. If it does we return -EEXIST
- */
-static int ipddp_create(struct ipddp_route *new_rt)
-{
-        struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
-       struct ipddp_route *test;
-
-        if(rt == NULL)
-                return -ENOMEM;
-
-        rt->ip = new_rt->ip;
-        rt->at = new_rt->at;
-        rt->next = NULL;
-        rt->dev = atrtr_get_dev(&rt->at);
-        if(rt->dev == NULL)
-                return (-ENETUNREACH);
-
-       test = ipddp_find_route(rt);
-       if(test != NULL)
-               return (-EEXIST);
-       
-        rt->next = ipddp_route_list;
-        ipddp_route_list = rt;
-
-        return 0;
-}
-
-/*
- * Delete a route, we only delete a FULL match.
- * If route does not exist we return -ENOENT.
- */
-static int ipddp_delete(struct ipddp_route *rt)
-{
-        struct ipddp_route **r = &ipddp_route_list;
-        struct ipddp_route *tmp;
-
-        while((tmp = *r) != NULL)
-        {
-                if(tmp->ip == rt->ip
-                        && tmp->at.s_net == rt->at.s_net
-                        && tmp->at.s_node == rt->at.s_node)
-                {
-                        *r = tmp->next;
-                        kfree_s(tmp, sizeof(struct ipddp_route));
-                        return 0;
-                }
-                r = &tmp->next;
-        }
-
-        return (-ENOENT);
-}
-
-/*
- * Find a routing entry, we only return a FULL match
- */
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
-{
-        struct ipddp_route *f;
-
-        for(f = ipddp_route_list; f != NULL; f = f->next)
-        {
-                if(f->ip == rt->ip
-                        && f->at.s_net == rt->at.s_net
-                        && f->at.s_node == rt->at.s_node)
-                        return (f);
-        }
-
-        return (NULL);
-}
-
-static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-        struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
-
-        if(!capable(CAP_NET_ADMIN))
-                return -EPERM;
-
-        switch(cmd)
-        {
-               case SIOCADDIPDDPRT:
-                        return (ipddp_create(rt));
-
-                case SIOCFINDIPDDPRT:
-                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
-                                return -EFAULT;
-                        return 0;
-
-                case SIOCDELIPDDPRT:
-                        return (ipddp_delete(rt));
-
-                default:
-                        return -EINVAL;
-        }
-}
-
-#ifdef MODULE  /* Module specific functions for ipddp.c */
-
-static struct net_device dev_ipddp=
-{
-        "ipddp0\0   ",
-                0, 0, 0, 0,
-                0x0, 0,
-                0, 0, 0, NULL, ipddp_init
-};
-
-MODULE_PARM(ipddp_mode, "i");
-
-int init_module(void)
-{
-       int err;
-
-       err=dev_alloc_name(&dev_ipddp, "ipddp%d");
-        if(err < 0)
-                return err;
-
-       if(register_netdev(&dev_ipddp) != 0)
-                return -EIO;
-
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       unregister_netdev(&dev_ipddp);
-        kfree(dev_ipddp.priv);
-       dev_ipddp.priv = NULL;
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/ipddp.h b/drivers/net/ipddp.h
deleted file mode 100644 (file)
index 0729a4d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *     ipddp.h: Header for IP-over-DDP driver for Linux.
- */
-
-#ifndef __LINUX_IPDDP_H
-#define __LINUX_IPDDP_H
-
-#ifdef __KERNEL__
-
-#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
-#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
-#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
-
-struct ipddp_route
-{
-        struct net_device *dev;             /* Carrier device */
-        __u32 ip;                       /* IP address */
-        struct at_addr at;              /* Gateway appletalk address */
-        int flags;
-        struct ipddp_route *next;
-};
-
-#define IPDDP_ENCAP    1
-#define IPDDP_DECAP    2
-
-#endif /* __KERNEL__ */
-#endif /* __LINUX_IPDDP_H */
diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c
deleted file mode 100644 (file)
index e461f88..0000000
+++ /dev/null
@@ -1,1364 +0,0 @@
-/***    ltpc.c -- a driver for the LocalTalk PC card.
- *
- *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU General Public License, incorporated herein by reference.
- *
- *      This is ALPHA code at best.  It may not work for you.  It may
- *      damage your equipment.  It may damage your relations with other
- *      users of your network.  Use it at your own risk!
- *
- *      Based in part on:
- *      skeleton.c      by Donald Becker
- *      dummy.c         by Nick Holloway and Alan Cox
- *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
- *      the netatalk source code (UMICH)
- *      lots of work on the card...
- *
- *      I do not have access to the (proprietary) SDK that goes with the card.
- *      If you do, I don't want to know about it, and you can probably write
- *      a better driver yourself anyway.  This does mean that the pieces that
- *      talk to the card are guesswork on my part, so use at your own risk!
- *
- *      This is my first try at writing Linux networking code, and is also
- *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
- *      welcome suggestions)
- *
- *      This is a loadable kernel module which seems to work at my site
- *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
- *      the kernel support from 1.3.3b2 including patches routing.patch
- *      and ddp.disappears.from.chooser.  In order to run it, you will need
- *      to patch ddp.c and aarp.c in the kernel, but only a little...
- *
- *      I'm fairly confident that while this is arguably badly written, the
- *      problems that people experience will be "higher level", that is, with
- *      complications in the netatalk code.  The driver itself doesn't do
- *      anything terribly complicated -- it pretends to be an ether device
- *      as far as netatalk is concerned, strips the DDP data out of the ether
- *      frame and builds a LLAP packet to send out the card.  In the other
- *      direction, it receives LLAP frames from the card and builds a fake
- *      ether packet that it then tosses up to the networking code.  You can
- *      argue (correctly) that this is an ugly way to do things, but it
- *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
- *
- *      The card will do a lot more than is used here -- I *think* it has the
- *      layers up through ATP.  Even if you knew how that part works (which I
- *      don't) it would be a big job to carve up the kernel ddp code to insert
- *      things at a higher level, and probably a bad idea...
- *
- *      There are a number of other cards that do LocalTalk on the PC.  If
- *      nobody finds any insurmountable (at the netatalk level) problems
- *      here, this driver should encourage people to put some work into the
- *      other cards (some of which I gather are still commercially available)
- *      and also to put hooks for LocalTalk into the official ddp code.
- *
- *      I welcome comments and suggestions.  This is my first try at Linux
- *      networking stuff, and there are probably lots of things that I did
- *      suboptimally.  
- *
- ***/
-
-/***
- *
- * $Log: ltpc.c,v $
- * Revision 1.8  1997/01/28 05:44:54  bradford
- * Clean up for non-module a little.
- * Hacked about a bit to clean things up - Alan Cox 
- * Probably broken it from the origina 1.8
- *
-
- * 1998/11/09: David Huggins-Daines <dhd@debian.org>
- * Cleaned up the initialization code to use the standard autoirq methods,
-   and to probe for things in the standard order of i/o, irq, dma.  This
-   removes the "reset the reset" hack, because I couldn't figure out an
-   easy way to get the card to trigger an interrupt after it.
- * Added support for passing configuration parameters on the kernel command
-   line and through insmod
- * Changed the device name from "ltalk0" to "lt0", both to conform with the
-   other localtalk driver, and to clear up the inconsistency between the
-   module and the non-module versions of the driver :-)
- * Added a bunch of comments (I was going to make some enums for the state
-   codes and the register offsets, but I'm still not sure exactly what their
-   semantics are)
- * Don't poll anymore in interrupt-driven mode
- * It seems to work as a module now (as of 2.1.127), but I don't think
-   I'm responsible for that...
-
- *
- * 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
-
-static int io=0;
-static int irq=0;
-static int dma=0;
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>
-
-#include <linux/delay.h>
-#include <linux/timer.h>
-
-#include <linux/atalk.h>
-
-/* our stuff */
-#include "ltpc.h"
-
-/* function prototypes */
-static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
-       void *dbuf, int dbuflen);
-static int sendup_buffer (struct net_device *dev);
-
-/* Dma Memory related stuff, cribbed directly from 3c505.c */
-
-static unsigned long dma_mem_alloc(int size)
-{
-        int order = get_order(size);
-
-        return __get_dma_pages(GFP_KERNEL, order);
-}
-
-/* DMA data buffer, DMA command buffer */
-static unsigned char *ltdmabuf;
-static unsigned char *ltdmacbuf;
-
-/* private struct, holds our appletalk address */
-
-struct ltpc_private
-{
-       struct net_device_stats stats;
-       struct at_addr my_addr;
-};
-
-/* transmit queue element struct */
-
-struct xmitQel {
-       struct xmitQel *next;
-       /* command buffer */
-       unsigned char *cbuf;
-       short cbuflen;
-       /* data buffer */
-       unsigned char *dbuf;
-       short dbuflen;
-       unsigned char QWrite;   /* read or write data */
-       unsigned char mailbox;
-};
-
-/* the transmit queue itself */
-
-static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
-
-static void enQ(struct xmitQel *qel)
-{
-       unsigned long flags;
-       qel->next = NULL;
-       save_flags(flags);
-       cli();
-       if (xmQtl) {
-               xmQtl->next = qel;
-       } else {
-               xmQhd = qel;
-       }
-       xmQtl = qel;
-       restore_flags(flags);
-
-       if (debug&DEBUG_LOWER)
-               printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
-}
-
-static struct xmitQel *deQ(void)
-{
-       unsigned long flags;
-       int i;
-       struct xmitQel *qel=NULL;
-       save_flags(flags);
-       cli();
-       if (xmQhd) {
-               qel = xmQhd;
-               xmQhd = qel->next;
-               if(!xmQhd) xmQtl = NULL;
-       }
-       restore_flags(flags);
-
-       if ((debug&DEBUG_LOWER) && qel) {
-               int n;
-               printk("ltpc: dequeued command ");
-               n = qel->cbuflen;
-               if (n>100) n=100;
-               for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
-               printk("\n");
-       }
-
-       return qel;
-}
-
-/* and... the queue elements we'll be using */
-static struct xmitQel qels[16];
-
-/* and their corresponding mailboxes */
-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 net_device *dev, int c)
-{
-       /* returns true if it stayed c */
-       /* this uses base+6, but it's ok */
-       int i;
-       int timeout;
-
-       /* twenty second or so total */
-
-       for(i=0;i<20000;i++) {
-               if ( c != inb_p(dev->base_addr+6) ) return 0;
-               for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
-       }
-       return 1; /* timed out */
-}
-
-/* get the first free mailbox */
-
-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;
-}
-
-/* read a command from the card */
-static void handlefc(struct net_device *dev)
-{
-       /* called *only* from idle, non-reentrant */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-
-       flags=claim_dma_lock();
-       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);
-       release_dma_lock(flags);
-
-       inb_p(base+3);
-       inb_p(base+2);
-
-       if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
-}
-
-/* read data from the card */
-static void handlefd(struct net_device *dev)
-{
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-       flags=claim_dma_lock();
-       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);
-       release_dma_lock(flags);
-
-       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 net_device *dev)
-{
-       /* called *only* from idle, non-reentrant */
-       /* on entry, 0xfb and ltdmabuf holds data */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-       
-       flags=claim_dma_lock();
-       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);
-       release_dma_lock(flags);
-       
-       inb_p(base+3);
-       inb_p(base+2);
-
-       if ( wait_timeout(dev,0xfb) ) {
-               flags=claim_dma_lock();
-               printk("timed out in handlewrite, dma res %d\n",
-                       get_dma_residue(dev->dma) );
-               release_dma_lock(flags);
-       }
-}
-
-static void handleread(struct net_device *dev)
-{
-       /* on entry, 0xfb */
-       /* on exit, ltdmabuf holds data */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-       
-       flags=claim_dma_lock();
-       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);
-       release_dma_lock(flags);
-
-       inb_p(base+3);
-       inb_p(base+2);
-       if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
-}
-
-static void handlecommand(struct net_device *dev)
-{
-       /* on entry, 0xfa and ltdmacbuf holds command */
-       int dma = dev->dma;
-       int base = dev->base_addr;
-       unsigned long flags;
-
-       flags=claim_dma_lock();
-       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);
-       release_dma_lock(flags);
-       inb_p(base+3);
-       inb_p(base+2);
-       if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
-} 
-
-/* ready made command for getting the result from the card */
-static unsigned char rescbuf[2] = {LT_GETRESULT,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 net_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 base = dev->base_addr;
-
-       save_flags(flags);
-       cli();
-       if(QInIdle) {
-               restore_flags(flags);
-               return;
-       }
-       QInIdle = 1;
-
-
-       restore_flags(flags);
-
-       /* this tri-states the IRQ line */
-       (void) inb_p(base+6);
-
-       oops = 100;
-
-loop:
-       if (0>oops--) { 
-               printk("idle: looped too many times\n");
-               goto done;
-       }
-
-       state = inb_p(base+6);
-       if (state != inb_p(base+6)) goto loop;
-
-       switch(state) {
-               case 0xfc:
-                       /* incoming command */
-                       if (debug&DEBUG_LOWER) printk("idle: fc\n");
-                       handlefc(dev); 
-                       break;
-               case 0xfd:
-                       /* incoming data */
-                       if(debug&DEBUG_LOWER) printk("idle: fd\n");
-                       handlefd(dev); 
-                       break;
-               case 0xf9:
-                       /* result ready */
-                       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:
-                       /* waiting for command */
-                       if(debug&DEBUG_LOWER) printk("idle: fa\n");
-                       if (xmQhd) {
-                               q=deQ();
-                               memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
-                               ltdmacbuf[1] = q->mailbox;
-                               if (debug>1) { 
-                                       int n;
-                                       printk("ltpc: sent command     ");
-                                       n = q->cbuflen;
-                                       if (n>100) n=100;
-                                       for(i=0;i<n;i++)
-                                               printk("%02x ",ltdmacbuf[i]);
-                                       printk("\n");
-                               }
-                               handlecommand(dev);
-                                       if(0xfa==inb_p(base+6)) {
-                                               /* we timed out, so return */
-                                               goto done;
-                                       } 
-                       } else {
-                               /* we don't seem to have a command */
-                               if (!mboxinuse[0]) {
-                                       mboxinuse[0] = 1;
-                                       qels[0].cbuf = rescbuf;
-                                       qels[0].cbuflen = 2;
-                                       qels[0].dbuf = resdbuf;
-                                       qels[0].dbuflen = 2;
-                                       qels[0].QWrite = 0;
-                                       qels[0].mailbox = 0;
-                                       enQ(&qels[0]);
-                               } else {
-                                       printk("trouble: response command already queued\n");
-                                       goto done;
-                               }
-                       } 
-                       break;
-               case 0Xfb:
-                       /* data transfer ready */
-                       if(debug&DEBUG_LOWER) printk("idle: fb\n");
-                       if(q->QWrite) {
-                               memcpy(ltdmabuf,q->dbuf,q->dbuflen);
-                               handlewrite(dev);
-                       } else {
-                               handleread(dev);
-                               /* non-zero mailbox numbers are for
-                                  commmands, 0 is for GETRESULT
-                                  requests */
-                               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 read takes it out of tri-state (but still high) */
-       /* the second resets it */
-       /* note that after this point, any read of base+6 will
-          trigger an interrupt */
-
-       if (dev->irq) {
-               inb_p(base+7);
-               inb_p(base+7);
-       }
-       return;
-}
-
-
-static int do_write(struct net_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 net_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 net_device *dev);
-static struct net_device_stats *ltpc_get_stats(struct net_device *dev);
-
-static int ltpc_open(struct net_device *dev)
-{
-#ifdef MODULE
-       MOD_INC_USE_COUNT;
-#endif
-       return 0;
-}
-
-static int ltpc_close(struct net_device *dev)
-{
-#ifdef MODULE
-       MOD_DEC_USE_COUNT;
-#endif
-       return 0;
-}
-
-static int read_30 ( struct net_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 net_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);
-}
-
-/* LLAP to DDP translation */
-
-static int sendup_buffer (struct net_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 net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
-       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;
-
-       stats->rx_packets++;
-       stats->rx_bytes+=skb->len;
-
-       /* toss it onwards */
-       netif_rx(skb);
-       return 0;
-}
-
-/* the handler for the board interrupt */
-static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
-{
-       struct net_device *dev = dev_id;
-
-       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 net_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 ltpc_private *)dev->priv)->my_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 net_device *dev)
-{
-       /* This needs to be present to keep netatalk happy. */
-       /* Actually netatalk needs fixing! */
-}
-
-static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, 
-       unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-       if(debug&DEBUG_VERBOSE)
-               printk("ltpc_hard_header called for device %s\n",
-                       dev->name);
-       return 0;
-}
-
-static int ltpc_init(struct net_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->hard_header = ltpc_hard_header;
-
-       dev->priv = kmalloc(sizeof(struct ltpc_private), 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 ltpc_private));
-       dev->get_stats = ltpc_get_stats;
-
-       dev->open = ltpc_open;
-       dev->stop = ltpc_close;
-
-       /* add the ltpc-specific things */
-       dev->do_ioctl = &ltpc_ioctl;
-
-       dev->set_multicast_list = &set_multicast_list;
-       dev->mc_list = NULL;
-
-       return 0;
-}
-
-static int ltpc_poll_counter = 0;
-
-static void ltpc_poll(unsigned long l)
-{
-       struct net_device *dev = (struct net_device *) l;
-
-       del_timer(&ltpc_timer);
-
-       if(debug&DEBUG_VERBOSE) {
-               if (!ltpc_poll_counter) {
-                       ltpc_poll_counter = 50;
-                       printk("ltpc poll is alive\n");
-               }
-               ltpc_poll_counter--;
-       }
-  
-       if (!dev)
-               return;  /* we've been downed */
-
-       idle(dev);
-       ltpc_timer.expires = jiffies+5;
-       
-       add_timer(&ltpc_timer);
-}
-
-/* DDP to LLAP translation */
-
-static int ltpc_xmit(struct sk_buff *skb, struct net_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 ltpc_private *)dev->priv)->stats;
-
-       int i;
-       struct lt_sendlap cbuf;
-
-       cbuf.command = LT_SENDLAP;
-       cbuf.dnode = skb->data[0];
-       cbuf.laptype = skb->data[2];
-       skb_pull(skb,3);        /* skip past LLAP header */
-       cbuf.length = skb->len; /* this is host order */
-       skb->h.raw=skb->data;
-
-       if(debug&DEBUG_UPPER) {
-               printk("command ");
-               for(i=0;i<6;i++)
-                       printk("%02x ",((unsigned char *)&cbuf)[i]);
-               printk("\n");
-       }
-
-       do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
-
-       if(debug&DEBUG_UPPER) {
-               printk("sent %d ddp bytes\n",skb->len);
-               for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
-               printk("\n");
-       }
-
-       stats->tx_packets++;
-       stats->tx_bytes+=skb->len;
-
-       dev_kfree_skb(skb);
-       return 0;
-}
-
-static struct net_device_stats *ltpc_get_stats(struct net_device *dev)
-{
-       struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats;
-       return stats;
-}
-
-/* initialization stuff */
-  
-int __init ltpc_probe_dma(int base)
-{
-       int dma = 0;
-       int timeout;
-       unsigned long f;
-  
-       if (!request_dma(1,"ltpc")) {
-               f=claim_dma_lock();
-               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);
-               release_dma_lock(f);
-               dma|=1;
-       }
-       if (!request_dma(3,"ltpc")) {
-               f=claim_dma_lock();
-               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);
-               release_dma_lock(f);
-               dma|=2;
-       }
-
-       /* set up request */
-
-       /* FIXME -- do timings better! */
-
-       ltdmabuf[0] = LT_READMEM;
-       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(io+1);
-       inb_p(io+0);
-       timeout = jiffies+100*HZ/100;
-       while(time_before(jiffies, timeout)) {
-               if ( 0xfa == inb_p(io+6) ) break;
-       }
-
-       inb_p(io+3);
-       inb_p(io+2);
-       while(time_before(jiffies, timeout)) {
-               if ( 0xfb == inb_p(io+6) ) break;
-       }
-
-       /* release the other dma channel (if we opened both of them) */
-
-       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);
-       }
-
-       /* fix up dma number */
-       dma|=1;
-
-       return dma;
-}
-
-int __init ltpc_probe(struct net_device *dev)
-{
-       int err;
-       int x=0,y=0;
-       int timeout;
-       int autoirq;
-       unsigned long flags;
-       unsigned long f;
-
-       save_flags(flags);
-
-       /* probe for the I/O port address */
-       if (io != 0x240 && !check_region(0x220,8)) {
-               x = inb_p(0x220+6);
-               if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
-       }
-       
-       if (io != 0x220 && !check_region(0x240,8)) {
-               y = inb_p(0x240+6);
-               if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
-       } 
-
-       if(io) {
-               /* found it, now grab it */
-               request_region(io,8,"ltpc");
-       } else {
-               /* give up in despair */
-               printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
-                       x,y);
-               restore_flags(flags);
-               return -1;
-       }
-
-       /* probe for the IRQ line */
-       if (irq < 2) {
-               autoirq_setup(2);
-
-               /* reset the interrupt line */
-               inb_p(io+7);
-               inb_p(io+7);
-               /* trigger an interrupt (I hope) */
-               inb_p(io+6);
-
-               autoirq = autoirq_report(1);
-
-               if (autoirq == 0) {
-                       printk("ltpc: probe at %#x failed to detect IRQ line.\n",
-                               io);
-               }
-               else {
-                       irq = autoirq;
-               }
-       }
-
-       /* allocate a DMA buffer */
-       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-
-       if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
-
-       if (!ltdmabuf) {
-               printk("ltpc: mem alloc failed\n");
-               restore_flags(flags);
-               return(-1);
-       }
-
-       if(debug&DEBUG_VERBOSE) {
-               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
-       }
-
-       /* reset the card */
-
-       inb_p(io+1);
-       inb_p(io+3);
-       timeout = jiffies+2*HZ/100;
-       while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */
-       inb_p(io+0);
-       inb_p(io+2);
-       inb_p(io+7); /* clear reset */
-       inb_p(io+4); 
-       inb_p(io+5);
-       inb_p(io+5); /* enable dma */
-       inb_p(io+6); /* tri-state interrupt line */
-
-       timeout = jiffies+100*HZ/100;
-       
-       while(time_before(jiffies, timeout)) {
-               /* wait for the card to complete initialization */
-       }
-       /* now, figure out which dma channel we're using, unless it's
-          already been specified */
-       /* well, 0 is a legal DMA channel, but the LTPC card doesn't
-          use it... */
-       if (dma == 0) {
-               dma = ltpc_probe_dma(io);
-               if (!dma) {  /* no dma channel */
-                       printk("No DMA channel found on ltpc card.\n");
-                       restore_flags(flags);
-                       return -1;
-               }
-       }
-
-       /* print out friendly message */
-
-       if(irq)
-               printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
-       else
-               printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
-
-       /* seems more logical to do this *after* probing the card... */
-       err = ltpc_init(dev);
-       if (err) return err;
-
-       dev->base_addr = io;
-       dev->irq = irq;
-       dev->dma = dma;
-
-       /* the card will want to send a result at this point */
-       /* (I think... leaving out this part makes the kernel crash,
-           so I put it back in...) */
-
-       f=claim_dma_lock();
-       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);
-       release_dma_lock(f);
-
-       (void) inb_p(io+3);
-       (void) inb_p(io+2);
-       timeout = jiffies+100*HZ/100;
-       while(time_before(jiffies, timeout)) {
-               if( 0xf9 == inb_p(io+6)) break;
-       }
-
-       if(debug&DEBUG_VERBOSE) {
-               printk("setting up timer and irq\n");
-       }
-
-       if (irq) {
-               /* grab it and don't let go :-) */
-               (void) request_irq( irq, &ltpc_interrupt, 0, "ltpc", dev);
-               (void) inb_p(io+7);  /* enable interrupts from board */
-               (void) inb_p(io+7);  /* and reset irq line */
-       } else {
-               /* polled mode -- 20 times per second */
-               /* this is really, really slow... should it poll more often? */
-               init_timer(&ltpc_timer);
-               ltpc_timer.function=ltpc_poll;
-               ltpc_timer.data = (unsigned long) dev;
-
-               ltpc_timer.expires = jiffies + 5;
-               add_timer(&ltpc_timer);
-               restore_flags(flags); 
-       }
-
-       return 0;
-}
-
-/* handles "ltpc=io,irq,dma" kernel command lines */
-static int __init ltpc_setup(char *str)
-{
-       int ints[5];
-
-       str = get_options(str, ARRAY_SIZE(ints), ints);
-
-       if (ints[0] == 0) {
-               if (str && !strncmp(str, "auto", 4)) {
-                       /* do nothing :-) */
-               }
-               else {
-                       /* usage message */
-                       printk (KERN_ERR
-                               "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
-               }
-               return 1;
-       } else {
-               io = ints[1];
-               if (ints[0] > 1) {
-                       irq = ints[2];
-                       return 1;
-               }
-               if (ints[0] > 2) {
-                       dma = ints[3];
-                       return 1;
-               }
-               /* ignore any other paramters */
-       }
-       return 1;
-}
-
-__setup("ltpc=", ltpc_setup);
-
-#ifdef MODULE
-
-static char dev_name[8];
-
-static struct net_device dev_ltpc = {
-               dev_name, 
-               0, 0, 0, 0,
-               0x0, 0,
-               0, 0, 0, NULL, ltpc_probe };
-
-MODULE_PARM(debug, "i");
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(dma, "i");
-
-int init_module(void)
-{
-       int err, result;
-       
-        if(io == 0)
-               printk(KERN_NOTICE
-                      "ltpc: Autoprobing is not recommended for modules\n");
-
-       /* Find a name for this unit */
-       err=dev_alloc_name(&dev_ltpc,"lt%d");
-       
-       if(err<0)
-               return err;
-
-       if ((result = register_netdev(&dev_ltpc)) != 0) {
-               printk(KERN_DEBUG "could not register Localtalk-PC device\n");
-               return result;
-       } 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,&dev_ltpc);
-               dev_ltpc.irq = 0;
-       }
-
-       if(del_timer(&ltpc_timer)) 
-       {
-               /* either the poll was never started, or a poll is in process */
-               if(debug&DEBUG_VERBOSE) printk("waiting\n");
-               /* if it's in process, wait a bit for it to finish */
-               timeout = jiffies+HZ; 
-               add_timer(&ltpc_timer);
-               while(del_timer(&ltpc_timer) && time_after(timeout, jiffies))
-               {
-                       add_timer(&ltpc_timer);
-                       schedule();
-               }
-       }
-
-       if(debug&DEBUG_VERBOSE) printk("freeing dma\n");
-
-       if(dev_ltpc.dma) {
-               free_dma(dev_ltpc.dma);
-               dev_ltpc.dma = 0;
-       }
-
-       if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n");
-
-       if(dev_ltpc.base_addr) {
-               release_region(dev_ltpc.base_addr,8);
-               dev_ltpc.base_addr = 0;
-       }
-
-       if(debug&DEBUG_VERBOSE) printk("free_pages\n");
-
-       free_pages( (unsigned long) ltdmabuf, get_order(1000));
-       ltdmabuf=NULL;
-       ltdmacbuf=NULL;
-
-       if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n");
-
-       unregister_netdev(&dev_ltpc);
-
-       if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ltpc.h b/drivers/net/ltpc.h
deleted file mode 100644 (file)
index cd30544..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/***   ltpc.h
- *
- *
- ***/
-
-#define LT_GETRESULT  0x00
-#define LT_WRITEMEM   0x01
-#define LT_READMEM    0x02
-#define LT_GETFLAGS   0x04
-#define LT_SETFLAGS   0x05
-#define LT_INIT       0x10
-#define LT_SENDLAP    0x13
-#define LT_RCVLAP     0x14
-
-/* the flag that we care about */
-#define LT_FLAG_ALLLAP 0x04
-
-struct lt_getresult {
-       unsigned char command;
-       unsigned char mailbox;
-};
-
-struct lt_mem {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned short addr;    /* host order */
-       unsigned short length;  /* host order */
-};
-
-struct lt_setflags {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned char flags;
-};
-
-struct lt_getflags {
-       unsigned char command;
-       unsigned char mailbox;
-};
-
-struct lt_init {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned char hint;
-};
-
-struct lt_sendlap {
-       unsigned char command;
-       unsigned char mailbox;
-       unsigned char dnode;
-       unsigned char laptype;
-       unsigned short length;  /* host order */
-};
-
-struct lt_rcvlap {
-       unsigned char command;
-       unsigned char dnode;
-       unsigned char snode;
-       unsigned char laptype;
-       unsigned short length;  /* host order */
-};
-
-union lt_command {
-       struct lt_getresult getresult;
-       struct lt_mem mem;
-       struct lt_setflags setflags;
-       struct lt_getflags getflags;
-       struct lt_init init;
-       struct lt_sendlap sendlap;
-       struct lt_rcvlap rcvlap;
-};
-typedef union lt_command lt_command;
-
index 6a8c8b4129a61c320e415ea01d59433d94ea6cbd..f91796d313c0674f0f2e4774b2c0982d07cd35f9 100644 (file)
@@ -1210,9 +1210,6 @@ static int __init ncr885e_probe(void)
        unsigned short cmd;
        unsigned char irq, latency;
 
-       if ( debug >= 0)
-               ncr885e_debug = debug;
-
        while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, 
                                        PCI_DEVICE_ID_NCR_53C885_ETHERNET,
                                        pdev )) != NULL ) {
@@ -1399,9 +1396,6 @@ write_mii( unsigned long ioaddr, int reg, int data )
 int
 init_module(void)
 {
-       if ( debug >= 0)
-               ncr885e_debug = debug;
-
        return ncr885e_probe();
 }
 
index b4fc3e0a8824d4c2993920be5e6b9b39ca0eeea1..96959300f83c7ef213d37ef425ea76f46f8991bf 100644 (file)
 static struct net_device *init_alloc_dev(int sizeof_priv)
 {
        struct net_device *dev;
-       int alloc_size = sizeof(struct net_device) + IFNAMSIZ
-               + sizeof_priv + 3;
-       alloc_size &= ~3;               /* Round to dword boundary. */
-       dev = (struct net_device *)kmalloc(alloc_size, GFP_KERNEL);
-       if(dev==NULL)
+       int alloc_size;
+       
+       /* 32-byte alignment */
+       alloc_size = sizeof (*dev) + IFNAMSIZ + sizeof_priv + 31;
+       alloc_size &= ~31;              
+
+       dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL);
+       if (dev == NULL)
        {
                printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n");
                return NULL;
        }
+
        memset(dev, 0, alloc_size);
+
        if (sizeof_priv)
                dev->priv = (void *) (dev + 1);
+
        dev->name = sizeof_priv + (char *)(dev + 1);
        return dev;
 }
index b7e67fbad134c5e70d3a717d839b11c7295ff31a..31688f34d3de20482997e8756d174b99bcd10e20 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 mainmenu_option next_comment
-comment 'Token Ring driver support'
+comment 'Token Ring devices'
 
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" != "n" ]; then
index 65dfefc702f6dbe9c3a01886e9390bc7e056acba..bf48c15e4de0619c9c94dc981df0b2d669fdd6d1 100644 (file)
@@ -5,73 +5,29 @@
 # 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 inherited from the
-# parent makefile.
-#
 
-#
-# Note : at this point, these files are compiled on all systems.
-# In the future, some of these should be built conditionally.
-#
-
-SUB_DIRS     := 
+SUB_DIRS     :=
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS)
 
+obj-y   :=
+obj-n   :=
+obj-m   :=
+obj-    :=
+export-objs :=
 
-L_TARGET := tr.a
-L_OBJS   := 
-M_OBJS   :=
-
-ifeq ($(CONFIG_IBMTR),y)
-  L_OBJS += ibmtr.o
-else
-  ifeq ($(CONFIG_IBMTR),m)
-    M_OBJS += ibmtr.o
-  endif
-endif
-
-ifeq ($(CONFIG_IBMOL),y)
-  L_OBJS += olympic.o
-else
-  ifeq ($(CONFIG_IBMOL),m)
-    M_OBJS += olympic.o
-  endif
-endif
-
-ifeq ($(CONFIG_TMS380TR),y)
-  L_OBJS += tms380tr.o
-  ifeq ($(CONFIG_ABYSS),y)
-    L_OBJS += abyss.o
-  endif
- ifeq ($(CONFIG_MADGEMC),y)
-    L_OBJS += madgemc.o
-  endif
-  ifeq ($(CONFIG_TMSPCI),y)
-    L_OBJS += tmspci.o
-  endif
-else
-  ifeq ($(CONFIG_TMS380TR),m)
-    M_OBJS += tms380tr.o
-    ifeq ($(CONFIG_ABYSS),m)
-      M_OBJS += abyss.o
-    endif
-    ifeq ($(CONFIG_MADGEMC),m)
-      M_OBJS += madgemc.o
-    endif
-    ifeq ($(CONFIG_TMSPCI),m)
-      M_OBJS += tmspci.o
-    endif
-  endif
-endif
+obj-$(CONFIG_IBMTR)    += ibmtr.o
+obj-$(CONFIG_IBMOL)    += olympic.o
+obj-$(CONFIG_TMS380TR)         += tms380tr.o
+obj-$(CONFIG_ABYSS)    += abyss.o
+obj-$(CONFIG_MADGEMC)  += madgemc.o
+obj-$(CONFIG_TMSPCI)   += tmspci.o
+obj-$(CONFIG_SMCTR)    += smctr.o
 
-ifeq ($(CONFIG_SMCTR),y)
-  L_OBJS += smctr.o
-else
-  ifeq ($(CONFIG_SMCTR),m)
-    M_OBJS += smctr.o
-  endif
-endif
+L_TARGET := tr.a
+L_OBJS   := $(filter-out $(export-objs), $(obj-y))
+LX_OBJS  := $(filter     $(export-objs), $(obj-y))
+M_OBJS   := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS  := $(sort $(filter     $(export-objs), $(obj-m)))
 
 include $(TOPDIR)/Rules.make
-
index abfde3e8a5e4c8acffd489145cea7c7667cc73cf..bbca052e750db7ab96cb7d14fa738c9f629e4e5f 100644 (file)
 
        Support and updates available at
        http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html
+
+
+       Linux kernel version history:
+       
+       LK1.1.0:
+       - Jeff Garzik: softnet 'n stuff
+       
+       LK1.1.1:
+       - Justin Guyett: softnet and locking fixes
+       - Jeff Garzik: use PCI interface
+               
 */
 
 static const char *versionA =
-"via-rhine.c:v1.01 2/27/99  Written by Donald Becker\n";
+"via-rhine.c:v1.01-LK1.1.1  3/2/2000  Written by Donald Becker\n";
 static const char *versionB =
 "  http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
 
@@ -29,7 +40,6 @@ static const char *versionB =
 
 static int debug = 1;                  /* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
@@ -112,7 +122,6 @@ static const int multicast_filter_limit = 32;
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
@@ -157,7 +166,7 @@ buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
 a fresh skbuff is allocated and the frame is copied to the new skbuff.
 When the incoming frame is larger, the skbuff is passed directly up the
 protocol stack.  Buffers consumed this way are replaced by newly allocated
-skbuffs in the last phase of netdev_rx().
+skbuffs in the last phase of via_rhine_rx().
 
 The RX_COPYBREAK value is chosen to trade-off the memory wasted by
 using a full-sized skbuff for small frames vs. the copying costs of larger
@@ -208,34 +217,50 @@ The chip does not pad to minimum transmit length.
 
 */
 
-\f
+
 
 /* This table drives the PCI probe routines.  It's mostly boilerplate in all
    of the drivers, and will likely be provided by some future kernel.
    Note the matching code -- the first table entry matchs all 56** cards but
    second only the 1234 card.
 */
+
 enum pci_flags_bit {
        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
        PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
-struct pci_id_info {
+
+enum via_rhine_chips {
+       vt86c100a = 0,
+       vt3043,
+};
+
+struct via_rhine_chip_info {
        const char *name;
-       u16     vendor_id, device_id, device_id_mask, flags;
+       u16 flags;
        int io_size;
-       struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt);
 };
 
-static struct net_device *via_probe1(struct pci_dev *pdev, long ioaddr, int irq,
-                                                                int chp_idx, int fnd_cnt);
 
-static struct pci_id_info pci_tbl[] = {
-       { "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
-         PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
-       { "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff,
-         PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
-       {0,},                                           /* 0 terminated list. */
+/* directly indexed by enum via_rhine_chips, above */
+static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata =
+{
+       {"VIA VT86C100A Rhine-II",
+        PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
+        128,},
+       {"VIA VT3043 Rhine",
+        PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
+        128,},
+};
+
+static struct pci_device_id via_rhine_pci_tbl[] __devinitdata =
+{
+       {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a},
+       {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043},
+       {0,},                   /* terminate list */
 };
+MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl);
+
 
 
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
@@ -315,16 +340,14 @@ struct netdev_private {
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
        unsigned char *tx_buf[TX_RING_SIZE];    /* Tx bounce buffers */
        unsigned char *tx_bufs;                         /* Tx bounce buffer region. */
-       struct net_device *next_module;                 /* Link for devices of this type. */
        struct net_device_stats stats;
        struct timer_list timer;        /* Media monitoring timer. */
        spinlock_t lock;
        /* Frequently used values: keep some adjacent for cache effect. */
        int chip_id;
-       long in_interrupt;                      /* Word-long for SMP locks. */
        struct rx_desc *rx_head_desc;
-       unsigned int cur_rx, dirty_rx;          /* Producer/consumer ring indices */
-       unsigned int cur_tx, dirty_tx;
+       unsigned short int cur_rx, dirty_rx;            /* Producer/consumer ring indices */
+       unsigned short int cur_tx, dirty_tx;
        unsigned int rx_buf_sz;                         /* Based on MTU+slack. */
        u16 chip_cmd;                                           /* Current setting for ChipCmd */
        unsigned int tx_full:1;                         /* The Tx queue is full. */
@@ -342,136 +365,94 @@ struct netdev_private {
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static int  netdev_open(struct net_device *dev);
-static void check_duplex(struct net_device *dev);
-static void netdev_timer(unsigned long data);
-static void tx_timeout(struct net_device *dev);
-static void init_ring(struct net_device *dev);
-static int  start_tx(struct sk_buff *skb, struct net_device *dev);
-static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-static int  netdev_rx(struct net_device *dev);
-static void netdev_error(struct net_device *dev, int intr_status);
-static void set_rx_mode(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
+static int  via_rhine_open(struct net_device *dev);
+static void via_rhine_check_duplex(struct net_device *dev);
+static void via_rhine_timer(unsigned long data);
+static void via_rhine_tx_timeout(struct net_device *dev);
+static void via_rhine_init_ring(struct net_device *dev);
+static int  via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
+static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void via_rhine_tx(struct net_device *dev);
+static void via_rhine_rx(struct net_device *dev);
+static void via_rhine_error(struct net_device *dev, int intr_status);
+static void via_rhine_set_rx_mode(struct net_device *dev);
+static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int  netdev_close(struct net_device *dev);
-
-\f
+static int  via_rhine_close(struct net_device *dev);
 
-/* A list of our installed devices, for removing the driver module. */
-static struct net_device *root_net_dev = NULL;
 
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   cards we know about in slot order. */
-
-static int pci_etherdev_probe(struct pci_id_info pci_tbl[])
+static int __devinit via_rhine_init_one (struct pci_dev *pdev,
+                                        const struct pci_device_id *ent)
 {
-       int cards_found = 0;
-       int pci_index = 0;
-       unsigned char pci_bus, pci_device_fn;
        struct net_device *dev;
+       struct netdev_private *np;
+       int i, option;
+       int chip_id = (int) ent->driver_data;
+       int irq = pdev->irq;
+       static int card_idx = -1;
+       static int did_version = 0;
+       long ioaddr;
+       int io_size;
+       
+       /* print version once and once only */
+       if (! did_version++) {
+               printk (KERN_INFO "%s", versionA);
+               printk (KERN_INFO "%s", versionB);
+       }
+       
+       card_idx++;
+       option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+       io_size = via_rhine_chip_info[chip_id].io_size;
 
-       for (;pci_index < 0xff; pci_index++) {
-               u16 vendor, device, pci_command, new_command;
-               int chip_idx, irq;
-               long pciaddr;
-               long ioaddr;
-               struct pci_dev *pdev;
-
-               if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-                                                               &pci_bus, &pci_device_fn)
-                       != PCIBIOS_SUCCESSFUL)
-                       break;
-               
-               pdev = pci_find_slot (pci_bus, pci_device_fn);
-               if (!pdev) continue;
-               vendor = pdev->vendor;
-               device = pdev->device;
-
-               for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-                       if (vendor == pci_tbl[chip_idx].vendor_id
-                               && (device & pci_tbl[chip_idx].device_id_mask) ==
-                               pci_tbl[chip_idx].device_id)
-                               break;
-               if (pci_tbl[chip_idx].vendor_id == 0)           /* Compiled out! */
-                       continue;
 
 #ifdef VIA_USE_IO
-               pciaddr = pdev->resource[0].start;
+       ioaddr = pci_resource_start (pdev, 0);
 #else
-               pciaddr = pdev->resource[1].start;
+       ioaddr = pci_resource_start (pdev, 1);
 #endif
-               irq = pdev->irq;
-
-               if (debug > 2)
-                       printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
-                                  pci_tbl[chip_idx].name, pciaddr, irq);
-
-               if (pci_tbl[chip_idx].flags & PCI_USES_IO) {
-                       ioaddr = pciaddr & ~3;
-                       if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-                               continue;
-               } else if ((ioaddr = (long)ioremap(pciaddr & ~0xf,
-                                                                                pci_tbl[chip_idx].io_size)) == 0) {
-                       printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-                                  pciaddr);
-                       continue;
-               }
-
-               pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-               new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-               if (pci_command != new_command) {
-                       printk(KERN_INFO "  The PCI BIOS has not enabled the"
-                                  " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
-                                  pdev->bus->number, pdev->devfn, pci_command, new_command);
-                       pci_write_config_word(pdev, PCI_COMMAND, new_command);
-               }
-
-               dev = pci_tbl[chip_idx].probe1(pdev, ioaddr, irq, chip_idx, cards_found);
 
-               if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-                       u8 pci_latency;
-                       pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-                       if (pci_latency < min_pci_latency) {
-                               printk(KERN_INFO "  PCI latency timer (CFLT) is "
-                                          "unreasonably low at %d.  Setting to %d clocks.\n",
-                                          pci_latency, min_pci_latency);
-                               pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
-                       }
-               }
-               dev = 0;
-               cards_found++;
+       if (pci_enable_device (pdev)) {
+               printk (KERN_ERR "unable to init PCI device (card #%d)\n",
+                       card_idx);
+               goto err_out;
+       }
+       
+       if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER)
+               pci_set_master (pdev);
+
+       dev = init_etherdev(NULL, sizeof (*np));
+       if (dev == NULL) {
+               printk (KERN_ERR "init_ethernet failed for card #%d\n",
+                       card_idx);
+               goto err_out;
+       }
+       
+       if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) {
+               printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n",
+                       dev->name, io_size,
+                       pci_resource_start (pdev, 0));
+               goto err_out_free_netdev;
+       }
+       if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) {
+               printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n",
+                       dev->name, io_size,
+                       pci_resource_start (pdev, 1));
+               goto err_out_free_pio;
        }
 
-       return cards_found ? 0 : -ENODEV;
-}
-
-
-static struct net_device *via_probe1(struct pci_dev *pdev,
-                                        long ioaddr, int irq,
-                                        int chip_id, int card_idx)
-{
-       struct net_device *dev;
-       struct netdev_private *np;
-       int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-
-       dev = init_etherdev(NULL, 0);
-       if(dev==NULL)
-               return NULL;
-
-       printk(KERN_INFO "%s: %s at 0x%lx, ",
-                  dev->name, pci_tbl[chip_id].name, ioaddr);
-
-#ifdef VIA_USE_IO
-       if (!request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name)) {
-               unregister_netdev (dev);
-               kfree (dev);
-               return NULL;
+#ifndef VIA_USE_IO
+       ioaddr = (long) ioremap (ioaddr, io_size);
+       if (!ioaddr) {
+               printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n",
+                       dev->name, io_size,
+                       pci_resource_start (pdev, 1));
+               goto err_out_free_mmio;
        }
 #endif
 
+       printk(KERN_INFO "%s: %s at 0x%lx, ",
+                  dev->name, via_rhine_chip_info[chip_id].name, ioaddr);
+
        /* Ideally we would be read the EEPROM but access may be locked. */
        for (i = 0; i <6; i++)
                dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
@@ -485,16 +466,8 @@ static struct net_device *via_probe1(struct pci_dev *pdev,
        dev->base_addr = ioaddr;
        dev->irq = irq;
 
-       /* Make certain the descriptor lists are cache-aligned. */
-       np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31);
-       /* FIXME! check return !!! */           
-       memset(np, 0, sizeof(*np));
-       dev->priv = np;
-
-       np->next_module = root_net_dev;
-       root_net_dev = dev;
-
-       np->lock = SPIN_LOCK_UNLOCKED;
+       np = dev->priv;
+       spin_lock_init (&np->lock);
        np->chip_id = chip_id;
 
        if (dev->mem_start)
@@ -515,14 +488,16 @@ static struct net_device *via_probe1(struct pci_dev *pdev,
                np->duplex_lock = 1;
 
        /* The chip-specific entries in the device structure. */
-       dev->open = &netdev_open;
-       dev->hard_start_xmit = &start_tx;
-       dev->stop = &netdev_close;
-       dev->get_stats = &get_stats;
-       dev->set_multicast_list = &set_rx_mode;
-       dev->do_ioctl = &mii_ioctl;
-       dev->tx_timeout = tx_timeout;
+       dev->open = via_rhine_open;
+       dev->hard_start_xmit = via_rhine_start_tx;
+       dev->stop = via_rhine_close;
+       dev->get_stats = via_rhine_get_stats;
+       dev->set_multicast_list = via_rhine_set_rx_mode;
+       dev->do_ioctl = mii_ioctl;
+       dev->tx_timeout = via_rhine_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
+       
+       pdev->driver_data = dev;
 
        if (cap_tbl[np->chip_id].flags & CanHaveMII) {
                int phy, phy_idx = 0;
@@ -541,10 +516,25 @@ static struct net_device *via_probe1(struct pci_dev *pdev,
                np->mii_cnt = phy_idx;
        }
 
-       return dev;
+       return 0;
+
+#ifndef VIA_USE_IO
+/* note this is ifdef'd because the ioremap is ifdef'd...
+ * so additional exit conditions above this must move
+ * release_mem_region outside of the ifdef */
+err_out_free_mmio:
+       release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name));
+#endif
+err_out_free_pio:
+       release_region(pci_resource_start (pdev, 0), io_size);
+err_out_free_netdev:
+       unregister_netdev (dev);
+       kfree (dev);
+err_out:
+       return -ENODEV;
 }
 
-\f
+
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
 
 static int mdio_read(struct net_device *dev, int phy_id, int regnum)
@@ -581,8 +571,8 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value
        return;
 }
 
-\f
-static int netdev_open(struct net_device *dev)
+
+static int via_rhine_open(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        long ioaddr = dev->base_addr;
@@ -591,16 +581,16 @@ static int netdev_open(struct net_device *dev)
        /* Reset the chip. */
        writew(CmdReset, ioaddr + ChipCmd);
 
-       if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
+       if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev))
                return -EAGAIN;
 
        if (debug > 1)
-               printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+               printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
                           dev->name, dev->irq);
 
        MOD_INC_USE_COUNT;
 
-       init_ring(dev);
+       via_rhine_init_ring(dev);
 
        writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
        writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
@@ -613,15 +603,14 @@ static int netdev_open(struct net_device *dev)
        /* Configure the FIFO thresholds. */
        writeb(0x20, ioaddr + TxConfig);        /* Initial threshold 32 bytes */
        np->tx_thresh = 0x20;
-       np->rx_thresh = 0x60;                           /* Written in set_rx_mode(). */
+       np->rx_thresh = 0x60;                           /* Written in via_rhine_set_rx_mode(). */
 
        if (dev->if_port == 0)
                dev->if_port = np->default_port;
 
        netif_start_queue(dev);
-       np->in_interrupt = 0;
 
-       set_rx_mode(dev);
+       via_rhine_set_rx_mode(dev);
 
        /* Enable interrupts by setting the interrupt mask. */
        writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
@@ -634,10 +623,10 @@ static int netdev_open(struct net_device *dev)
                np->chip_cmd |= CmdFDuplex;
        writew(np->chip_cmd, ioaddr + ChipCmd);
 
-       check_duplex(dev);
+       via_rhine_check_duplex(dev);
 
        if (debug > 2)
-               printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
+               printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
                           "MII status: %4.4x.\n",
                           dev->name, readw(ioaddr + ChipCmd),
                           mdio_read(dev, np->phys[0], 1));
@@ -646,22 +635,23 @@ static int netdev_open(struct net_device *dev)
        init_timer(&np->timer);
        np->timer.expires = RUN_AT(1);
        np->timer.data = (unsigned long)dev;
-       np->timer.function = &netdev_timer;                             /* timer handler */
+       np->timer.function = &via_rhine_timer;                          /* timer handler */
        add_timer(&np->timer);
 
        return 0;
 }
 
-static void check_duplex(struct net_device *dev)
+static void via_rhine_check_duplex(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        long ioaddr = dev->base_addr;
        int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+       int negotiated = mii_reg5 & np->advertising;
        int duplex;
 
        if (np->duplex_lock  ||  mii_reg5 == 0xffff)
                return;
-       duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+       duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
        if (np->full_duplex != duplex) {
                np->full_duplex = duplex;
                if (debug)
@@ -676,7 +666,7 @@ static void check_duplex(struct net_device *dev)
        }
 }
 
-static void netdev_timer(unsigned long data)
+static void via_rhine_timer(unsigned long data)
 {
        struct net_device *dev = (struct net_device *)data;
        struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -687,41 +677,41 @@ static void netdev_timer(unsigned long data)
                printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
                           dev->name, readw(ioaddr + IntrStatus));
        }
-       check_duplex(dev);
+       via_rhine_check_duplex(dev);
 
        np->timer.expires = RUN_AT(next_tick);
        add_timer(&np->timer);
 }
 
-static void tx_timeout(struct net_device *dev)
+static void via_rhine_tx_timeout (struct net_device *dev)
 {
-       struct netdev_private *np = (struct netdev_private *)dev->priv;
+       struct netdev_private *np = (struct netdev_private *) dev->priv;
        long ioaddr = dev->base_addr;
 
-       printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
-                  "%4.4x, resetting...\n",
-                  dev->name, readw(ioaddr + IntrStatus),
-                  mdio_read(dev, np->phys[0], 1));
+       printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
+               "%4.4x, resetting...\n",
+               dev->name, readw (ioaddr + IntrStatus),
+               mdio_read (dev, np->phys[0], 1));
 
-  /* Perhaps we should reinitialize the hardware here. */
-  dev->if_port = 0;
-  /* Stop and restart the chip's Tx processes . */
+       /* Perhaps we should reinitialize the hardware here. */
+       dev->if_port = 0;
+       /* Stop and restart the chip's Tx processes . */
 
-  /* Trigger an immediate transmit demand. */
+       /* Trigger an immediate transmit demand. */
 
-  dev->trans_start = jiffies;
-  np->stats.tx_errors++;
-  return;
+       dev->trans_start = jiffies;
+       np->stats.tx_errors++;
+
+       netif_start_queue (dev);
 }
 
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void init_ring(struct net_device *dev)
+static void via_rhine_init_ring(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        int i;
 
-       np->tx_full = 0;
        np->cur_rx = np->cur_tx = 0;
        np->dirty_rx = np->dirty_tx = 0;
 
@@ -749,7 +739,6 @@ static void init_ring(struct net_device *dev)
                np->rx_ring[i].rx_status = 0;
                np->rx_ring[i].rx_length = DescOwn;
        }
-       np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
        for (i = 0; i < TX_RING_SIZE; i++) {
                np->tx_skbuff[i] = 0;
@@ -763,14 +752,18 @@ static void init_ring(struct net_device *dev)
        return;
 }
 
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
+static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        unsigned entry;
+       unsigned long flags;
 
        /* Caution: the write order is important here, set the field
           with the "ownership" bits last. */
 
+       /* lock eth irq */
+       spin_lock_irqsave (&np->lock, flags);
+
        /* Calculate the next Tx descriptor entry. */
        entry = np->cur_tx % TX_RING_SIZE;
 
@@ -796,12 +789,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        /* Wake the potentially-idle transmit channel. */
        writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 
-       if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1)
-               netif_start_queue(dev);         /* Typical path */
-       else
-               np->tx_full = 1;
+       if (np->cur_tx == np->dirty_tx + TX_RING_SIZE)
+               netif_stop_queue(dev);
+
        dev->trans_start = jiffies;
 
+       spin_unlock_irqrestore (&np->lock, flags);
+
        if (debug > 4) {
                printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
                           dev->name, np->cur_tx, entry);
@@ -811,20 +805,15 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
 {
        struct net_device *dev = (struct net_device *)dev_instance;
-       struct netdev_private *np;
        long ioaddr, boguscnt = max_interrupt_work;
+       u32 intr_status;
 
        ioaddr = dev->base_addr;
-       np = (struct netdev_private *)dev->priv;
        
-       spin_lock (&np->lock);
-
-       do {
-               u32 intr_status = readw(ioaddr + IntrStatus);
-
+       while ((intr_status = readw(ioaddr + IntrStatus))) {
                /* Acknowledge all of the current interrupt sources ASAP. */
                writew(intr_status & 0xffff, ioaddr + IntrStatus);
 
@@ -832,54 +821,18 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                        printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
                                   dev->name, intr_status);
 
-               if (intr_status == 0)
-                       break;
-
                if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
                                                   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
-                       netdev_rx(dev);
-
-               for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-                       int entry = np->dirty_tx % TX_RING_SIZE;
-                       int txstatus;
-                       if (np->tx_ring[entry].tx_own)
-                               break;
-                       txstatus = np->tx_ring[entry].tx_status;
-                       if (debug > 6)
-                               printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
-                                          entry, txstatus);
-                       if (txstatus & 0x8000) {
-                               if (debug > 1)
-                                       printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
-                                                  dev->name, txstatus);
-                               np->stats.tx_errors++;
-                               if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
-                               if (txstatus & 0x0200) np->stats.tx_window_errors++;
-                               if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
-                               if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
-                               if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
-                               /* Transmitter restarted in 'abnormal' handler. */
-                       } else {
-                               np->stats.collisions += (txstatus >> 3) & 15;
-                               np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
-                               np->stats.tx_packets++;
-                       }
-                       /* Free the original skb. */
-                       dev_kfree_skb_irq(np->tx_skbuff[entry]);
-                       np->tx_skbuff[entry] = 0;
-               }
-               if (np->tx_full &&
-                   netif_queue_stopped(dev) &&
-                   np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
-                       /* The ring is no longer full, clear tbusy. */
-                       np->tx_full = 0;
-                       netif_wake_queue (dev);
-               }
+                       via_rhine_rx(dev);
+
+               if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+                                                  IntrTxAborted))
+                       via_rhine_tx(dev);
 
                /* Abnormal error summary/uncommon events handlers. */
                if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |
                                                   IntrStatsMax | IntrTxAbort | IntrTxUnderrun))
-                       netdev_error(dev, intr_status);
+                       via_rhine_error(dev, intr_status);
 
                if (--boguscnt < 0) {
                        printk(KERN_WARNING "%s: Too much work at interrupt, "
@@ -887,25 +840,67 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                                   dev->name, intr_status);
                        break;
                }
-       } while (1);
+       }
 
        if (debug > 3)
                printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
                           dev->name, readw(ioaddr + IntrStatus));
+}
+
+/* This routine is logically part of the interrupt handler, but isolated
+   for clarity and better register allocation. */
+static void via_rhine_tx(struct net_device *dev)
+{
+       struct netdev_private *np = (struct netdev_private *)dev->priv;
+       int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE;
+
+       spin_lock (&np->lock);
+
+       /* if tx_full is set, they're all dirty, not clean */
+       while (np->dirty_tx != np->cur_tx) {
+               if (np->tx_ring[entry].tx_own) /* transmit request pending */
+                       break;
+               txstatus = np->tx_ring[entry].tx_status;
+               if (debug > 6)
+                       printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
+                                  entry, txstatus);
+               if (txstatus & 0x8000) {
+                       if (debug > 1)
+                               printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
+                                          dev->name, txstatus);
+                       np->stats.tx_errors++;
+                       if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
+                       if (txstatus & 0x0200) np->stats.tx_window_errors++;
+                       if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
+                       if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
+                       if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
+                       /* Transmitter restarted in 'abnormal' handler. */
+               } else {
+                       np->stats.collisions += (txstatus >> 3) & 15;
+                       np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
+                       np->stats.tx_packets++;
+               }
+               /* Free the original skb. */
+               dev_kfree_skb_irq(np->tx_skbuff[entry]);
+               np->tx_skbuff[entry] = NULL;
+               entry = (++np->dirty_tx) % TX_RING_SIZE;
+       }
+       if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2)
+               netif_wake_queue (dev);
 
        spin_unlock (&np->lock);
 }
 
 /* This routine is logically part of the interrupt handler, but isolated
    for clarity and better register allocation. */
-static int netdev_rx(struct net_device *dev)
+static void via_rhine_rx(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
-       int entry = np->cur_rx % RX_RING_SIZE;
-       int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+       int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE;
+       int boguscnt = RX_RING_SIZE;
 
        if (debug > 4) {
-               printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
+               printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n",
                           entry, np->rx_head_desc->rx_length);
        }
 
@@ -916,7 +911,7 @@ static int netdev_rx(struct net_device *dev)
                u16 desc_status = desc->rx_status;
 
                if (debug > 4)
-                       printk(KERN_DEBUG "  netdev_rx() status is %4.4x.\n",
+                       printk(KERN_DEBUG "  via_rhine_rx() status is %4.4x.\n",
                                   desc_status);
                if (--boguscnt < 0)
                        break;
@@ -924,15 +919,15 @@ static int netdev_rx(struct net_device *dev)
                        if ((desc_status & RxWholePkt) !=  RxWholePkt) {
                                printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
                                           "multiple buffers, entry %#x length %d status %4.4x!\n",
-                                          dev->name, np->cur_rx, data_size, desc_status);
+                                          dev->name, entry, data_size, desc_status);
                                printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
                                           dev->name, np->rx_head_desc,
-                                          &np->rx_ring[np->cur_rx % RX_RING_SIZE]);
+                                          &np->rx_ring[entry]);
                                np->stats.rx_length_errors++;
                        } else if (desc_status & RxErr) {
                                /* There was a error. */
                                if (debug > 2)
-                                       printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
+                                       printk(KERN_DEBUG "  via_rhine_rx() Rx error was %8.8x.\n",
                                                   desc_status);
                                np->stats.rx_errors++;
                                if (desc_status & 0x0030) np->stats.rx_length_errors++;
@@ -973,9 +968,9 @@ static int netdev_rx(struct net_device *dev)
        }
 
        /* Refill the Rx ring buffers. */
-       for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+       while (np->dirty_rx != np->cur_rx) {
                struct sk_buff *skb;
-               entry = np->dirty_rx % RX_RING_SIZE;
+               entry = np->dirty_rx++ % RX_RING_SIZE;
                if (np->rx_skbuff[entry] == NULL) {
                        skb = dev_alloc_skb(np->rx_buf_sz);
                        np->rx_skbuff[entry] = skb;
@@ -990,10 +985,9 @@ static int netdev_rx(struct net_device *dev)
 
        /* Pre-emptively restart Rx engine. */
        writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
-       return 0;
 }
 
-static void netdev_error(struct net_device *dev, int intr_status)
+static void via_rhine_error(struct net_device *dev, int intr_status)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        long ioaddr = dev->base_addr;
@@ -1003,7 +997,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
                        /* Link failed, restart autonegotiation. */
                        mdio_write(dev, np->phys[0], 0, 0x3300);
                else
-                       check_duplex(dev);
+                       via_rhine_check_duplex(dev);
                if (debug)
                        printk(KERN_ERR "%s: MII status changed: Autonegotiation "
                                   "advertising %4.4x  partner %4.4x.\n", dev->name,
@@ -1026,7 +1020,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
                        printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
                                   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
        }
-       if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) {
+       if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) {
                printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
                           dev->name, intr_status);
                /* Recovery for other fault sources not known. */
@@ -1034,7 +1028,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
        }
 }
 
-static struct enet_statistics *get_stats(struct net_device *dev)
+static struct net_device_stats *via_rhine_get_stats(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        long ioaddr = dev->base_addr;
@@ -1068,7 +1062,7 @@ static inline u32 ether_crc(int length, unsigned char *data)
     return crc;
 }
 
-static void set_rx_mode(struct net_device *dev)
+static void via_rhine_set_rx_mode(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        long ioaddr = dev->base_addr;
@@ -1120,7 +1114,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        }
 }
 
-static int netdev_close(struct net_device *dev)
+static int via_rhine_close(struct net_device *dev)
 {
        long ioaddr = dev->base_addr;
        struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -1162,45 +1156,49 @@ static int netdev_close(struct net_device *dev)
        return 0;
 }
 
-static int __init via_rhine_init_module (void)
+
+static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
 {
-       if (debug)                                      /* Emit version even if no cards detected. */
-               printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-#ifdef CARDBUS
-       register_driver(&etherdev_ops);
-       return 0;
-#else
-       return pci_etherdev_probe(pci_tbl);
+       struct net_device *dev = pdev->driver_data;
+       struct netdev_private *np = (struct netdev_private *)(dev->priv);
+       
+       unregister_netdev(dev);
+
+       release_region(pci_resource_start (pdev, 0),
+                      via_rhine_chip_info[np->chip_id].io_size);
+       release_mem_region(pci_resource_start (pdev, 1),
+                          via_rhine_chip_info[np->chip_id].io_size);
+
+#ifndef VIA_USE_IO
+       iounmap((char *)(dev->base_addr));
 #endif
+
+       kfree(dev);
 }
 
-static void __exit via_rhine_cleanup_module (void)
+
+static struct pci_driver via_rhine_driver = {
+       name:           "via-rhine",
+       id_table:       via_rhine_pci_tbl,
+       probe:          via_rhine_init_one,
+       remove:         via_rhine_remove_one,
+};
+
+
+static int __init via_rhine_init (void)
 {
+       return pci_module_init (&via_rhine_driver);
+}
 
-#ifdef CARDBUS
-       unregister_driver(&etherdev_ops);
-#endif
 
-       /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-       while (root_net_dev) {
-               struct netdev_private *np =
-                       (struct netdev_private *)(root_net_dev->priv);
-               unregister_netdev(root_net_dev);
-#ifdef VIA_USE_IO
-               release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size);
-#else
-               iounmap((char *)(root_net_dev->base_addr));
-#endif
-               kfree(root_net_dev);
-               root_net_dev = np->next_module;
-#if 0
-               kfree(np);                              /* Assumption: no struct realignment. */
-#endif
-       }
+static void __exit via_rhine_cleanup (void)
+{
+       pci_unregister_driver (&via_rhine_driver);
 }
 
-module_init(via_rhine_init_module);
-module_exit(via_rhine_cleanup_module);
+
+module_init(via_rhine_init);
+module_exit(via_rhine_cleanup);
 
 
 /*
index 7eb759b94de25a3447d4e6b1926ee2cf01ac8eae..85febe47dc9117ba67d4f5b168c615c0483f9945 100644 (file)
@@ -1263,7 +1263,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
        real_ioaddr = ioaddr = pci_resource_start (pdev, 0);
 #else
        real_ioaddr = ioaddr = pci_resource_start (pdev, 1);
-       ioaddr = ioremap(ioaddr, YELLOWFIN_SIZE);
+       ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);
 #endif
        irq = pdev->irq;
 
index d2af7d8f6756ba88a8b9efcb190156e61f323e71..d4222f353f1730902ab2b2c5075c2dee682522ad 100644 (file)
@@ -5,6 +5,9 @@
 # Parport configuration.
 #
 
+mainmenu_option next_comment
+comment 'Parallel port support'
+
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
    dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
@@ -47,3 +50,5 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
 
    bool '  IEEE 1284 transfer modes' CONFIG_PARPORT_1284
 fi
+
+endmenu
index 49e530ace82a2a8e2838d8fb23e551c96631a956..9cfa53b0d02b6548b40a1dfd841d06269a9c9485 100644 (file)
 #define ECR_TST 06
 #define ECR_CNF 07
 
+#undef DEBUG
+
+#ifdef DEBUG
+#define DPRINTK  printk
+#else
+#define DPRINTK(stuff...)
+#endif
+
+
+#define NR_SUPERIOS 3
+static struct superio_struct { /* For Super-IO chips autodetection */
+       int io;
+       int irq;
+       int dma;
+} superios[NR_SUPERIOS]= { {0,},};
+       
 /* frob_control, but for ECR */
 static void frob_econtrol (struct parport *pb, unsigned char m,
                           unsigned char v)
 {
        unsigned char ectr = inb (ECONTROL (pb));
-#ifdef DEBUG_PARPORT
-       printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
+       DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
                m, v, ectr, (ectr & ~m) ^ v);
-#endif
+
        outb ((ectr & ~m) ^ v, ECONTROL (pb));
 }
 
 #ifdef CONFIG_PARPORT_PC_FIFO
-/* Safely change the mode bits in the ECR */
+/* Safely change the mode bits in the ECR 
+   Returns:
+           0    : Success
+          -EBUSY: Could not drain FIFO in some finite amount of time,
+                  mode not changed!
+ */
 static int change_mode(struct parport *p, int m)
 {
        const struct parport_pc_private *priv = p->physport->private_data;
@@ -91,6 +111,8 @@ static int change_mode(struct parport *p, int m)
        unsigned char oecr;
        int mode;
 
+       DPRINTK("parport change_mode ECP-ISA to mode 0x%02x\n",m);
+
        if (!priv->ecr) {
                printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
                return 0;
@@ -993,6 +1015,305 @@ struct parport_operations parport_pc_ops =
        parport_ieee1284_read_byte,
 };
 
+/* Super-IO chipset detection, Winbond, SMSC */
+
+static void show_parconfig_smsc37c669(int io, int key)
+{
+       int cr1,cr4,cra,cr23,cr26,cr27,i=0;
+       char *modes[]={ "SPP and Bidirectional (PS/2)", 
+                       "EPP and SPP",
+                       "ECP",
+                       "ECP and EPP"};
+
+       outb(key,io);
+       outb(key,io);
+       outb(1,io);
+       cr1=inb(io+1);
+       outb(4,io);
+       cr4=inb(io+1);
+       outb(0x0a,io);
+       cra=inb(io+1);
+       outb(0x23,io);
+       cr23=inb(io+1);
+       outb(0x26,io);
+       cr26=inb(io+1);
+       outb(0x27,io);
+       cr27=inb(io+1);
+       outb(0xaa,io);
+
+       printk ("SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, "
+               "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n",
+               cr1,cr4,cra,cr23,cr26,cr27);
+
+       /* The documentation calls DMA and IRQ-Lines by letters, so
+          the board maker can/will wire them
+          appropriately/randomly...  G=reserved H=IDE-irq, */
+       printk ("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, "
+               "fifo threshold=%d\n", cr23*4,
+               (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-',
+               (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f);
+       printk("SMSC LPT Config: enabled=%s power=%s\n",
+              (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no");
+       printk("SMSC LPT Config: Port mode=%s, EPP version =%s\n",
+              (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], 
+              (cr4 & 40) ? "1.7" : "1.9");
+
+       /* Heuristics !  BIOS setup for this mainboard device limits
+          the choices to standard settings, i.e. io-address and IRQ
+          are related, however DMA can be 1 or 3, assume DMA_A=DMA1,
+          DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */
+       if(cr23*4 >=0x100) { /* if active */
+               while((superios[i].io!= 0) && (i<NR_SUPERIOS))
+                       i++;
+               if(i==NR_SUPERIOS)
+                       printk("Super-IO: too many chips!\n");
+               else {
+                       int d;
+                       switch (cr23*4) {
+                               case 0x3bc:
+                                       superios[i].io = 0x3bc;
+                                       superios[i].irq = 7;
+                                       break;
+                               case 0x378:
+                                       superios[i].io = 0x378;
+                                       superios[i].irq = 7;
+                                       break;
+                               case 0x278:
+                                       superios[i].io = 0x278;
+                                       superios[i].irq = 5;
+                       }
+                       d=(cr26 &0x0f);
+                       if((d==1) || (d==3)) 
+                               superios[i].dma= d;
+                       else
+                               superios[i].dma= PARPORT_DMA_NONE;
+               }
+       }
+}
+
+
+static void show_parconfig_winbond(int io, int key)
+{
+       int cr30,cr60,cr61,cr70,cr74,crf0,i=0;
+       char *modes[]={ "Standard (SPP) and Bidirectional(PS/2)", /* 0 */
+                       "EPP-1.9 and SPP",
+                       "ECP",
+                       "ECP and EPP-1.9",
+                       "Standard (SPP)",
+                       "EPP-1.7 and SPP",              /* 5 */
+                       "undefined!",
+                       "ECP and EPP-1.7"};
+       char *irqtypes[]={"pulsed low, high-Z", "follows nACK"};
+               
+       /* The registers are called compatible-PnP because the
+           register layout is modelled after ISA-PnP, the access
+           method is just another ... */
+       outb(key,io);
+       outb(key,io);
+       outb(0x07,io);   /* Register 7: Select Logical Device */
+       outb(0x01,io+1); /* LD1 is Parallel Port */
+       outb(0x30,io);
+       cr30=inb(io+1);
+       outb(0x60,io);
+       cr60=inb(io+1);
+       outb(0x61,io);
+       cr61=inb(io+1);
+       outb(0x70,io);
+       cr70=inb(io+1);
+       outb(0x74,io);
+       cr74=inb(io+1);
+       outb(0xf0,io);
+       crf0=inb(io+1);
+       outb(0xaa,io);
+
+       printk("Winbond LPT Config: cr_30=%02x 60,61=%02x%02x "
+              "70=%02x 74=%02x, f0=%02x\n", cr30,cr60,cr61,cr70,cr74,crf0);
+       printk("Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", 
+              (cr30 & 0x01) ? "yes":"no", cr60,cr61,cr70&0x0f );
+       if ((cr74 & 0x07) > 3)
+               printk("dma=none\n");
+       else
+               printk("dma=%d\n",cr74 & 0x07);
+       printk("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n",
+              irqtypes[crf0>>7], (crf0>>3)&0x0f);
+       printk("Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]);
+
+       if(cr30 & 0x01) { /* the settings can be interrogated later ... */
+               while((superios[i].io!= 0) && (i<NR_SUPERIOS))
+                       i++;
+               if(i==NR_SUPERIOS) 
+                       printk("Super-IO: too many chips!\n");
+               else {
+                       superios[i].io = (cr60<<8)|cr61;
+                       superios[i].irq = cr70&0x0f;
+                       superios[i].dma = (((cr74 & 0x07) > 3) ?
+                                          PARPORT_DMA_NONE : (cr74 & 0x07));
+               }
+       }
+}
+
+static void decode_winbond(int efer, int key, int devid, int devrev, int oldid)
+{
+       char *type=NULL;
+       int id,progif=2;
+
+       if (devid == devrev)
+               /* simple heuristics, we happened to read some
+                   non-winbond register */
+               return;
+
+       printk("Winbond chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x "
+              "oldid=%02x\n", efer,key,devid,devrev,oldid);
+       id=(devid<<8) | devrev;
+
+       /* Values are from public data sheets pdf files, I can just
+           confirm 83977TF is correct :-) */
+       if      (id == 0x9773) type="83977TF";
+       else if (id == 0x9774) type="83977ATF";
+       else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x";
+       else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97x35x";
+       else if ((id & ~0x0f) == 0x5210) type="83627";
+       else if ((id & ~0x0f) == 0x6010) type="83697HF";
+       else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;}
+       else if ((oldid &0x0f ) == 0x0c) { type="83877ATF"; progif=1;}
+       else progif=0;
+
+       if(type==NULL) 
+               printk("Winbond unkown chip type\n");
+       else    
+               printk("Winbond chip type %s\n",type);
+
+       if(progif==2)
+               show_parconfig_winbond(efer,key);
+       return;
+}
+
+static void decode_smsc(int efer, int key, int devid, int devrev)
+{
+        char *type=NULL;
+       void (*func)(int io, int key);
+        int id;
+
+        if (devid == devrev)
+               /* simple heuristics, we happened to read some
+                   non-winbond register */
+               return;
+
+       func=NULL;
+        printk("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x\n",
+              efer,key,devid,devrev);
+        id=(devid<<8) | devrev;
+
+       if      (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;}
+       else if (id==0x6582) type="37c665IR";
+       else if ((id==0x6502) && (key==0x44)) type="37c665GT";
+       else if ((id==0x6502) && (key==0x55)) type="37c666GT";
+
+       if(type==NULL)
+                printk("SMSC unknown chip type\n");
+        else
+                printk("SMSC chip type %s\n",type);
+
+       if(func) (func)(efer,key);
+       return;
+}
+
+
+static void winbond_check(int io, int key)
+{
+       int devid,devrev,oldid;
+
+       outb(key,io);
+       outb(key,io);     /* Write Magic Sequence to EFER, extended
+                             funtion enable register */
+       outb(0x20,io);    /* Write EFIR, extended function index register */
+       devid=inb(io+1);  /* Read EFDR, extended function data register */
+       outb(0x21,io);
+       devrev=inb(io+1);
+       outb(0x09,io);
+       oldid=inb(io+1);
+       outb(0xaa,io);    /* Magic Seal */
+
+       decode_winbond(io,key,devid,devrev,oldid);
+}
+
+static void winbond_check2(int io,int key)
+{
+        int devid,devrev,oldid;
+
+        outb(key,io);     /* Write Magic Byte to EFER, extended
+                             funtion enable register */
+        outb(0x20,io+2);  /* Write EFIR, extended function index register */
+        devid=inb(io+2);  /* Read EFDR, extended function data register */
+        outb(0x21,io+1);
+        devrev=inb(io+2);
+        outb(0x09,io+1);
+        oldid=inb(io+2);
+        outb(0xaa,io);    /* Magic Seal */
+
+        decode_winbond(io,key,devid,devrev,oldid);
+}
+
+static void smsc_check(int io, int key)
+{
+        int devid,devrev;
+
+        outb(key,io);
+        outb(key,io);     /* Write Magic Sequence to EFER, extended
+                             funtion enable register */
+        outb(0x0d,io);    /* Write EFIR, extended function index register */
+        devid=inb(io+1);  /* Read EFDR, extended function data register */
+        outb(0x0e,io);
+        devrev=inb(io+1);
+        outb(0xaa,io);    /* Magic Seal */
+
+        decode_smsc(io,key,devid,devrev);
+}
+
+
+static void detect_and_report_winbond (void)
+{ 
+       printk("Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n");
+
+       winbond_check(0x3f0,0x87);
+       winbond_check(0x370,0x87);
+       winbond_check(0x2e ,0x87);
+       winbond_check(0x4e ,0x87);
+       winbond_check(0x3f0,0x86);
+       winbond_check2(0x250,0x88); 
+       winbond_check2(0x250,0x89);
+}
+
+static void detect_and_report_smsc (void)
+{
+       printk("SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n");
+       smsc_check(0x3f0,0x55);
+       smsc_check(0x370,0x55);
+       smsc_check(0x3f0,0x44);
+       smsc_check(0x370,0x44);
+}
+
+static int get_superio_dma (struct parport *p)
+{
+       int i=0;
+       while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
+               i++;
+       if (i!=NR_SUPERIOS)
+               return superios[i].dma;
+       return PARPORT_DMA_NONE;
+}
+
+static int get_superio_irq (struct parport *p)
+{
+       int i=0;
+        while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
+                i++;
+        if (i!=NR_SUPERIOS)
+                return superios[i].irq;
+        return PARPORT_IRQ_NONE;
+}
+       
+
 /* --- Mode detection ------------------------------------- */
 
 /*
@@ -1158,9 +1479,12 @@ static int __devinit parport_PS2_supported(struct parport *pb)
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
        int i;
-       int config;
+       int config, configb;
        int pword;
        struct parport_pc_private *priv = pb->private_data;
+       int intrline[]={0,7,9,10,11,14,15,5}; /* Translate ECP
+                                                 intrLine to ISA irq
+                                                 value */
 
        /* If there is no ECR, we have no hope of supporting ECP. */
        if (!priv->ecr)
@@ -1253,11 +1577,23 @@ static int __devinit parport_ECP_supported(struct parport *pb)
        printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
                config & 0x80 ? "Level" : "Pulses");
 
-       config = inb (CONFIGB (pb));
-       if (!(config & 0x40)) {
+       configb = inb (CONFIGB (pb));
+       if (!(configb & 0x40)) {
                printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
                pb->irq = PARPORT_IRQ_NONE;
        }
+       printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n",
+               pb->base, config, configb);
+        printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base);
+       if ((configb >>3) & 0x07)
+               printk("%d",intrline[(configb >>3) & 0x07]);
+       else
+               printk("<none or set by other means>");
+       printk ( " dma=");
+       if( (configb & 0x03 ) == 0x00)
+               printk("<none or set by other means>\n");
+       else
+               printk("%d\n",configb & 0x07);
 
        /* Go back to mode 000 */
        frob_econtrol (pb, 0xe0, ECR_SPP << 5);
@@ -1476,8 +1812,6 @@ static int __devinit parport_irq_probe(struct parport *pb)
 
        if (priv->ecr) {
                pb->irq = programmable_irq_support(pb);
-               if (pb->irq != PARPORT_IRQ_NONE)
-                       goto out;
        }
 
        if (pb->modes & PARPORT_MODE_ECP)
@@ -1497,7 +1831,9 @@ static int __devinit parport_irq_probe(struct parport *pb)
        if (pb->irq == PARPORT_IRQ_NONE)
                pb->irq = irq_probe_SPP(pb);
 
-out:
+       if (pb->irq == PARPORT_IRQ_NONE)
+               pb->irq = get_superio_irq(pb);
+
        return pb->irq;
 }
 
@@ -1525,7 +1861,12 @@ static int __devinit parport_dma_probe (struct parport *p)
 {
        const struct parport_pc_private *priv = p->private_data;
        if (priv->ecr)
-               p->dma = programmable_dma_support(p);
+               p->dma = programmable_dma_support(p); /* ask ECP chipset first */
+       if (p->dma == PARPORT_DMA_NONE)
+               /* ask known Super-IO chips proper, although these
+                  claim ECP compatible, some don't report their DMA
+                  conforming to ECP standards */
+               p->dma = get_superio_dma(p);
 
        return p->dma;
 }
@@ -1533,9 +1874,9 @@ static int __devinit parport_dma_probe (struct parport *p)
 /* --- Initialisation code -------------------------------- */
 
 struct parport *__devinit parport_pc_probe_port (unsigned long int base,
-                                                   unsigned long int base_hi,
-                                                   int irq, int dma,
-                                                   struct pci_dev *dev)
+                                                unsigned long int base_hi,
+                                                int irq, int dma,
+                                                struct pci_dev *dev)
 {
        struct parport_pc_private *priv;
        struct parport_operations *ops;
@@ -1625,7 +1966,8 @@ struct parport *__devinit parport_pc_probe_port (unsigned long int base,
                        parport_dma_probe(p);
                }
        }
-       if (p->dma == PARPORT_DMA_AUTO)         
+       if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq
+                                           is mandatory (see above) */
                p->dma = PARPORT_DMA_NONE;
 
 #ifdef CONFIG_PARPORT_PC_FIFO
@@ -2040,6 +2382,7 @@ static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PAR
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
+static int superio = 0;
 
 MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
 MODULE_DESCRIPTION("PC-style parallel port driver");
@@ -2051,12 +2394,18 @@ MODULE_PARM_DESC(irq, "IRQ line");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
+MODULE_PARM_DESC(superio, "Enable Super-IO chipset probe");
+MODULE_PARM(superio, "i");
 
 int init_module(void)
 {      
        /* Work out how many ports we have, then get parport_share to parse
           the irq values. */
        unsigned int i;
+       if (superio) {
+               detect_and_report_winbond ();
+               detect_and_report_smsc ();
+       }
        for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
        if (i) {
                if (parport_parse_irqs(i, irq, irqval)) return 1;
index fc971cc7428c63d653355bbdb63bdf16a5365994..abb46572a50795f2e47b508327e1e6275e12b008 100644 (file)
@@ -602,7 +602,19 @@ static int yenta_init(pci_socket_t *socket)
 static int yenta_suspend(pci_socket_t *socket)
 {
        yenta_set_socket(socket, &dead_socket);
+
+       /*
+        * This does not work currently. The controller
+        * loses too much informationduring D3 to come up
+        * cleanly. We should probably fix yenta_init()
+        * to update all the critical registers, notably
+        * the IO and MEM bridging region data.. That is
+        * something that pci_set_power_state() should
+        * probably know about bridges anyway.
+        *
        pci_set_power_state(socket->dev, 3);
+        */
+
        return 0;
 }
 
index 35f18a53c42782037d80ad66f834d524b19dbc36..781cde85af84b4c3c778fe723964f475bac11862 100644 (file)
@@ -666,11 +666,7 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
        /* scsi_wait_cmd sets the command length */
        SRpnt->sr_cmd_len = 0;
 
-       /*
-        * FIXME(eric) - need to set the data direction here.
-        */
-       SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
-
+       SRpnt->sr_data_direction = cgc->data_direction;
        scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
                      SR_TIMEOUT, MAX_RETRIES);
 
index 95bafcf20df2c2fcbb0fac36ac184dd3df2fb3ae..32a3380e9ae426e29cdae2e77aec7fec476a8b82 100644 (file)
@@ -20,6 +20,8 @@
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * History
+ * v0.3 Feb 22 2000 Ollie Lho
+ *     bug fix for record mask setting
  * v0.2 Feb 10 2000 Ollie Lho
  *     add ac97_read_proc for /proc/driver/vnedor/ac97
  * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
@@ -40,7 +42,9 @@ static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, uns
 static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
 static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
 
-#define arraysize(x)   (sizeof(x)/sizeof((x)[0]))
+static int sigmatel_init(struct ac97_codec * codec);
+
+#define arraysize(x)   (sizeof(x)/sizeof((x)[0]))
 
 static struct {
        unsigned int id;
@@ -50,14 +54,16 @@ static struct {
        {0x414B4D00, "Asahi Kasei AK4540"     , NULL},
        {0x41445340, "Analog Devices AD1881"  , NULL},
        {0x43525900, "Cirrus Logic CS4297"    , NULL},
+       {0x43525903, "Cirrus Logic CS4297"  ,   NULL},
        {0x43525913, "Cirrus Logic CS4297A"   , NULL},
+       {0x43525923, "Cirrus Logic CS4298"    , NULL},
        {0x43525931, "Cirrus Logic CS4299"    , NULL},
-       {0x4e534331, "National Semiconductor LM4549", NULL},
+       {0x4e534331, "National Semiconductor LM4549" ,  NULL},
        {0x83847600, "SigmaTel STAC????"      , NULL},
        {0x83847604, "SigmaTel STAC9701/3/4/5", NULL},
        {0x83847605, "SigmaTel STAC9704"      , NULL},
        {0x83847608, "SigmaTel STAC9708"      , NULL},
-       {0x83847609, "SigmaTel STAC9721/23"   , NULL},
+       {0x83847609, "SigmaTel STAC9721/23"   , sigmatel_init},
        {0x54524108, "TriTech TR28028"        , NULL},
        {0x574D4C00, "Wolfson WM9704"         , NULL},
        {0x00000000, NULL, NULL}
@@ -156,11 +162,12 @@ enum ac97_recsettings {
 };
 
 static unsigned int ac97_rm2oss[] = {
-       [AC97_REC_MIC]   = SOUND_MIXER_MIC, 
-       [AC97_REC_CD]    = SOUND_MIXER_CD, 
-       [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, 
-       [AC97_REC_AUX]   = SOUND_MIXER_LINE1, 
-       [AC97_REC_LINE]  = SOUND_MIXER_LINE, 
+       [AC97_REC_MIC]   = SOUND_MIXER_MIC,
+       [AC97_REC_CD]    = SOUND_MIXER_CD,
+       [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
+       [AC97_REC_AUX]   = SOUND_MIXER_LINE1,
+       [AC97_REC_LINE]  = SOUND_MIXER_LINE,
+       [AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
        [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
 };
 
@@ -171,6 +178,7 @@ static unsigned int ac97_oss_rm[] = {
        [SOUND_MIXER_VIDEO]     = AC97_REC_VIDEO,
        [SOUND_MIXER_LINE1]     = AC97_REC_AUX,
        [SOUND_MIXER_LINE]      = AC97_REC_LINE,
+       [SOUND_MIXER_IGAIN]     = AC97_REC_STEREO,
        [SOUND_MIXER_PHONEIN]   = AC97_REC_PHONE
 };
 
@@ -216,8 +224,10 @@ static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel)
        }
 
 #ifdef DEBUG
-       printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), "
-              "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret);
+       printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
+              "0x%04x -> 0x%04x\n",
+              oss_channel, codec->id ? "Secondary" : "Primary",
+              mh->offset, val, ret);
 #endif
 
        return ret;
@@ -269,6 +279,7 @@ static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
 #ifdef DEBUG
        printk(" 0x%04x", val);
 #endif
+
        codec->codec_write(codec, mh->offset, val);
 
 #ifdef DEBUG
@@ -303,8 +314,11 @@ static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask)
 
        if (rw) {
                /* read it from the card */
-               val = codec->codec_read(codec, 0x1a) & 0x7;
-               return ac97_rm2oss[val];
+               val = codec->codec_read(codec, AC97_RECORD_SELECT);
+#ifdef DEBUG
+               printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
+#endif
+               return (1 << ac97_rm2oss[val & 0x07]);
        }
 
        /* else, write the first set in the mask as the
@@ -315,10 +329,10 @@ static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask)
        val |= val << 8;  /* set both channels */
 
 #ifdef DEBUG
-       printk("ac97_codec: setting ac97 recmask to 0x%x\n", val);
+       printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
 #endif
 
-       codec->codec_write(codec, 0x1a, val);
+       codec->codec_write(codec, AC97_RECORD_SELECT, val);
 
        return 0;
 };
@@ -384,9 +398,9 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
                                return -EINVAL;
 
                        /* do we ever want to touch the hardware? */
-                       val = codec->read_mixer(codec, i);
-                       /* val = codec->mixer_state[i]; */
-                       break;
+                       /* val = codec->read_mixer(codec, i); */
+                       val = codec->mixer_state[i];
+                       break;
                }
                return put_user(val, (int *)arg);
        }
@@ -497,9 +511,10 @@ int ac97_probe_codec(struct ac97_codec *codec)
        codec->codec_write(codec, AC97_RESET, 0L);
        if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000)
                return 0;
-       
+
        codec->name = NULL;
        codec->codec_init = NULL;
+
        id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
        id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
        for (i = 0; i < arraysize(ac97_codec_ids); i++) {
@@ -520,6 +535,8 @@ int ac97_probe_codec(struct ac97_codec *codec)
        codec->record_sources = AC97_RECORD_MASK;
        if (!(cap & 0x04))
                codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
+       if (!(cap & 0x10))
+               codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
 
        /* generic OSS to AC97 wrapper */
        codec->read_mixer = ac97_read_mixer;
index de01c6cbe02fe8f007a9f348c3fff5e21a5c0af2..b3a9f750402a50a3b0efe2647365cbf6d894d365 100644 (file)
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.13 Mar 03 2000 Ollie Lho
+ *     new pci_* for 2.4 kernel, back ported to 2.2
+ *  v0.12 Feb 23 2000 Ollie Lho
+ *     Preliminary Recording support
+ *  v0.11.2 Feb 19 2000 Ollie Lho
+ *     removed incomplete full-dulplex support
  *  v0.11.1 Jan 28 2000 Ollie Lho
  *     small bug in setting sample rate for 4d-nx (reported by Aaron)
  *  v0.11 Jan 27 2000 Ollie Lho
  *     Clean up of low level channel register access code. (done)
  *        Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
  *     Dual AC97 codecs support (done partially, need channel binding to test)
- *     Recording support
+ *     Recording support (done)
  *     Mmap support
  *     "Channel Binding" ioctl extension
+ *     new pci device driver interface for 2.4 kernel
  */
       
 #include <linux/module.h>
 
 #include "trident.h"
 
-#undef DEBUG
-
-#define DRIVER_VERSION "0.11.1"
+#define DRIVER_VERSION "0.13"
 
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC     0x5072696E /* "Prin" */
 #define TRIDENT_STATE_MAGIC    0x63657373 /* "cess" */
 
-/* The first 32 channels are called Bank A. They are (should be) reserved
-   for MIDI synthesizer. But since that is not supported yet, we can (ab)use
-   them to play PCM samples */
-#undef ABUSE_BANK_A
-
-/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ?
-   NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW
-   channels */
-#ifdef ABUSE_BANK_A
-#define NR_HW_CH               64
-#else
+#define TRIDENT_DMA_MASK               0x3fffffff /* DMA buffer mask for pci_alloc_consist */
+
 #define NR_HW_CH               32
-#endif
 
 /* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
    have 2 SDATA_IN lines (currently) */
@@ -119,18 +114,29 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
 static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
 
-struct pci_audio_info {
-       u16 vendor;
-       u16 device;
-       char *name;
+enum {
+       TRIDENT_4D_DX = 0,
+       TRIDENT_4D_NX,
+       SIS_7018
 };
 
-static struct pci_audio_info pci_audio_devices[] = {
-       {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"},
-       {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"},
-       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
+static char * card_names[] = {
+       "Trident 4DWave DX",
+       "Trident 4DWave NX",
+       "SiS 7018 PCI Audio"
 };
 
+static struct pci_device_id trident_pci_tbl [] __devinitdata = {
+       {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX},
+       {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX},
+       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018},
+};
+
+MODULE_DEVICE_TABLE (pci, trident_pci_tbl);
+
 /* "software" or virtual channel, an instance of opened /dev/dsp */
 struct trident_state {
        unsigned int magic;
@@ -156,14 +162,15 @@ struct trident_state {
 
                /* OSS buffer manangemeent stuff */
                void *rawbuf;
+               dma_addr_t dma_handle;
                unsigned buforder;
                unsigned numfrag;
                unsigned fragshift;
 
                /* our buffer acts like a circular ring */
-               unsigned hwptr;         /* where dma last started, update by update_ptr */
+               unsigned hwptr;         /* where dma last started, updated by update_ptr */
                unsigned swptr;         /* where driver last clear/filled, updated by read/write */
-               int count;              /* bytes to be comsumed by dma machine */
+               int count;              /* bytes to be comsumed or been generated by dma machine */
                unsigned total_bytes;   /* total bytes dmaed by hardware */
 
                unsigned error;         /* number of over/underruns */
@@ -177,22 +184,21 @@ struct trident_state {
                /* OSS stuff */
                unsigned mapped:1;
                unsigned ready:1;
-               unsigned endcleared:1;
                unsigned ossfragshift;
                int ossmaxfrags;
                unsigned subdivision;
-       } dma_dac, dma_adc;
+       } dmabuf;
 };
 
 /* hardware channels */
 struct trident_channel {
        int  num;       /* channel number */
-       u32 lba;        /* reg 0xe4 */
-       u32 eso;        /* reg 0xe8 */
-       u32 delta;
-       u16 attribute;  /* reg 0xec */
+       u32 lba;        /* Loop Begine Address, where dma buffer starts */
+       u32 eso;        /* End Sample Offset, wehre dma buffer ends (in the unit of samples) */
+       u32 delta;      /* delta value, sample rate / 48k for playback, 48k/sample rate for recording */
+       u16 attribute;  /* control where PCM data go and come  */
        u16 fm_vol;
-       u32 control;    /* reg 0xf0 */
+       u32 control;    /* signed/unsigned, 8/16 bits, mono/stereo */
 };
 
 struct trident_pcm_bank_address {
@@ -234,7 +240,6 @@ struct trident_card {
        spinlock_t lock;
 
        /* PCI device stuff */
-       struct pci_audio_info *pci_info;
        struct pci_dev * pci_dev;
        u16 pci_id;
 
@@ -422,9 +427,6 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c
        if (bank->bitmap == ~0UL) {
                /* no more free channels avaliable */
                printk(KERN_ERR "trident: no more channels available on Bank B.\n");
-#ifdef ABUSE_BANK_A
-               goto bank_a;
-#endif
                return NULL;
        }
        for (idx = 31; idx >= 0; idx--) {
@@ -435,26 +437,6 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c
                        return channel;
                }
        }
-
-#ifdef ABUSE_BANK_A
-       /* channels in Bank A should be reserved for synthesizer 
-          not for normal use (channels in Bank A can't record) */
- bank_a:
-       bank = &card->banks[BANK_A];
-       if (bank->bitmap == ~0UL) {
-               /* no more free channels avaliable */
-               printk(KERN_ERR "trident: no more channels available on Bank A.\n");
-               return NULL;
-       }
-       for (idx = 31; idx >= 0; idx--) {
-               if (!(bank->bitmap & (1 << idx))) {
-                       struct trident_channel *channel = &bank->channels[idx];
-                       banks->bitmap |= 1 << idx;
-                       channel->num = idx;
-                       return channels;
-               }
-       }
-#endif
        return NULL;
 }
 
@@ -462,13 +444,8 @@ static void trident_free_pcm_channel(struct trident_card *card, int channel)
 {
        int bank;
 
-#ifdef ABUSE_BANK_A
-       if (channel < 0 || channel > 63)
-               return;
-#else
        if (channel < 31 || channel > 63)
                return;
-#endif
 
        bank = channel >> 5;
        channel = channel & 0x1f;
@@ -497,15 +474,12 @@ static int trident_load_channel_registers(struct trident_card *card, u32 *data,
 }
 
 /* called with spin lock held */
-static int trident_write_voice_regs(struct trident_state *state, unsigned int rec)
+static int trident_write_voice_regs(struct trident_state *state)
 {
        unsigned int data[CHANNEL_REGS + 1];
        struct trident_channel *channel;
 
-       if (rec)
-               channel = state->dma_adc.channel;
-       else
-               channel = state->dma_dac.channel;
+       channel = state->dmabuf.channel;
 
        data[1] = channel->lba;
        data[4] = channel->control;
@@ -534,7 +508,7 @@ static int trident_write_voice_regs(struct trident_state *state, unsigned int re
        return trident_load_channel_registers(state->card, data, channel->num);
 }
 
-static int compute_rate(u32 rate)
+static int compute_rate_play(u32 rate)
 {
        int delta;
        /* We special case 44100 and 8000 since rounding with the equation
@@ -552,10 +526,25 @@ static int compute_rate(u32 rate)
        return delta;
 }
 
+static int compute_rate_rec(u32 rate)
+{
+       int delta;
+
+       if (rate == 44100)
+               delta = 0x116a;
+       else if (rate == 8000)
+               delta = 0x6000;
+       else if (rate == 48000)
+               delta = 0x1000;
+       else
+               delta = ((48000 << 12) / rate) & 0x0000ffff;
+
+       return delta;
+}
 /* set playback sample rate */
 static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate)
 {      
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
 
        if (rate > 48000)
                rate = 48000;
@@ -563,9 +552,9 @@ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned
                rate = 4000;
 
        dmabuf->rate = rate;
-       dmabuf->channel->delta = compute_rate(rate);
+       dmabuf->channel->delta = compute_rate_play(rate);
 
-       trident_write_voice_regs(state, 0);
+       trident_write_voice_regs(state);
 
 #ifdef DEBUG
        printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
@@ -577,16 +566,17 @@ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned
 /* set recording sample rate */
 static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate)
 {
-       struct dmabuf *dmabuf = &state->dma_adc;
+       struct dmabuf *dmabuf = &state->dmabuf;
+
        if (rate > 48000)
                rate = 48000;
        if (rate < 4000)
                rate = 4000;
 
        dmabuf->rate = rate;
-       dmabuf->channel->delta = compute_rate(rate);
+       dmabuf->channel->delta = compute_rate_rec(rate);
 
-       trident_write_voice_regs(state, 1);
+       trident_write_voice_regs(state);
 
 #ifdef DEBUG
        printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
@@ -597,18 +587,18 @@ static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned
 /* prepare channel attributes for playback */ 
 static void trident_play_setup(struct trident_state *state)
 {
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        struct trident_channel *channel = dmabuf->channel;
 
        channel->lba = virt_to_bus(dmabuf->rawbuf);
-       channel->delta = compute_rate(dmabuf->rate);
+       channel->delta = compute_rate_play(dmabuf->rate);
 
        channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
        channel->eso -= 1;
 
        if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
-               /* FIXME: channel attributes are configured by ioctls, but it is not implemented
-                  so just set to ZERO for the moment */
+               /* FIXME: channel attributes are configured by ioctls, but it is not
+                  implemented so just set to ZERO for the moment */
                channel->attribute = 0;
        } else {
                channel->attribute = 0;
@@ -631,7 +621,7 @@ static void trident_play_setup(struct trident_state *state)
               "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
               channel->lba, channel->delta, channel->eso, channel->control);
 #endif
-       trident_write_voice_regs(state, 0);
+       trident_write_voice_regs(state);
 }
 
 /* prepare channel attributes for recording */
@@ -639,7 +629,7 @@ static void trident_rec_setup(struct trident_state *state)
 {
        u16 w;
        struct trident_card *card = state->card;
-       struct dmabuf *dmabuf = &state->dma_adc;
+       struct dmabuf *dmabuf = &state->dmabuf;
        struct trident_channel *channel = dmabuf->channel;
 
        /* Enable AC-97 ADC (capture) */
@@ -651,25 +641,30 @@ static void trident_rec_setup(struct trident_state *state)
        case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
                w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
                outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+               /* enable and set record channel */
+               outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
                break;
        case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
                w = inw(TRID_REG(card, T4D_MISCINT));
                outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));
+               /* enable and set record channel */
+               outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
                break;
        default:
                return;
        }
 
        channel->lba = virt_to_bus(dmabuf->rawbuf);
-       channel->delta = compute_rate(dmabuf->rate);
+       channel->delta = compute_rate_rec(dmabuf->rate);
 
        channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
        channel->eso -= 1;
 
        if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
-               /* FIXME: channel attributes are configured by ioctls, but it is not implemented
-                  so just set to ZERO for the moment */
-               channel->attribute = 0;
+               /* FIXME: channel attributes are configured by ioctls, but it is not
+                  implemented so just set to 0x8a80 for the moment, record from PCM L/R
+                  input and mono = (left + right + 1)/2*/
+               channel->attribute = 0x8A80;
        } else {
                channel->attribute = 0;
        }
@@ -691,21 +686,16 @@ static void trident_rec_setup(struct trident_state *state)
               "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
               channel->lba, channel->delta, channel->eso, channel->control);
 #endif
-       trident_write_voice_regs(state, 1);
+       trident_write_voice_regs(state);
 }
 
 /* get current playback/recording dma buffer pointer (byte offset from LBA),
    called with spinlock held! */
-extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec)
+extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state)
 {
-       struct dmabuf *dmabuf;
+       struct dmabuf *dmabuf = &state->dmabuf;
        u32 cso;
 
-       if (rec)
-               dmabuf = &state->dma_adc;
-       else
-               dmabuf = &state->dma_dac;
-
        if (!dmabuf->enable)
                return 0;
 
@@ -727,7 +717,8 @@ extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, uns
        }
 
 #ifdef DEBUG
-       printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n",
+       printk("trident: trident_get_dma_addr: chip reported channel: %d, "
+              "cso = 0x%04x\n",
               dmabuf->channel->num, cso);
 #endif
        /* ESO and CSO are in units of Samples, convert to byte offset */
@@ -739,11 +730,11 @@ extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, uns
 /* Stop recording (lock held) */
 extern __inline__ void __stop_adc(struct trident_state *state)
 {
-       struct dmabuf *dmabuf = &state->dma_adc;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned int chan_num = dmabuf->channel->num;
        struct trident_card *card = state->card;
 
-       dmabuf->enable &= ~DMA_RUNNING;
+       dmabuf->enable &= ~ADC_RUNNING;
        trident_stop_voice(card, chan_num);
        trident_disable_voice_irq(card, chan_num);
 }
@@ -760,16 +751,14 @@ static void stop_adc(struct trident_state *state)
 
 static void start_adc(struct trident_state *state)
 {
-       struct dmabuf *dmabuf = &state->dma_adc;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned int chan_num = dmabuf->channel->num;
        struct trident_card *card = state->card;
        unsigned long flags;
 
        spin_lock_irqsave(&card->lock, flags);
-       if ((dmabuf->mapped || 
-            dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize))
-           && dmabuf->ready) {
-               dmabuf->enable |= DMA_RUNNING;
+       if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) {
+               dmabuf->enable |= ADC_RUNNING;
                trident_enable_voice_irq(card, chan_num);
                trident_start_voice(card, chan_num);
        }
@@ -779,11 +768,11 @@ static void start_adc(struct trident_state *state)
 /* stop playback (lock held) */
 extern __inline__ void __stop_dac(struct trident_state *state)
 {
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned int chan_num = dmabuf->channel->num;
        struct trident_card *card = state->card;
 
-       dmabuf->enable &= ~DMA_RUNNING;
+       dmabuf->enable &= ~DAC_RUNNING;
        trident_stop_voice(card, chan_num);
        trident_disable_voice_irq(card, chan_num);
 }
@@ -800,14 +789,14 @@ static void stop_dac(struct trident_state *state)
 
 static void start_dac(struct trident_state *state)
 {
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned int chan_num = dmabuf->channel->num;
        struct trident_card *card = state->card;
        unsigned long flags;
 
        spin_lock_irqsave(&card->lock, flags);
        if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
-               dmabuf->enable |= DMA_RUNNING;
+               dmabuf->enable |= DAC_RUNNING;
                trident_enable_voice_irq(card, chan_num);
                trident_start_voice(card, chan_num);
        }
@@ -818,39 +807,27 @@ static void start_dac(struct trident_state *state)
 #define DMABUF_MINORDER 1
 
 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct trident_state *state, unsigned rec)
+static int alloc_dmabuf(struct trident_state *state)
 {
-       struct dmabuf *dmabuf;
+       struct dmabuf *dmabuf = &state->dmabuf;
        void *rawbuf;
        int order;
        unsigned long map, mapend;
 
-       if (rec)
-               dmabuf  = &state->dma_adc;
-       else
-               dmabuf  = &state->dma_dac;
-
        /* alloc as big a chunk as we can, FIXME: is this necessary ?? */
        for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-               if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
+               if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
+                                                  PAGE_SIZE << order,
+                                                  &dmabuf->dma_handle)))
                        break;
        if (!rawbuf)
                return -ENOMEM;
+
 #ifdef DEBUG
        printk("trident: allocated %ld (order = %d) bytes at %p\n",
               PAGE_SIZE << order, order, rawbuf);
 #endif
 
-       /* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address
-          (LBA) which limits the address space to 1 (2) GB, bad T^2 design */
-       if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) {
-               printk(KERN_ERR "trident: DMA buffer beyond 1 GB; "
-                      "bus address = 0x%lx, size = %ld\n",
-                      virt_to_bus(rawbuf), PAGE_SIZE << order);
-               free_pages((unsigned long)rawbuf, order);
-               return -ENOMEM;
-       }
-
        dmabuf->ready  = dmabuf->mapped = 0;
        dmabuf->rawbuf = rawbuf;
        dmabuf->buforder = order;
@@ -864,16 +841,18 @@ static int alloc_dmabuf(struct trident_state *state, unsigned rec)
 }
 
 /* free DMA buffer */
-static void dealloc_dmabuf(struct dmabuf *dmabuf)
+static void dealloc_dmabuf(struct trident_state *state)
 {
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned long map, mapend;
 
        if (dmabuf->rawbuf) {
                /* undo marking the pages as reserved */
                mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
                for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++)
-                       clear_bit(PG_reserved, &mem_map[map].flags);    
-               free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder);
+                       clear_bit(PG_reserved, &mem_map[map].flags);
+               pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
+                                   dmabuf->rawbuf, dmabuf->dma_handle);
        }
        dmabuf->rawbuf = NULL;
        dmabuf->mapped = dmabuf->ready = 0;
@@ -881,25 +860,20 @@ static void dealloc_dmabuf(struct dmabuf *dmabuf)
 
 static int prog_dmabuf(struct trident_state *state, unsigned rec)
 {
-       struct dmabuf *dmabuf;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned bytepersec;
        unsigned bufsize;
        unsigned long flags;
        int ret;
 
-       if (rec)
-               dmabuf = &state->dma_adc;
-       else
-               dmabuf = &state->dma_dac;
-
        spin_lock_irqsave(&state->card->lock, flags);
-       dmabuf->hwptr  = dmabuf->swptr = dmabuf->total_bytes = 0;
-       dmabuf->count  = dmabuf->error = dmabuf->endcleared  = 0;
+       dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0;
+       dmabuf->count = dmabuf->error = 0;
        spin_unlock_irqrestore(&state->card->lock, flags);
 
        /* allocate DMA buffer if not allocated yet */
        if (!dmabuf->rawbuf)
-               if ((ret = alloc_dmabuf(state, rec)))
+               if ((ret = alloc_dmabuf(state)))
                        return ret;
 
        /* FIXME: figure out all this OSS fragment stuff */
@@ -958,7 +932,7 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
 */
 static void trident_clear_tail(struct trident_state *state)
 {
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned swptr;
        unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;
        unsigned int len;
@@ -971,7 +945,6 @@ static void trident_clear_tail(struct trident_state *state)
        if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)
                return;
 
-
        if (swptr < dmabuf->dmasize/2)
                len = dmabuf->dmasize/2 - swptr;
        else
@@ -979,7 +952,7 @@ static void trident_clear_tail(struct trident_state *state)
 
        memset(dmabuf->rawbuf + swptr, silence, len);
 
-       spin_lock_irqsave(&state->card->lock, flags);   
+       spin_lock_irqsave(&state->card->lock, flags);
        dmabuf->swptr += len;
        dmabuf->count += len;
        spin_unlock_irqrestore(&state->card->lock, flags);
@@ -991,7 +964,7 @@ static void trident_clear_tail(struct trident_state *state)
 static int drain_dac(struct trident_state *state, int nonblock)
 {
        DECLARE_WAITQUEUE(wait, current);
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned long flags;
        unsigned long tmo;
        int count;
@@ -1038,49 +1011,49 @@ static int drain_dac(struct trident_state *state, int nonblock)
        return 0;
 }
 
-/* call with spinlock held! */
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
 static void trident_update_ptr(struct trident_state *state)
 {
-       struct dmabuf *dmabuf;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned hwptr;
        int diff;
 
-       /* update ADC pointer */
-       if (state->dma_adc.ready) {
-               dmabuf = &state->dma_adc;
-               hwptr = trident_get_dma_addr(state, 1);
-               diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+       /* update hardware pointer */
+       hwptr = trident_get_dma_addr(state);
+       diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+       dmabuf->hwptr = hwptr;
+       dmabuf->total_bytes += diff;
 
-               dmabuf->hwptr = hwptr;
-               dmabuf->total_bytes += diff;
-               dmabuf->count += diff;
+       /* error handling and process wake up for DAC */
+       if (dmabuf->enable == ADC_RUNNING) {
+               if (dmabuf->mapped) {
+                       dmabuf->count -= diff;
+                       if (dmabuf->count >= (signed)dmabuf->fragsize)
+                               wake_up(&dmabuf->wait);
+               } else {
+                       dmabuf->count += diff;
 
-               if (dmabuf->count >= (signed)dmabuf->fragsize)
-                       wake_up(&dmabuf->wait);
-               if (!dmabuf->mapped) {
-                       if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) {
-                               __stop_adc(state); 
+                       if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+                               /* buffer underrun or buffer overrun, we have no way to recover
+                                  it here, just stop the machine and let the process force hwptr
+                                  and swptr to sync */
+                               __stop_adc(state);
                                dmabuf->error++;
                        }
+                       /* since dma machine only interrupts at ESO and ESO/2, we sure have at
+                          least half of dma buffer free, so wake up the process unconditionally */
+                       wake_up(&dmabuf->wait);
                }
        }
-
-       /* update DAC pointer */
-       if (state->dma_dac.ready) {
-               dmabuf = &state->dma_dac;
-               hwptr = trident_get_dma_addr(state, 0);
-               diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-
-               dmabuf->hwptr = hwptr;
-               dmabuf->total_bytes += diff;
-
+       /* error handling and process wake up for DAC */
+       if (dmabuf->enable == DAC_RUNNING) {
                if (dmabuf->mapped) {
                        dmabuf->count += diff;
-                       if (dmabuf->count >= (signed)dmabuf->fragsize) 
+                       if (dmabuf->count >= (signed)dmabuf->fragsize)
                                wake_up(&dmabuf->wait);
-               }
-               else {
+               } else {
                        dmabuf->count -= diff;
+
                        if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
                                /* buffer underrun or buffer overrun, we have no way to recover
                                   it here, just stop the machine and let the process force hwptr
@@ -1088,7 +1061,7 @@ static void trident_update_ptr(struct trident_state *state)
                                __stop_dac(state);
                                dmabuf->error++;
                        }
-                       /* since dma machine only interrupts at ESO and ESO/2, we sure have at 
+                       /* since dma machine only interrupts at ESO and ESO/2, we sure have at
                           least half of dma buffer free, so wake up the process unconditionally */
                        wake_up(&dmabuf->wait);
                }
@@ -1120,17 +1093,13 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                } else {
                                        printk("trident: spurious channel irq %d.\n",
                                               63 - i);
-                                       trident_stop_voice(card, i);
-                                       trident_disable_voice_irq(card, i);     
+                                       trident_stop_voice(card, 63 - i);
+                                       trident_disable_voice_irq(card, 63 - i);
                                }
                        }
                }
        }
 
-       if (event & SB_IRQ){
-               /* Midi - TODO */
-       }
-
        /* manually clear interrupt status, bad hardware design, blame T^2 */
        outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
             TRID_REG(card, T4D_MISCINT));
@@ -1142,18 +1111,21 @@ static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
        return -ESPIPE;
 }
 
-/* in this loop, dma_adc.count signifies the amount of data thats waiting
-   to be copied to the user's buffer.  it is filled by the interrupt
-   handler and drained by this loop. */
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
+   the user's buffer.  it is filled by the dma machine and drained by this loop. */
 static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
        struct trident_state *state = (struct trident_state *)file->private_data;
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        ssize_t ret;
        unsigned long flags;
        unsigned swptr;
        int cnt;
 
+#ifdef DEBUG
+       printk("trident: trident_read called, count = %d\n", count);
+#endif
+
        VALIDATE_STATE(state);
        if (ppos != &file->f_pos)
                return -ESPIPE;
@@ -1167,6 +1139,12 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
 
        while (count > 0) {
                spin_lock_irqsave(&state->card->lock, flags);
+               if (dmabuf->count > (signed) dmabuf->dmasize) {
+                       /* buffer overrun, we are recovering from sleep_on_timeout,
+                          resync hwptr and swptr, make process flush the buffer */
+                       dmabuf->count = dmabuf->dmasize;
+                       dmabuf->swptr = dmabuf->hwptr;
+               }
                swptr = dmabuf->swptr;
                cnt = dmabuf->dmasize - swptr;
                if (dmabuf->count < cnt)
@@ -1175,25 +1153,35 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
 
                if (cnt > count)
                        cnt = count;
-
                if (cnt <= 0) {
+                       unsigned long tmo;
+                       /* buffer is empty, start the dma machine and wait for data to be
+                          recorded */
                        start_adc(state);
                        if (file->f_flags & O_NONBLOCK) {
-                               ret = ret ? ret : -EAGAIN;
+                               if (!ret) ret = -EAGAIN;
                                return ret;
                        }
-                       if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) {
-                               printk(KERN_ERR
-                                      "(trident) read: chip lockup? "
+                       /* No matter how much space left in the buffer, we have to wait untill
+                          CSO == ESO/2 or CSO == ESO when address engine interrupts */
+                       tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+                       tmo >>= sample_shift[dmabuf->fmt];
+                       /* There are two situations when sleep_on_timeout returns, one is when
+                          the interrupt is serviced correctly and the process is waked up by
+                          ISR ON TIME. Another is when timeout is expired, which means that
+                          either interrupt is NOT serviced correctly (pending interrupt) or it
+                          is TOO LATE for the process to be scheduled to run (scheduler latency)
+                          which results in a (potential) buffer overrun. And worse, there is
+                          NOTHING we can do to prevent it. */
+                       if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+                               printk(KERN_ERR "trident: recording schedule timeout, "
                                       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
                                       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
                                       dmabuf->hwptr, dmabuf->swptr);
-                               stop_adc(state);
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               dmabuf->count = 0;
-                               dmabuf->hwptr = 0;
-                               dmabuf->swptr = 0;
-                               spin_unlock_irqrestore(&state->card->lock, flags);
+#endif
+                               /* a buffer overrun, we delay the recovery untill next time the
+                                  while loop begin and we REALLY have space to record */
                        }
                        if (signal_pending(current)) {
                                ret = ret ? ret : -ERESTARTSYS;
@@ -1203,7 +1191,7 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
                }
 
                if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-                       ret = ret ? ret : -EFAULT;
+                       if (!ret) ret = -EFAULT;
                        return ret;
                }
 
@@ -1219,14 +1207,15 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
                ret += cnt;
                start_adc(state);
        }
-
        return ret;
 }
 
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+   the soundcard.  it is drained by the dma machine and filled by this loop. */
 static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
        struct trident_state *state = (struct trident_state *)file->private_data;
-       struct dmabuf *dmabuf = &state->dma_dac;
+       struct dmabuf *dmabuf = &state->dmabuf;
        ssize_t ret;
        unsigned long flags;
        unsigned swptr;
@@ -1234,7 +1223,7 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
 
 #ifdef DEBUG
        printk("trident: trident_write called, count = %d\n", count);
-#endif 
+#endif
 
        VALIDATE_STATE(state);
        if (ppos != &file->f_pos)
@@ -1265,7 +1254,8 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
                        cnt = count;
                if (cnt <= 0) {
                        unsigned long tmo;
-                       /* buffer is full, start the dma machine and wait for data to be played */
+                       /* buffer is full, start the dma machine and wait for data to be
+                          played */
                        start_dac(state);
                        if (file->f_flags & O_NONBLOCK) {
                                if (!ret) ret = -EAGAIN;
@@ -1275,15 +1265,16 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
                           CSO == ESO/2 or CSO == ESO when address engine interrupts */
                        tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
                        tmo >>= sample_shift[dmabuf->fmt];
-                       /* There are two situations when sleep_on_timeout returns, one is when the
-                          interrupt is serviced correctly and the process is waked up by ISR ON TIME.
-                          Another is when timeout is expired, which means that either interrupt is NOT
-                          serviced correctly (pending interrupt) or it is TOO LATE for the process to 
-                          be scheduled to run (scheduler latency) which results in a (potential) buffer
-                          underrun. And worse, there is NOTHING we can do to prevent it. */
+                       /* There are two situations when sleep_on_timeout returns, one is when
+                          the interrupt is serviced correctly and the process is waked up by
+                          ISR ON TIME. Another is when timeout is expired, which means that
+                          either interrupt is NOT serviced correctly (pending interrupt) or it
+                          is TOO LATE for the process to be scheduled to run (scheduler latency)
+                          which results in a (potential) buffer underrun. And worse, there is
+                          NOTHING we can do to prevent it. */
                        if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
 #ifdef DEBUG
-                               printk(KERN_ERR "trident: schedule timeout, "
+                               printk(KERN_ERR "trident: playback schedule timeout, "
                                       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
                                       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
                                       dmabuf->hwptr, dmabuf->swptr);
@@ -1307,7 +1298,6 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
                spin_lock_irqsave(&state->card->lock, flags);
                dmabuf->swptr = swptr;
                dmabuf->count += cnt;
-               dmabuf->endcleared = 0;
                spin_unlock_irqrestore(&state->card->lock, flags);
 
                count -= cnt;
@@ -1320,32 +1310,33 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
 
 static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait)
 {
-       struct trident_state *s = (struct trident_state *)file->private_data;
+       struct trident_state *state = (struct trident_state *)file->private_data;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned long flags;
        unsigned int mask = 0;
 
-       VALIDATE_STATE(s);
+       VALIDATE_STATE(state);
        if (file->f_mode & FMODE_WRITE)
-               poll_wait(file, &s->dma_dac.wait, wait);
+               poll_wait(file, &dmabuf->wait, wait);
        if (file->f_mode & FMODE_READ)
-               poll_wait(file, &s->dma_adc.wait, wait);
+               poll_wait(file, &dmabuf->wait, wait);
 
-       spin_lock_irqsave(&s->card->lock, flags);
-       trident_update_ptr(s);
+       spin_lock_irqsave(&state->card->lock, flags);
+       trident_update_ptr(state);
        if (file->f_mode & FMODE_READ) {
-               if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+               if (dmabuf->count >= (signed)dmabuf->fragsize)
                        mask |= POLLIN | POLLRDNORM;
        }
        if (file->f_mode & FMODE_WRITE) {
-               if (s->dma_dac.mapped) {
-                       if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
+               if (dmabuf->mapped) {
+                       if (dmabuf->count >= (signed)dmabuf->fragsize)
                                mask |= POLLOUT | POLLWRNORM;
                } else {
-                       if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+                       if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
                                mask |= POLLOUT | POLLWRNORM;
                }
        }
-       spin_unlock_irqrestore(&s->card->lock, flags);
+       spin_unlock_irqrestore(&state->card->lock, flags);
 
        return mask;
 }
@@ -1353,7 +1344,7 @@ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wa
 static int trident_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct trident_state *state = (struct trident_state *)file->private_data;
-       struct dmabuf *dmabuf;
+       struct dmabuf *dmabuf = &state->dmabuf;
        int ret;
        unsigned long size;
 
@@ -1361,11 +1352,9 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma)
        if (vma->vm_flags & VM_WRITE) {
                if ((ret = prog_dmabuf(state, 0)) != 0)
                        return ret;
-               dmabuf = &state->dma_dac;
        } else if (vma->vm_flags & VM_READ) {
                if ((ret = prog_dmabuf(state, 1)) != 0)
                        return ret;
-               dmabuf = &state->dma_adc;
        } else 
                return -EINVAL;
 
@@ -1385,14 +1374,15 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma)
 static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct trident_state *state = (struct trident_state *)file->private_data;
+       struct dmabuf *dmabuf = &state->dmabuf;
        unsigned long flags;
        audio_buf_info abinfo;
        count_info cinfo;
        int val, mapped, ret;
 
        VALIDATE_STATE(state);
-       mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) ||
-               ((file->f_mode & FMODE_READ) && state->dma_adc.mapped);
+       mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
+               ((file->f_mode & FMODE_READ) && dmabuf->mapped);
 #ifdef DEBUG
        printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
               _IOC_NR(cmd), arg ? *(int *)arg : 0);
@@ -1404,19 +1394,20 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                return put_user(SOUND_VERSION, (int *)arg);
 
        case SNDCTL_DSP_RESET:
+               /* FIXME: spin_lock ? */
                if (file->f_mode & FMODE_WRITE) {
                        stop_dac(state);
                        synchronize_irq();
-                       state->dma_dac.ready = 0;
-                       state->dma_dac.swptr = state->dma_dac.hwptr = 0;
-                       state->dma_dac.count = state->dma_dac.total_bytes = 0;
+                       dmabuf->ready = 0;
+                       dmabuf->swptr = dmabuf->hwptr = 0;
+                       dmabuf->count = dmabuf->total_bytes = 0;
                }
                if (file->f_mode & FMODE_READ) {
                        stop_adc(state);
                        synchronize_irq();
-                       state->dma_adc.ready = 0;
-                       state->dma_adc.swptr = state->dma_adc.hwptr = 0;
-                       state->dma_adc.count = state->dma_adc.total_bytes = 0;
+                       dmabuf->ready = 0;
+                       dmabuf->swptr = dmabuf->hwptr = 0;
+                       dmabuf->count = dmabuf->total_bytes = 0;
                }
                return 0;
 
@@ -1430,40 +1421,38 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                if (val >= 0) {
                        if (file->f_mode & FMODE_WRITE) {
                                stop_dac(state);
-                               state->dma_dac.ready = 0;
+                               dmabuf->ready = 0;
                                spin_lock_irqsave(&state->card->lock, flags);
                                trident_set_dac_rate(state, val);
                                spin_unlock_irqrestore(&state->card->lock, flags);
                        }
                        if (file->f_mode & FMODE_READ) {
                                stop_adc(state);
-                               state->dma_adc.ready = 0;
+                               dmabuf->ready = 0;
                                spin_lock_irqsave(&state->card->lock, flags);
                                trident_set_adc_rate(state, val);
                                spin_unlock_irqrestore(&state->card->lock, flags);
                        }
                }
-               return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
-                               state->dma_dac.rate,
-                               (int *)arg);
+               return put_user(dmabuf->rate, (int *)arg);
 
        case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
                get_user_ret(val, (int *)arg, -EFAULT);
                if (file->f_mode & FMODE_WRITE) {
                        stop_dac(state);
-                       state->dma_dac.ready = 0;
+                       dmabuf->ready = 0;
                        if (val)
-                               state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
+                               dmabuf->fmt |= TRIDENT_FMT_STEREO;
                        else
-                               state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
+                               dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
                }
                if (file->f_mode & FMODE_READ) {
                        stop_adc(state);
-                       state->dma_adc.ready = 0;
+                       dmabuf->ready = 0;
                        if (val)
-                               state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
+                               dmabuf->fmt |= TRIDENT_FMT_STEREO;
                        else
-                               state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
+                               dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
                }
                return 0;
 
@@ -1471,12 +1460,12 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                if (file->f_mode & FMODE_WRITE) {
                        if ((val = prog_dmabuf(state, 0)))
                                return val;
-                       return put_user(state->dma_dac.fragsize, (int *)arg);
+                       return put_user(dmabuf->fragsize, (int *)arg);
                }
                if (file->f_mode & FMODE_READ) {
                        if ((val = prog_dmabuf(state, 1)))
                                return val;
-                       return put_user(state->dma_adc.fragsize, (int *)arg);
+                       return put_user(dmabuf->fragsize, (int *)arg);
                }
 
        case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
@@ -1487,120 +1476,99 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                if (val != AFMT_QUERY) {
                        if (file->f_mode & FMODE_WRITE) {
                                stop_dac(state);
-                               state->dma_dac.ready = 0;
+                               dmabuf->ready = 0;
                                if (val == AFMT_S16_LE)
-                                       state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
+                                       dmabuf->fmt |= TRIDENT_FMT_16BIT;
                                else
-                                       state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT;
+                                       dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
                        }
                        if (file->f_mode & FMODE_READ) {
                                stop_adc(state);
-                               state->dma_adc.ready = 0;
+                               dmabuf->ready = 0;
                                if (val == AFMT_S16_LE)
-                                       state->dma_adc.fmt |= TRIDENT_FMT_16BIT;
+                                       dmabuf->fmt |= TRIDENT_FMT_16BIT;
                                else
-                                       state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT;
+                                       dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
                        }
                }
-               if (file->f_mode & FMODE_WRITE)
-                       return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
-                                       AFMT_S16_LE : AFMT_U8, (int *)arg);
-               else
-                       return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
-                                       AFMT_S16_LE : AFMT_U8, (int *)arg);
+               return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
+                               AFMT_S16_LE : AFMT_U8, (int *)arg);
 
        case SNDCTL_DSP_CHANNELS:
                get_user_ret(val, (int *)arg, -EFAULT);
                if (val != 0) {
                        if (file->f_mode & FMODE_WRITE) {
                                stop_dac(state);
-                               state->dma_dac.ready = 0;
+                               dmabuf->ready = 0;
                                if (val >= 2)
-                                       state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
+                                       dmabuf->fmt |= TRIDENT_FMT_STEREO;
                                else
-                                       state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
+                                       dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
                        }
                        if (file->f_mode & FMODE_READ) {
                                stop_adc(state);
-                               state->dma_adc.ready = 0;
+                               dmabuf->ready = 0;
                                if (val >= 2)
-                                       state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
+                                       dmabuf->fmt |= TRIDENT_FMT_STEREO;
                                else
-                                       state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
+                                       dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
                        }
                }
-               if (file->f_mode & FMODE_WRITE)
-                       return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-                                       (int *)arg);
-               else
-                       return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-                                       (int *)arg);
+               return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+                               (int *)arg);
+
        case SNDCTL_DSP_POST:
                /* FIXME: the same as RESET ?? */
                return 0;
 
        case SNDCTL_DSP_SUBDIVIDE:
-               if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) ||
-                   (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision))
+               if (dmabuf->subdivision)
                        return -EINVAL;
                get_user_ret(val, (int *)arg, -EFAULT);
                if (val != 1 && val != 2 && val != 4)
                        return -EINVAL;
-               if (file->f_mode & FMODE_READ)
-                       state->dma_adc.subdivision = val;
-               if (file->f_mode & FMODE_WRITE)
-                       state->dma_dac.subdivision = val;
+               dmabuf->subdivision = val;
                return 0;
 
        case SNDCTL_DSP_SETFRAGMENT:
                get_user_ret(val, (int *)arg, -EFAULT);
-               if (file->f_mode & FMODE_READ) {
-                       state->dma_adc.ossfragshift = val & 0xffff;
-                       state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-                       if (state->dma_adc.ossfragshift < 4)
-                               state->dma_adc.ossfragshift = 4;
-                       if (state->dma_adc.ossfragshift > 15)
-                               state->dma_adc.ossfragshift = 15;
-                       if (state->dma_adc.ossmaxfrags < 4)
-                               state->dma_adc.ossmaxfrags = 4;
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       state->dma_dac.ossfragshift = val & 0xffff;
-                       state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-                       if (state->dma_dac.ossfragshift < 4)
-                               state->dma_dac.ossfragshift = 4;
-                       if (state->dma_dac.ossfragshift > 15)
-                               state->dma_dac.ossfragshift = 15;
-                       if (state->dma_dac.ossmaxfrags < 4)
-                               state->dma_dac.ossmaxfrags = 4;
-               }
+
+               dmabuf->ossfragshift = val & 0xffff;
+               dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+               if (dmabuf->ossfragshift < 4)
+                       dmabuf->ossfragshift = 4;
+               if (dmabuf->ossfragshift > 15)
+                       dmabuf->ossfragshift = 15;
+               if (dmabuf->ossmaxfrags < 4)
+                       dmabuf->ossmaxfrags = 4;
+
                return 0;
 
        case SNDCTL_DSP_GETOSPACE:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
-               if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0)
+               if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)
                        return val;
                spin_lock_irqsave(&state->card->lock, flags);
                trident_update_ptr(state);
-               abinfo.fragsize = state->dma_dac.fragsize;
-               abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count;
-               abinfo.fragstotal = state->dma_dac.numfrag;
-               abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift;      
+               abinfo.fragsize = dmabuf->fragsize;
+               abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+               abinfo.fragstotal = dmabuf->numfrag;
+               abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
                spin_unlock_irqrestore(&state->card->lock, flags);
                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
        case SNDCTL_DSP_GETISPACE:
                if (!(file->f_mode & FMODE_READ))
                        return -EINVAL;
-               if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0)
+               if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)
                        return val;
                spin_lock_irqsave(&state->card->lock, flags);
                trident_update_ptr(state);
-               abinfo.fragsize = state->dma_adc.fragsize;
-               abinfo.bytes = state->dma_adc.count;
-               abinfo.fragstotal = state->dma_adc.numfrag;
-               abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift;      
+               abinfo.fragsize = dmabuf->fragsize;
+               abinfo.bytes = dmabuf->count;
+               abinfo.fragstotal = dmabuf->numfrag;
+               abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
                spin_unlock_irqrestore(&state->card->lock, flags);
                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
@@ -1609,14 +1577,13 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
-           return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
-                           (int *)arg);
+           return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg);
 
        case SNDCTL_DSP_GETTRIGGER:
                val = 0;
-               if (file->f_mode & FMODE_READ && state->dma_adc.enable) 
+               if (file->f_mode & FMODE_READ && dmabuf->enable)
                        val |= PCM_ENABLE_INPUT;
-               if (file->f_mode & FMODE_WRITE && state->dma_dac.enable) 
+               if (file->f_mode & FMODE_WRITE && dmabuf->enable)
                        val |= PCM_ENABLE_OUTPUT;
                return put_user(val, (int *)arg);
 
@@ -1624,20 +1591,18 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                get_user_ret(val, (int *)arg, -EFAULT);
                if (file->f_mode & FMODE_READ) {
                        if (val & PCM_ENABLE_INPUT) {
-                               if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
+                               if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
                                        return ret;
                                start_adc(state);
-                       } 
-                       else
+                       } else
                                stop_adc(state);
                }
                if (file->f_mode & FMODE_WRITE) {
                        if (val & PCM_ENABLE_OUTPUT) {
-                               if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
+                               if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
                                        return ret;
                                start_dac(state);
-                       } 
-                       else
+                       } else
                                stop_dac(state);
                }
                return 0;
@@ -1647,59 +1612,50 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
                        return -EINVAL;
                spin_lock_irqsave(&state->card->lock, flags);
                trident_update_ptr(state);
-               cinfo.bytes = state->dma_adc.total_bytes;
-               cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift;
-               cinfo.ptr = state->dma_adc.hwptr;
-               if (state->dma_adc.mapped)
-                       state->dma_adc.count &= state->dma_adc.fragsize-1;
+               cinfo.bytes = dmabuf->total_bytes;
+               cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+               cinfo.ptr = dmabuf->hwptr;
+               if (dmabuf->mapped)
+                       dmabuf->count &= dmabuf->fragsize-1;
                spin_unlock_irqrestore(&state->card->lock, flags);
                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-               
+
        case SNDCTL_DSP_GETOPTR:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
                spin_lock_irqsave(&state->card->lock, flags);
                trident_update_ptr(state);
-               cinfo.bytes = state->dma_dac.total_bytes;
-               cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift;
-               cinfo.ptr = state->dma_dac.hwptr;
-               if (state->dma_dac.mapped)
-                       state->dma_dac.count &= state->dma_dac.fragsize-1;
+               cinfo.bytes = dmabuf->total_bytes;
+               cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+               cinfo.ptr = dmabuf->hwptr;
+               if (dmabuf->mapped)
+                       dmabuf->count &= dmabuf->fragsize-1;
                spin_unlock_irqrestore(&state->card->lock, flags);
                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
        case SNDCTL_DSP_SETDUPLEX:
-               /* XXX fix */
-               return 0;
+               return -EINVAL;
 
        case SNDCTL_DSP_GETODELAY:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
                spin_lock_irqsave(&state->card->lock, flags);
                trident_update_ptr(state);
-               val = state->dma_dac.count;
+               val = dmabuf->count;
                spin_unlock_irqrestore(&state->card->lock, flags);
                return put_user(val, (int *)arg);
 
        case SOUND_PCM_READ_RATE:
-               return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
-                               state->dma_dac.rate, (int *)arg);
+               return put_user(dmabuf->rate, (int *)arg);
 
        case SOUND_PCM_READ_CHANNELS:
-               if (file->f_mode & FMODE_WRITE)
-                       return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-                                       (int *)arg);
-               else
-                       return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-                                       (int *)arg);
-               
+               return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+                               (int *)arg);
+
        case SOUND_PCM_READ_BITS:
-               if (file->f_mode & FMODE_WRITE)
-                       return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
-                                       AFMT_S16_LE : AFMT_U8, (int *)arg);
-               else
-                       return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
-                                       AFMT_S16_LE : AFMT_U8, (int *)arg);
+               return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
+                               AFMT_S16_LE : AFMT_U8, (int *)arg);
+
        case SNDCTL_DSP_MAPINBUF:
        case SNDCTL_DSP_MAPOUTBUF:
        case SNDCTL_DSP_SETSYNCRO:
@@ -1738,70 +1694,61 @@ static int trident_open(struct inode *inode, struct file *file)
 
  found_virt:
        /* found a free virtual channel, allocate hardware channels */
-       if (file->f_mode & FMODE_READ)
-               if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) {
-                       kfree (card->states[i]);
-                       card->states[i] = NULL;;
-                       return -ENODEV;
-               }
-       if (file->f_mode & FMODE_WRITE)
-               if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) {
-                       kfree (card->states[i]);
-                       card->states[i] = NULL;
-                       if (file->f_mode & FMODE_READ)
-                               /* free previously allocated hardware channel */
-                               trident_free_pcm_channel(card, state->dma_adc.channel->num);
-                       return -ENODEV;
-               }
+       if ((state->dmabuf.channel = trident_alloc_pcm_channel(card)) == NULL) {
+               kfree (card->states[i]);
+               card->states[i] = NULL;;
+               return -ENODEV;
+       }
 
        /* initialize the virtual channel */
        state->virt = i;
        state->card = card;
        state->magic = TRIDENT_STATE_MAGIC;
-       init_waitqueue_head(&state->dma_adc.wait);
-       init_waitqueue_head(&state->dma_dac.wait);
+       init_waitqueue_head(&state->dmabuf.wait);
        init_MUTEX(&state->open_sem);
        file->private_data = state;
 
        down(&state->open_sem);
 
-       /* set default sample format, Refer to  OSS Programmer's Guide */
-       if (file->f_mode & FMODE_READ) {
-               /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */
-               state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT;
-               state->dma_adc.ossfragshift = 0;
-               state->dma_adc.ossmaxfrags  = 0;
-               state->dma_adc.subdivision  = 0;
-               trident_set_adc_rate(state, 48000);
-       }
-
-       /* according to OSS document, /dev/dsp should be default to unsigned 8-bits, 
-          mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */
+       /* set default sample format. According to OSS Programmer's Guide  /dev/dsp
+          should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+          /dev/dspW will accept 16-bits sample */
        if (file->f_mode & FMODE_WRITE) {
-               state->dma_dac.fmt &= ~TRIDENT_FMT_MASK;
+               state->dmabuf.fmt &= ~TRIDENT_FMT_MASK;
                if ((minor & 0xf) == SND_DEV_DSP16)
-                        state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
-               state->dma_dac.ossfragshift = 0;
-               state->dma_dac.ossmaxfrags  = 0;
-               state->dma_dac.subdivision  = 0;
+                       state->dmabuf.fmt |= TRIDENT_FMT_16BIT;
+               state->dmabuf.ossfragshift = 0;
+               state->dmabuf.ossmaxfrags  = 0;
+               state->dmabuf.subdivision  = 0;
                trident_set_dac_rate(state, 8000);
        }
 
+       if (file->f_mode & FMODE_READ) {
+               /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample,
+                  to be dealed with in trident_set_adc_rate() ?? */
+               state->dmabuf.fmt &= ~TRIDENT_FMT_MASK;
+               if ((minor & 0xf) == SND_DEV_DSP16)
+                       state->dmabuf.fmt |= TRIDENT_FMT_16BIT;
+               state->dmabuf.ossfragshift = 0;
+               state->dmabuf.ossmaxfrags  = 0;
+               state->dmabuf.subdivision  = 0;
+               trident_set_adc_rate(state, 8000);
+       }
+
        state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
        up(&state->open_sem);
 
-       //FIXME put back in
-       //MOD_INC_USE_COUNT;
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
 static int trident_release(struct inode *inode, struct file *file)
 {
        struct trident_state *state = (struct trident_state *)file->private_data;
+       struct dmabuf *dmabuf = &state->dmabuf;
 
        VALIDATE_STATE(state);
 
-
        if (file->f_mode & FMODE_WRITE) {
                trident_clear_tail(state);
                drain_dac(state, file->f_flags & O_NONBLOCK);
@@ -1812,13 +1759,13 @@ static int trident_release(struct inode *inode, struct file *file)
 
        if (file->f_mode & FMODE_WRITE) {
                stop_dac(state);
-               dealloc_dmabuf(&state->dma_dac);
-               trident_free_pcm_channel(state->card, state->dma_dac.channel->num);
+               dealloc_dmabuf(state);
+               trident_free_pcm_channel(state->card, dmabuf->channel->num);
        }
        if (file->f_mode & FMODE_READ) {
                stop_adc(state);
-               dealloc_dmabuf(&state->dma_adc);
-               trident_free_pcm_channel(state->card, state->dma_adc.channel->num);
+               dealloc_dmabuf(state);
+               trident_free_pcm_channel(state->card, dmabuf->channel->num);
        }
 
        kfree(state->card->states[state->virt]);
@@ -1828,8 +1775,7 @@ static int trident_release(struct inode *inode, struct file *file)
        /* we're covered by the open_sem */
        up(&state->open_sem);
 
-       //FIXME put back in
-       //MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1845,7 +1791,7 @@ static /*const*/ struct file_operations trident_audio_fops = {
 };
 
 /* trident specific AC97 functions */
-/* Write AC97 mixer registers */
+/* Write AC97 codec registers */
 static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
 {
        struct trident_card *card = (struct trident_card *)codec->private_data;
@@ -1863,7 +1809,7 @@ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
                address = SI_AC97_WRITE;
                mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
                if (codec->id)
-                   mask |= SI_AC97_SECONDARY;
+                       mask |= SI_AC97_SECONDARY;
                busy = SI_AC97_BUSY_WRITE;
                break;
        case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
@@ -1874,7 +1820,7 @@ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
                address = NX_ACR1_AC97_W;
                mask = NX_AC97_BUSY_WRITE;
                if (codec->id)
-                   mask |= NX_AC97_WRITE_SECONDARY;
+                       mask |= NX_AC97_WRITE_SECONDARY;
                busy = NX_AC97_BUSY_WRITE;
                break;
        }
@@ -1968,17 +1914,13 @@ static int trident_open_mixdev(struct inode *inode, struct file *file)
  match:
        file->private_data = card->ac97_codec[i];
 
-       //FIXME put back in
-       //MOD_INC_USE_COUNT;
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
 static int trident_release_mixdev(struct inode *inode, struct file *file)
 {
-       //struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
-       //FIXME put back in
-       //MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -2061,36 +2003,35 @@ static int __init trident_ac97_init(struct trident_card *card)
 }
 
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */
-static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
+   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+static int __devinit trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
-       u16 w;
        unsigned long iobase;
        struct trident_card *card;
 
-       iobase = pcidev->resource[0].start;
+       if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) {
+               printk(KERN_ERR "trident: architecture does not support"
+                      " 30bit PCI busmaster DMA\n");
+               return -1;
+       }
+
+       iobase = pci_dev->resource[0].start;
        if (check_region(iobase, 256)) {
                printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
                       iobase);
-               return 0;
+               return -1;
        }
 
-       /* just to be sure that IO space and bus master is on */
-       pci_set_master(pcidev); 
-       pci_read_config_word(pcidev, PCI_COMMAND, &w);
-       w |= PCI_COMMAND_IO|PCI_COMMAND_MASTER;
-       pci_write_config_word(pcidev, PCI_COMMAND, w);
-
        if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
                printk(KERN_ERR "trident: out of memory\n");
-               return 0;
+               return -1;
        }
        memset(card, 0, sizeof(*card));
 
        card->iobase = iobase;
-       card->pci_info = pci_info;
-       card->pci_id = pci_info->device;
-       card->irq = pcidev->irq;
+       card->pci_dev = pci_dev;
+       card->pci_id = pci_id->device;
+       card->irq = pci_dev->irq;
        card->next = devs;
        card->magic = TRIDENT_CARD_MAGIC;
        card->banks[BANK_A].addresses = &bank_a_addrs;
@@ -2098,14 +2039,18 @@ static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info
        card->banks[BANK_B].addresses = &bank_b_addrs;
        card->banks[BANK_B].bitmap = 0UL;
        spin_lock_init(&card->lock);
-       devs = card;    
+       devs = card;
+
+       pci_set_master(pci_dev);
+       pci_enable_device(pci_dev);
 
        printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
-              card->pci_info->name, card->iobase, card->irq);
+              card_names[pci_id->driver_data], card->iobase, card->irq);
 
        /* claim our iospace and irq */
-       request_region(card->iobase, 256, card->pci_info->name);
-       if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) {
+       request_region(card->iobase, 256, card_names[pci_id->driver_data]);
+       if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ,
+                       card_names[pci_id->driver_data], card)) {
                printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq);
                release_region(card->iobase, 256);
                kfree(card);
@@ -2117,7 +2062,7 @@ static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info
                release_region(iobase, 256);
                free_irq(card->irq, card);
                kfree(card);
-               return 0;
+               return -1;
        }
        /* initilize AC97 codec and register /dev/mixer */
        if (trident_ac97_init(card) <= 0) {
@@ -2125,68 +2070,66 @@ static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info
                release_region(iobase, 256);
                free_irq(card->irq, card);
                kfree(card);
-               return 0;
+               return -1;
        }
        outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
 
+       pci_dev->driver_data = card;
+       pci_dev->dma_mask = TRIDENT_DMA_MASK;
+
        /* Enable Address Engine Interrupts */
        trident_enable_loop_interrupts(card);
 
-       return 1; 
+       return 0;
 }
 
-static int __init init_trident(void)
+static void __devexit trident_remove(struct pci_dev *pci_dev)
 {
-       struct pci_dev *pcidev = NULL;
-       int foundone = 0;
        int i;
+       struct trident_card *card = pci_dev->driver_data;
 
-       if (!pci_present())   /* No PCI bus in this machine! */
-               return -ENODEV;
+       /* Kill interrupts, and SP/DIF */
+       trident_disable_loop_interrupts(card);
 
-       printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
-              DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+       /* free hardware resources */
+       free_irq(card->irq, devs);
+       release_region(card->iobase, 256);
 
-       for (i = 0; i < sizeof (pci_audio_devices); i++) {
-               pcidev = NULL;
-               while ((pcidev = pci_find_device(pci_audio_devices[i].vendor,
-                                                pci_audio_devices[i].device,
-                                                pcidev)) != NULL) {
-                       foundone += trident_install(pcidev, pci_audio_devices + i);
+       /* unregister audio devices */
+       for (i = 0; i < NR_AC97; i++)
+               if (devs->ac97_codec[i] != NULL) {
+                       unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
+                       kfree (card->ac97_codec[i]);
                }
-       }
+       unregister_sound_dsp(card->dev_audio);
 
-       if (!foundone)
-               return -ENODEV;
-       return 0;
+       kfree(card);
 }
 
 MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
 MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
 
-static void __exit cleanup_trident(void)
-{
-       while (devs != NULL) {
-               int i;
-               /* Kill interrupts, and SP/DIF */
-               trident_disable_loop_interrupts(devs);
+#define TRIDENT_MODULE_NAME "trident"
 
-               /* free hardware resources */
-               free_irq(devs->irq, devs);
-               release_region(devs->iobase, 256);
+static struct pci_driver trident_pci_driver = {
+       name:           TRIDENT_MODULE_NAME,
+       id_table:       trident_pci_tbl,
+       probe:          trident_probe,
+       remove:         trident_remove,
+};
 
-               /* unregister audio devices */
-               for (i = 0; i < NR_AC97; i++)
-                       if (devs->ac97_codec[i] != NULL) {
-                               unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer);
-                               kfree (devs->ac97_codec[i]);
-                       }
-               unregister_sound_dsp(devs->dev_audio);
+static int __init trident_init_module (void)
+{
+       printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+              DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
-               kfree(devs);
-               devs = devs->next;
-       }
+       return pci_module_init (&trident_pci_driver);
+}
+
+static void __exit trident_cleanup_module (void)
+{
+       pci_unregister_driver (&trident_pci_driver);
 }
 
-module_init(init_trident);
-module_exit(cleanup_trident);
+module_init(trident_init_module);
+module_exit(trident_cleanup_module);
index 4504cb30390a9adf18b89aced8b1c7cdbfeba8ce..6bbb25bd1594b88aa65fa8af40fe124b6de1a55e 100644 (file)
 #define TRIDENT_FMT_16BIT      0x02
 #define TRIDENT_FMT_MASK       0x03
 
-#define DMA_ENABLE     0x01
-#define DMA_RUNNING    0x02
-
+#define DAC_RUNNING    0x01
+#define ADC_RUNNING    0x02
 /* Register Addresses */
 
 /* operational registers common to DX, NX, 7018 */
 enum trident_op_registers {
+       T4D_REC_CH      = 0x70,
        T4D_START_A     = 0x80, T4D_STOP_A      = 0x84,
        T4D_DLY_A       = 0x88, T4D_SIGN_CSO_A  = 0x8c,
        T4D_CSPF_A      = 0x90, T4D_CEBC_A      = 0x94,
index bf6c23b53aba888effe2c6bec979bf29467ada90..39659ca553c395e35e36a4c31ab285ca00df2f68 100644 (file)
@@ -45,7 +45,7 @@ comment 'USB Devices'
    dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
    dep_tristate '  PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB
-   dep_tristate '  USB ADMteks Pegasus based devices support' CONFIG_USB_PEGASUS $CONFIG_USB
+   dep_tristate '  USB ADMtek Pegasus-based device support' CONFIG_USB_PEGASUS $CONFIG_USB
    dep_tristate '  USB Diamond Rio500 support' CONFIG_USB_RIO500 $CONFIG_USB
    
 comment 'USB HID'
index bb017e60c6bbdf65d03133964b5d9db1efecfdec..9bc13642063ee23e342db702fbf8c980f70e90ec 100644 (file)
@@ -1264,7 +1264,7 @@ static int rh_submit_urb (urb_t * urb)
        int status = TD_CC_NOERROR;
        
        __u32 datab[4];
-       __u8  * data_buf = datab;
+       __u8  * data_buf = (__u8 *) datab;
        
        __u16 bmRType_bReq;
        __u16 wValue; 
index 6b9615e72b610060bc15a1b6df30943c410d06b8..40c935ce930b2d15d83372706f65f67c0bf8a17f 100644 (file)
@@ -1347,6 +1347,8 @@ static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned
                                               urb_value , 0,
                                               buf, 0, HZ * 5));
        }
+
+       return -ENOIOCTLCMD;
 }
 
 #endif /* CONFIG_USB_SERIAL_FTDI_SIO */
index 4e8c4e9d46509542ce80a7c94c8d1a0d5731053c..82c916d8a499e691e200f604f6d0bb75bef3a5d6 100644 (file)
@@ -517,8 +517,8 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
        rinfo->riva.Architecture = rci->arch_rev;
 
        rinfo->pd = pd;
-       rinfo->base0_region_size = pci_resource_start (pd, 0);
-       rinfo->base1_region_size = pci_resource_start (pd, 1);
+       rinfo->base0_region_size = pci_resource_len (pd, 0);
+       rinfo->base1_region_size = pci_resource_len (pd, 1);
 
        assert (rinfo->base0_region_size >= 0x00800000);        /* from GGI */
        assert (rinfo->base0_region_size >= 0x01000000);        /* from GGI */
index 5a202c7e1d4df5e51f56bb3d577b386546415457..c455a735d7699c73a24da17f7f00f5cd959b03f6 100644 (file)
@@ -630,7 +630,7 @@ int blkdev_put(struct block_device *bdev, int kind)
        /* syncing will go here */
        if (kind == BDEV_FILE || kind == BDEV_FS)
                fsync_dev(rdev);
-       if (atomic_dec_and_test(&bdev->bd_openers) && MAJOR(rdev) != RAMDISK_MAJOR) {
+       if (atomic_dec_and_test(&bdev->bd_openers)) {
                /* invalidating buffers will go here */
                invalidate_buffers(rdev);
        }
index db58636722fe4f304ebed3003ba6d441adaab183..1a6eddc87ee68d3dfc5f5110528505ff16e15d40 100644 (file)
@@ -664,8 +664,11 @@ void __init proc_misc_init(void)
                }
        }
 #ifdef __powerpc__
-       entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
-       if (entry)
-               entry->proc_fops = &ppc_htab_operations;
+       {
+               extern struct file_operations ppc_htab_operations;
+               entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
+               if (entry)
+                       entry->proc_fops = &ppc_htab_operations;
+       }
 #endif
 }
index 6cdb2ad19d13e8e375a4a190c0507f67abb58f34..cce48d845b076c5cb07e5543242e2992689335d7 100644 (file)
@@ -70,9 +70,6 @@ void __init proc_root_init(void)
        proc_mkdir("openprom", 0);
 #endif
        proc_tty_init();
-#ifdef __powerpc__
-       proc_register(&proc_root, &proc_root_ppc_htab);
-#endif
 #ifdef CONFIG_PROC_DEVICETREE
        proc_device_tree_init();
 #endif
index b2d7f1ab4d94d6d6e6c0c683437fd88408a87e3c..b92eed7db895bbc243e180be70d83f21f2783583 100644 (file)
@@ -9,6 +9,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/types.h>
 
 #ifndef LINUX_VERSION_CODE
index 4cbcd785079d2c4a4f3f587af6f974f0256d03c3..ca2fb05297939cdceb269bf3f64f011a314557a2 100644 (file)
@@ -2,10 +2,7 @@
 #define _PPC_TYPES_H
 
 #ifndef __ASSEMBLY__
-/*
- * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
- * header files exported to user space
- */
+#ifdef __KERNEL__
 
 typedef unsigned short umode_t;
 
@@ -42,8 +39,6 @@ typedef struct {
        u32 u[4];
 } __attribute((aligned(16))) vector128;
 
-#ifdef __KERNEL__
-
 #define BITS_PER_LONG 32
 
 /* DMA addresses are 32-bits wide */
index 7090e062577c1a9e0b44f804868f01ee31418d60..50c75c3a846bc47d9e67bb1f42d551c37128aaa9 100644 (file)
 /* record mux defines */
 #define AC97_RECMUX_MIC           0x0000
 #define AC97_RECMUX_CD            0x0101
-#define AC97_RECMUX_VIDEO         0x0202       /* not used */
-#define AC97_RECMUX_AUX           0x0303      
-#define AC97_RECMUX_LINE          0x0404      
+#define AC97_RECMUX_VIDEO         0x0202
+#define AC97_RECMUX_AUX           0x0303
+#define AC97_RECMUX_LINE          0x0404
 #define AC97_RECMUX_STEREO_MIX    0x0505
 #define AC97_RECMUX_MONO_MIX      0x0606
 #define AC97_RECMUX_PHONE         0x0707
 
-
 /* general purpose register bit defines */
 #define AC97_GP_LPBK              0x0080       /* Loopback mode */
 #define AC97_GP_MS                0x0100       /* Mic Select 0=Mic1, 1=Mic2 */
@@ -73,7 +72,6 @@
 #define AC97_GP_ST                0x4000       /* Stereo Enhancement 1=on */
 #define AC97_GP_POP               0x8000       /* Pcm Out Path, 0=pre 3D, 1=post 3D */
 
-
 /* powerdown control and status bit defines */
 
 /* status */
        SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT)
 
 #define AC97_RECORD_MASK (SOUND_MASK_MIC|\
-       SOUND_MASK_CD|SOUND_MASK_VIDEO|\
+       SOUND_MASK_CD|SOUND_MASK_IGAIN|SOUND_MASK_VIDEO|\
        SOUND_MASK_LINE1| SOUND_MASK_LINE|\
        SOUND_MASK_PHONEIN)
 
index 3f15c3063b5e4798ced938419bad68e5cff702d9..a1d9b293943a9c361c41d72301920e7877a64121 100644 (file)
@@ -5,13 +5,12 @@
  *               1994, 1995   Eberhard Moenkeberg, emoenke@gwdg.de
  *               1996         David van Leeuwen, david@tm.tno.nl
  *               1997, 1998   Erik Andersen, andersee@debian.org
- *               1998, 1999   Jens Axboe, axboe@image.dk
+ *               1998-2000    Jens Axboe, axboe@suse.de
  */
  
 #ifndef        _LINUX_CDROM_H
 #define        _LINUX_CDROM_H
 
-#include <linux/types.h>
 #include <asm/byteorder.h>
 
 /*******************************************************
@@ -225,7 +224,7 @@ struct cdrom_tocentry
 struct cdrom_read      
 {
        int     cdread_lba;
-       caddr_t cdread_bufaddr;
+       char    *cdread_bufaddr;
        int     cdread_buflen;
 };
 
@@ -267,6 +266,11 @@ struct cdrom_blk
 
 #define CDROM_PACKET_SIZE      12
 
+#define CGC_DATA_UNKNOWN       0
+#define CGC_DATA_WRITE         1
+#define CGC_DATA_READ          2
+#define CGC_DATA_NONE          3
+
 /* for CDROM_PACKET_COMMAND ioctl */
 struct cdrom_generic_command
 {
@@ -275,6 +279,7 @@ struct cdrom_generic_command
        unsigned int            buflen;
        int                     stat;
        struct request_sense    *sense;
+       unsigned char           data_direction;
        void                    *reserved[3];
 };
 
@@ -790,7 +795,8 @@ extern int cdrom_mode_sense(struct cdrom_device_info *cdi,
                            struct cdrom_generic_command *cgc,
                            int page_code, int page_control);
 extern void init_cdrom_command(struct cdrom_generic_command *cgc,
-                              void *buffer, int len);
+                              void *buffer, int len, int type);
+extern struct cdrom_device_info *cdrom_find_device(kdev_t dev);
 
 typedef struct {
        __u16 disc_information_length;
@@ -798,9 +804,9 @@ typedef struct {
        __u8 reserved1                  : 3;
         __u8 erasable                  : 1;
         __u8 border_status             : 2;
-        __u8 disc_border               : 2;
+        __u8 disc_status               : 2;
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
-        __u8 disc_border               : 2;
+        __u8 disc_status               : 2;
         __u8 border_status             : 2;
         __u8 erasable                  : 1;
        __u8 reserved1                  : 3;
@@ -938,7 +944,6 @@ struct mode_page_header {
 };
 
 typedef struct {
-       struct mode_page_header header;
 #if defined(__BIG_ENDIAN_BITFIELD)
        __u8 ps                 : 1;
        __u8 reserved1          : 1;
@@ -991,7 +996,7 @@ typedef struct {
        __u8 subhdr1;
        __u8 subhdr2;
        __u8 subhdr3;
-} write_param_page __attribute__((packed));
+} __attribute__((packed)) write_param_page;
 
 #endif  /* End of kernel only stuff */ 
 
index 3672f2789f795aac91ca0ccf464c235f685bfddc..64136c7327d7bcacbc9575b8c5ee96226ae46b89 100644 (file)
@@ -358,7 +358,8 @@ typedef enum {      ide_unknown,    ide_generic,    ide_pci,
                ide_cmd640,     ide_dtc2278,    ide_ali14xx,
                ide_qd6580,     ide_umc8672,    ide_ht6560b,
                ide_pdc4030,    ide_rz1000,     ide_trm290,
-               ide_cmd646,     ide_cy82c693,   ide_4drives
+               ide_cmd646,     ide_cy82c693,   ide_4drives,
+               ide_pmac
 } hwif_chipset_t;
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
index 9c326c7997061b222047a8b886d2de6d4d65d02a..6c6fc31d65c303fe0d695836c29fc7283779bae3 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -925,9 +925,9 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
                        swap_free(entry);
                        if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
                                BUG();
-                       if (is_shmzero) shm_swp--;
+                       if (is_shmzero == 0) shm_swp--;
                }
-               if (is_shmzero) shm_rss++;
+               if (is_shmzero == 0) shm_rss++;
                pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
                SHM_ENTRY(shp, idx) = pte;
        } else
index 45f1b1168977bf54a607bd61eee5f30b704f44b4..833846406b200e109fc8148eb059df0ec8e98705 100644 (file)
@@ -53,7 +53,7 @@ tristate 'The IPX protocol' CONFIG_IPX
 if [ "$CONFIG_IPX" != "n" ]; then
    source net/ipx/Config.in
 fi
-tristate 'Appletalk DDP' CONFIG_ATALK
+tristate 'Appletalk protocol support' CONFIG_ATALK
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'DECnet Support (EXPERIMENTAL)' CONFIG_DECNET
    if [ "$CONFIG_DECNET" != "n" ]; then
index 16ff31dd0023d22bccf1528c663d7632ca0cf6cb..d99e539579cee691fb59281c1bebeb15e240ae7d 100644 (file)
@@ -586,6 +586,8 @@ EXPORT_SYMBOL(nf_register_queue_handler);
 EXPORT_SYMBOL(nf_unregister_queue_handler);
 EXPORT_SYMBOL(nf_hook_slow);
 EXPORT_SYMBOL(nf_hooks);
+EXPORT_SYMBOL(nf_setsockopt);
+EXPORT_SYMBOL(nf_getsockopt);
 #endif
 
 EXPORT_SYMBOL(register_gifconf);